Repository: GoldenGnu/jeveassets Branch: main Commit: 4515534818cb Files: 791 Total size: 22.2 MB Directory structure: gitextract_syw4v6nw/ ├── .github/ │ └── workflows/ │ ├── codeql-analysis.yml │ ├── esi.yml │ └── tests.yml ├── .gitignore ├── CONTRIBUTING.md ├── changelog.txt ├── checkstyle.xml ├── credits.txt ├── data/ │ ├── agents.xml │ ├── flags.xml │ ├── items.xml │ ├── jumps.xml │ ├── locations.xml │ └── npccorporation.xml ├── license.txt ├── pom.xml ├── readme.txt ├── src/ │ ├── main/ │ │ ├── assembly/ │ │ │ └── assembly.xml │ │ ├── java/ │ │ │ └── net/ │ │ │ └── nikr/ │ │ │ └── eve/ │ │ │ └── jeveasset/ │ │ │ ├── CliExport.java │ │ │ ├── CliOptions.java │ │ │ ├── CliUpdate.java │ │ │ ├── DetectEdtViolationRepaintManager.java │ │ │ ├── LibraryManager.java │ │ │ ├── Main.java │ │ │ ├── NahimicDetector.java │ │ │ ├── NikrUncaughtExceptionHandler.java │ │ │ ├── Program.java │ │ │ ├── SingleInstance.java │ │ │ ├── SplashUpdater.java │ │ │ ├── ToolLoader.java │ │ │ ├── data/ │ │ │ │ ├── api/ │ │ │ │ │ ├── accounts/ │ │ │ │ │ │ ├── AbstractOwner.java │ │ │ │ │ │ ├── ApiType.java │ │ │ │ │ │ ├── EsiOwner.java │ │ │ │ │ │ ├── OwnerType.java │ │ │ │ │ │ └── SimpleOwner.java │ │ │ │ │ ├── my/ │ │ │ │ │ │ ├── MyAccountBalance.java │ │ │ │ │ │ ├── MyAsset.java │ │ │ │ │ │ ├── MyBlueprint.java │ │ │ │ │ │ ├── MyContract.java │ │ │ │ │ │ ├── MyContractItem.java │ │ │ │ │ │ ├── MyExtraction.java │ │ │ │ │ │ ├── MyIndustryJob.java │ │ │ │ │ │ ├── MyJournal.java │ │ │ │ │ │ ├── MyLoyaltyPoints.java │ │ │ │ │ │ ├── MyMarketOrder.java │ │ │ │ │ │ ├── MyMining.java │ │ │ │ │ │ ├── MyNpcStanding.java │ │ │ │ │ │ ├── MyShip.java │ │ │ │ │ │ ├── MySkill.java │ │ │ │ │ │ └── MyTransaction.java │ │ │ │ │ └── raw/ │ │ │ │ │ ├── RawAccountBalance.java │ │ │ │ │ ├── RawAsset.java │ │ │ │ │ ├── RawBlueprint.java │ │ │ │ │ ├── RawClone.java │ │ │ │ │ ├── RawContract.java │ │ │ │ │ ├── RawContractItem.java │ │ │ │ │ ├── RawExtraction.java │ │ │ │ │ ├── RawIndustryJob.java │ │ │ │ │ ├── RawJournal.java │ │ │ │ │ ├── RawJournalRefType.java │ │ │ │ │ ├── RawLoyaltyPoints.java │ │ │ │ │ ├── RawMarketOrder.java │ │ │ │ │ ├── RawMining.java │ │ │ │ │ ├── RawNpcStanding.java │ │ │ │ │ ├── RawPublicMarketOrder.java │ │ │ │ │ ├── RawSkill.java │ │ │ │ │ └── RawTransaction.java │ │ │ │ ├── profile/ │ │ │ │ │ ├── Profile.java │ │ │ │ │ ├── ProfileData.java │ │ │ │ │ ├── ProfileManager.java │ │ │ │ │ ├── StockpileIDs.java │ │ │ │ │ └── TableData.java │ │ │ │ ├── sde/ │ │ │ │ │ ├── Agent.java │ │ │ │ │ ├── IndustryMaterial.java │ │ │ │ │ ├── Item.java │ │ │ │ │ ├── ItemFlag.java │ │ │ │ │ ├── Jump.java │ │ │ │ │ ├── MyLocation.java │ │ │ │ │ ├── NpcCorporation.java │ │ │ │ │ ├── ReprocessedMaterial.java │ │ │ │ │ ├── RouteFinder.java │ │ │ │ │ └── StaticData.java │ │ │ │ └── settings/ │ │ │ │ ├── AddedData.java │ │ │ │ ├── Citadel.java │ │ │ │ ├── CitadelSettings.java │ │ │ │ ├── ColorEntry.java │ │ │ │ ├── ColorSettings.java │ │ │ │ ├── ColorTheme.java │ │ │ │ ├── ColorThemeColorblind.java │ │ │ │ ├── ColorThemeDark.java │ │ │ │ ├── ColorThemeDefault.java │ │ │ │ ├── ColorThemeStrong.java │ │ │ │ ├── Colors.java │ │ │ │ ├── CopySettings.java │ │ │ │ ├── DarkNimbus.java │ │ │ │ ├── ExportSettings.java │ │ │ │ ├── ManufacturingSettings.java │ │ │ │ ├── MarketOrdersSettings.java │ │ │ │ ├── MarketPriceData.java │ │ │ │ ├── PriceData.java │ │ │ │ ├── PriceDataSettings.java │ │ │ │ ├── PriceHistoryDatabase.java │ │ │ │ ├── ProxyData.java │ │ │ │ ├── ReprocessSettings.java │ │ │ │ ├── RouteAvoidSettings.java │ │ │ │ ├── RouteResult.java │ │ │ │ ├── RoutingSettings.java │ │ │ │ ├── Settings.java │ │ │ │ ├── SettingsUpdateListener.java │ │ │ │ ├── StockpileGroupSettings.java │ │ │ │ ├── TempDirs.java │ │ │ │ ├── TrackerData.java │ │ │ │ ├── TrackerSettings.java │ │ │ │ ├── UserItem.java │ │ │ │ ├── tag/ │ │ │ │ │ ├── Tag.java │ │ │ │ │ ├── TagColor.java │ │ │ │ │ ├── TagID.java │ │ │ │ │ ├── TagUpdate.java │ │ │ │ │ └── Tags.java │ │ │ │ └── types/ │ │ │ │ ├── BlueprintType.java │ │ │ │ ├── CorporationType.java │ │ │ │ ├── EditableLocationType.java │ │ │ │ ├── EditablePriceType.java │ │ │ │ ├── EsiType.java │ │ │ │ ├── ItemType.java │ │ │ │ ├── LastTransactionType.java │ │ │ │ ├── LocationType.java │ │ │ │ ├── LocationsType.java │ │ │ │ ├── MarketDetailType.java │ │ │ │ ├── OwnersType.java │ │ │ │ ├── PriceType.java │ │ │ │ └── TagsType.java │ │ │ ├── gui/ │ │ │ │ ├── dialogs/ │ │ │ │ │ ├── AboutDialog.java │ │ │ │ │ ├── account/ │ │ │ │ │ │ ├── AccountImportDialog.java │ │ │ │ │ │ ├── AccountManagerDialog.java │ │ │ │ │ │ ├── AccountSeparatorTableCell.java │ │ │ │ │ │ ├── AccountTableFormat.java │ │ │ │ │ │ ├── JAccountTable.java │ │ │ │ │ │ └── SeparatorListComparator.java │ │ │ │ │ ├── profile/ │ │ │ │ │ │ ├── JValidatedInputDialog.java │ │ │ │ │ │ └── ProfileDialog.java │ │ │ │ │ ├── settings/ │ │ │ │ │ │ ├── AssetsToolSettingsPanel.java │ │ │ │ │ │ ├── ColorSeparatorTableCell.java │ │ │ │ │ │ ├── ColorSettingsPanel.java │ │ │ │ │ │ ├── ColorsTableFormat.java │ │ │ │ │ │ ├── ContractToolSettingsPanel.java │ │ │ │ │ │ ├── ExperimentalSettingsPanel.java │ │ │ │ │ │ ├── GeneralSettingsPanel.java │ │ │ │ │ │ ├── IndustryJobsToolSettingsPanel.java │ │ │ │ │ │ ├── JColorTable.java │ │ │ │ │ │ ├── JSettingsPanel.java │ │ │ │ │ │ ├── JUserListPanel.java │ │ │ │ │ │ ├── JournalToolSettingsPanel.java │ │ │ │ │ │ ├── JumpsSettingsPanel.java │ │ │ │ │ │ ├── LookAndFeelPreview.java │ │ │ │ │ │ ├── ManufacturingSettingsPanel.java │ │ │ │ │ │ ├── MarketOrdersToolSettingsPanel.java │ │ │ │ │ │ ├── MiningToolSettingsPanel.java │ │ │ │ │ │ ├── OverviewToolSettingsPanel.java │ │ │ │ │ │ ├── PriceDataSettingsPanel.java │ │ │ │ │ │ ├── PriceHistoryToolSettingsPanel.java │ │ │ │ │ │ ├── ProxySettingsPanel.java │ │ │ │ │ │ ├── ReprocessingSettingsPanel.java │ │ │ │ │ │ ├── SettingsDialog.java │ │ │ │ │ │ ├── ShowToolSettingsPanel.java │ │ │ │ │ │ ├── SoundsSettingsPanel.java │ │ │ │ │ │ ├── StockpileToolSettingsPanel.java │ │ │ │ │ │ ├── TagsSettingsPanel.java │ │ │ │ │ │ ├── TrackerToolSettingsPanel.java │ │ │ │ │ │ ├── TransactionsToolSettingsPanel.java │ │ │ │ │ │ ├── UserLocationSettingsPanel.java │ │ │ │ │ │ ├── UserNameSettingsPanel.java │ │ │ │ │ │ ├── UserPriceSettingsPanel.java │ │ │ │ │ │ └── WindowSettingsPanel.java │ │ │ │ │ └── update/ │ │ │ │ │ ├── StructureUpdateDialog.java │ │ │ │ │ ├── TaskDialog.java │ │ │ │ │ ├── UpdateDialog.java │ │ │ │ │ └── UpdateTask.java │ │ │ │ ├── frame/ │ │ │ │ │ ├── MainMenu.java │ │ │ │ │ ├── MainWindow.java │ │ │ │ │ └── StatusPanel.java │ │ │ │ ├── images/ │ │ │ │ │ └── Images.java │ │ │ │ ├── shared/ │ │ │ │ │ ├── ColorIcon.java │ │ │ │ │ ├── ColorUtil.java │ │ │ │ │ ├── CopyHandler.java │ │ │ │ │ ├── DocumentFactory.java │ │ │ │ │ ├── Formatter.java │ │ │ │ │ ├── InstantToolTip.java │ │ │ │ │ ├── JFreeChartUtil.java │ │ │ │ │ ├── JOptionInput.java │ │ │ │ │ ├── JSimpleColorPicker.java │ │ │ │ │ ├── MarketDetailsColumn.java │ │ │ │ │ ├── MenuScroller.java │ │ │ │ │ ├── NativeUtil.java │ │ │ │ │ ├── StringComparators.java │ │ │ │ │ ├── TextImport.java │ │ │ │ │ ├── TextManager.java │ │ │ │ │ ├── TreeSelectDialog.java │ │ │ │ │ ├── Updatable.java │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── CheckBoxNode.java │ │ │ │ │ │ ├── CheckBoxNodeEditor.java │ │ │ │ │ │ ├── CheckBoxNodeRenderer.java │ │ │ │ │ │ ├── CompoundUndoManager.java │ │ │ │ │ │ ├── JAutoCompleteDialog.java │ │ │ │ │ │ ├── JButtonComparable.java │ │ │ │ │ │ ├── JButtonNull.java │ │ │ │ │ │ ├── JCustomFileChooser.java │ │ │ │ │ │ ├── JDateChooser.java │ │ │ │ │ │ ├── JDefaultField.java │ │ │ │ │ │ ├── JDialogCentered.java │ │ │ │ │ │ ├── JDoubleField.java │ │ │ │ │ │ ├── JDragTabbedPane.java │ │ │ │ │ │ ├── JDropDownButton.java │ │ │ │ │ │ ├── JFixedToolBar.java │ │ │ │ │ │ ├── JGroupLayoutPanel.java │ │ │ │ │ │ ├── JImportDialog.java │ │ │ │ │ │ ├── JIntegerField.java │ │ │ │ │ │ ├── JLabelMultiline.java │ │ │ │ │ │ ├── JLabelMultilineHtml.java │ │ │ │ │ │ ├── JLockWindow.java │ │ │ │ │ │ ├── JMainTab.java │ │ │ │ │ │ ├── JMainTabPrimary.java │ │ │ │ │ │ ├── JMainTabSecondary.java │ │ │ │ │ │ ├── JManagerDialog.java │ │ │ │ │ │ ├── JMultiSelectionDialog.java │ │ │ │ │ │ ├── JMultiSelectionList.java │ │ │ │ │ │ ├── JOptionsDialog.java │ │ │ │ │ │ ├── JSelectionDialog.java │ │ │ │ │ │ ├── JTextAreaPlaceholder.java │ │ │ │ │ │ ├── JTextDialog.java │ │ │ │ │ │ ├── JTreemap.java │ │ │ │ │ │ ├── JWorking.java │ │ │ │ │ │ └── ListComboBoxModel.java │ │ │ │ │ ├── filter/ │ │ │ │ │ │ ├── ColumnCache.java │ │ │ │ │ │ ├── ExportDialog.java │ │ │ │ │ │ ├── ExportTableData.java │ │ │ │ │ │ ├── Filter.java │ │ │ │ │ │ ├── FilterControl.java │ │ │ │ │ │ ├── FilterExport.java │ │ │ │ │ │ ├── FilterGui.java │ │ │ │ │ │ ├── FilterLogicalMatcher.java │ │ │ │ │ │ ├── FilterMatcher.java │ │ │ │ │ │ ├── FilterMenu.java │ │ │ │ │ │ ├── FilterPanel.java │ │ │ │ │ │ ├── FilterPanelSeparator.java │ │ │ │ │ │ ├── FilterSave.java │ │ │ │ │ │ ├── JFilterManagerDialog.java │ │ │ │ │ │ ├── SimpleFilterControl.java │ │ │ │ │ │ └── SimpleTableFormat.java │ │ │ │ │ ├── menu/ │ │ │ │ │ │ ├── JFormulaDialog.java │ │ │ │ │ │ ├── JMenuAssetFilter.java │ │ │ │ │ │ ├── JMenuColumns.java │ │ │ │ │ │ ├── JMenuCopy.java │ │ │ │ │ │ ├── JMenuCopyPlus.java │ │ │ │ │ │ ├── JMenuFormula.java │ │ │ │ │ │ ├── JMenuInfo.java │ │ │ │ │ │ ├── JMenuJumps.java │ │ │ │ │ │ ├── JMenuLoadout.java │ │ │ │ │ │ ├── JMenuLocation.java │ │ │ │ │ │ ├── JMenuLookup.java │ │ │ │ │ │ ├── JMenuName.java │ │ │ │ │ │ ├── JMenuPrice.java │ │ │ │ │ │ ├── JMenuPriceHistory.java │ │ │ │ │ │ ├── JMenuReprocessed.java │ │ │ │ │ │ ├── JMenuRouting.java │ │ │ │ │ │ ├── JMenuStockpile.java │ │ │ │ │ │ ├── JMenuSum.java │ │ │ │ │ │ ├── JMenuTags.java │ │ │ │ │ │ ├── JMenuTransactionFilter.java │ │ │ │ │ │ ├── JMenuUI.java │ │ │ │ │ │ ├── JTagsDialog.java │ │ │ │ │ │ ├── MenuData.java │ │ │ │ │ │ └── MenuManager.java │ │ │ │ │ └── table/ │ │ │ │ │ ├── ColumnManager.java │ │ │ │ │ ├── EnumTableColumn.java │ │ │ │ │ ├── EnumTableFormatAdaptor.java │ │ │ │ │ ├── EventListManager.java │ │ │ │ │ ├── EventModels.java │ │ │ │ │ ├── JAutoColumnTable.java │ │ │ │ │ ├── JEditColumnsDialog.java │ │ │ │ │ ├── JSeparatorTable.java │ │ │ │ │ ├── JViewManagerDialog.java │ │ │ │ │ ├── PaddingTableCellRenderer.java │ │ │ │ │ ├── SeparatorTableCell.java │ │ │ │ │ ├── SimpleColumnManager.java │ │ │ │ │ ├── TableCellRenderers.java │ │ │ │ │ ├── TableFormatFactory.java │ │ │ │ │ ├── View.java │ │ │ │ │ └── containers/ │ │ │ │ │ ├── AssetContainer.java │ │ │ │ │ ├── DateOnly.java │ │ │ │ │ ├── Duration.java │ │ │ │ │ ├── ExpirerDate.java │ │ │ │ │ ├── HierarchyColumn.java │ │ │ │ │ ├── ISK.java │ │ │ │ │ ├── LongInt.java │ │ │ │ │ ├── ModulePriceValue.java │ │ │ │ │ ├── NumberValue.java │ │ │ │ │ ├── Percent.java │ │ │ │ │ ├── Runs.java │ │ │ │ │ ├── Security.java │ │ │ │ │ ├── Standing.java │ │ │ │ │ ├── TextIcon.java │ │ │ │ │ └── YesNo.java │ │ │ │ ├── sounds/ │ │ │ │ │ ├── DefaultSound.java │ │ │ │ │ ├── FileSound.java │ │ │ │ │ ├── Sound.java │ │ │ │ │ ├── SoundPlayer.java │ │ │ │ │ └── SoundThread.java │ │ │ │ └── tabs/ │ │ │ │ ├── agents/ │ │ │ │ │ ├── AgentsTab.java │ │ │ │ │ └── AgentsTableFormat.java │ │ │ │ ├── assets/ │ │ │ │ │ ├── AssetTableFormat.java │ │ │ │ │ ├── AssetsTab.java │ │ │ │ │ └── JAssetTable.java │ │ │ │ ├── contracts/ │ │ │ │ │ ├── ContractsSeparatorTableCell.java │ │ │ │ │ ├── ContractsTab.java │ │ │ │ │ ├── ContractsTableFormat.java │ │ │ │ │ └── JContractsTable.java │ │ │ │ ├── items/ │ │ │ │ │ ├── ItemTableFormat.java │ │ │ │ │ └── ItemsTab.java │ │ │ │ ├── jobs/ │ │ │ │ │ ├── IndustryJobTableFormat.java │ │ │ │ │ ├── IndustryJobsTab.java │ │ │ │ │ └── JIndustryJobsTable.java │ │ │ │ ├── journal/ │ │ │ │ │ ├── JJournalTable.java │ │ │ │ │ ├── JournalChartDialog.java │ │ │ │ │ ├── JournalTab.java │ │ │ │ │ └── JournalTableFormat.java │ │ │ │ ├── loadout/ │ │ │ │ │ ├── Loadout.java │ │ │ │ │ ├── LoadoutData.java │ │ │ │ │ ├── LoadoutExtendedTableFormat.java │ │ │ │ │ ├── LoadoutSeparatorComparator.java │ │ │ │ │ ├── LoadoutSeparatorTableCell.java │ │ │ │ │ ├── LoadoutTableFormat.java │ │ │ │ │ ├── LoadoutsExportDialog.java │ │ │ │ │ └── LoadoutsTab.java │ │ │ │ ├── loyalty/ │ │ │ │ │ ├── LoyaltyPointsTab.java │ │ │ │ │ ├── LoyaltyPointsTableFormat.java │ │ │ │ │ └── TotalLoyaltyPoints.java │ │ │ │ ├── materials/ │ │ │ │ │ ├── Material.java │ │ │ │ │ ├── MaterialExtendedTableFormat.java │ │ │ │ │ ├── MaterialSeparatorComparator.java │ │ │ │ │ ├── MaterialTableFormat.java │ │ │ │ │ ├── MaterialsData.java │ │ │ │ │ ├── MaterialsSeparatorTableCell.java │ │ │ │ │ └── MaterialsTab.java │ │ │ │ ├── mining/ │ │ │ │ │ ├── ExtractionsTab.java │ │ │ │ │ ├── ExtractionsTableFormat.java │ │ │ │ │ ├── JExtractionsTable.java │ │ │ │ │ ├── MiningGraphTab.java │ │ │ │ │ ├── MiningTab.java │ │ │ │ │ └── MiningTableFormat.java │ │ │ │ ├── orders/ │ │ │ │ │ ├── JMarketOrdersTable.java │ │ │ │ │ ├── MarketLog.java │ │ │ │ │ ├── MarketOrdersTab.java │ │ │ │ │ ├── MarketTableFormat.java │ │ │ │ │ ├── Outbid.java │ │ │ │ │ └── OutbidProcesser.java │ │ │ │ ├── overview/ │ │ │ │ │ ├── JOverviewMenu.java │ │ │ │ │ ├── JOverviewTable.java │ │ │ │ │ ├── Overview.java │ │ │ │ │ ├── OverviewData.java │ │ │ │ │ ├── OverviewGroup.java │ │ │ │ │ ├── OverviewLocation.java │ │ │ │ │ ├── OverviewTab.java │ │ │ │ │ └── OverviewTableFormat.java │ │ │ │ ├── prices/ │ │ │ │ │ ├── JItemsManagerDialog.java │ │ │ │ │ ├── PriceChangesTab.java │ │ │ │ │ ├── PriceChangesTableFormat.java │ │ │ │ │ └── PriceHistoryTab.java │ │ │ │ ├── reprocessed/ │ │ │ │ │ ├── JReprocessedTable.java │ │ │ │ │ ├── ReprocessedData.java │ │ │ │ │ ├── ReprocessedExtendedTableFormat.java │ │ │ │ │ ├── ReprocessedGrandItem.java │ │ │ │ │ ├── ReprocessedGrandTotal.java │ │ │ │ │ ├── ReprocessedInterface.java │ │ │ │ │ ├── ReprocessedItem.java │ │ │ │ │ ├── ReprocessedSeparatorComparator.java │ │ │ │ │ ├── ReprocessedSeparatorTableCell.java │ │ │ │ │ ├── ReprocessedTab.java │ │ │ │ │ ├── ReprocessedTableFormat.java │ │ │ │ │ └── ReprocessedTotal.java │ │ │ │ ├── routing/ │ │ │ │ │ ├── EditableListModel.java │ │ │ │ │ ├── JAvoid.java │ │ │ │ │ ├── JAvoidManagerDialog.java │ │ │ │ │ ├── JRouteEditDialog.java │ │ │ │ │ ├── JRouteManagerDialog.java │ │ │ │ │ ├── MoveJList.java │ │ │ │ │ ├── RoutingTab.java │ │ │ │ │ └── SolarSystem.java │ │ │ │ ├── skills/ │ │ │ │ │ ├── JSkillPlansManageDialog.java │ │ │ │ │ ├── SkillsOverviewTab.java │ │ │ │ │ ├── SkillsOverviewTableFormat.java │ │ │ │ │ ├── SkillsTab.java │ │ │ │ │ └── SkillsTableFormat.java │ │ │ │ ├── slots/ │ │ │ │ │ ├── JSlotsTable.java │ │ │ │ │ ├── Slots.java │ │ │ │ │ ├── SlotsData.java │ │ │ │ │ ├── SlotsTab.java │ │ │ │ │ └── SlotsTableFormat.java │ │ │ │ ├── standing/ │ │ │ │ │ ├── NpcStandingTab.java │ │ │ │ │ └── NpcStandingTableFormat.java │ │ │ │ ├── stockpile/ │ │ │ │ │ ├── JStockpileItemMenu.java │ │ │ │ │ ├── JStockpileTable.java │ │ │ │ │ ├── Stockpile.java │ │ │ │ │ ├── StockpileBpDialog.java │ │ │ │ │ ├── StockpileData.java │ │ │ │ │ ├── StockpileDialog.java │ │ │ │ │ ├── StockpileExtendedTableFormat.java │ │ │ │ │ ├── StockpileItemDialog.java │ │ │ │ │ ├── StockpileSeparatorTableCell.java │ │ │ │ │ ├── StockpileShoppingListDialog.java │ │ │ │ │ ├── StockpileTab.java │ │ │ │ │ └── StockpileTableFormat.java │ │ │ │ ├── tracker/ │ │ │ │ │ ├── JTrackerEditDialog.java │ │ │ │ │ ├── QuickDate.java │ │ │ │ │ ├── TrackerAssetFilterDialog.java │ │ │ │ │ ├── TrackerDate.java │ │ │ │ │ ├── TrackerNote.java │ │ │ │ │ ├── TrackerSkillPointFilter.java │ │ │ │ │ ├── TrackerSkillPointsFilterDialog.java │ │ │ │ │ ├── TrackerSkillPointsFilterTableFormat.java │ │ │ │ │ ├── TrackerTab.java │ │ │ │ │ └── TrackerWalletFilterDialog.java │ │ │ │ ├── transaction/ │ │ │ │ │ ├── JTransactionTable.java │ │ │ │ │ ├── TransactionTab.java │ │ │ │ │ └── TransactionTableFormat.java │ │ │ │ ├── tree/ │ │ │ │ │ ├── JTreeTable.java │ │ │ │ │ ├── TreeAsset.java │ │ │ │ │ ├── TreeData.java │ │ │ │ │ ├── TreeTab.java │ │ │ │ │ └── TreeTableFormat.java │ │ │ │ └── values/ │ │ │ │ ├── AssetValue.java │ │ │ │ ├── DataSetCreator.java │ │ │ │ ├── IskData.java │ │ │ │ ├── JValueTable.java │ │ │ │ ├── Value.java │ │ │ │ ├── ValueRetroTab.java │ │ │ │ ├── ValueTableFormat.java │ │ │ │ └── ValueTableTab.java │ │ │ ├── i18n/ │ │ │ │ ├── BundleServiceFactory.java │ │ │ │ ├── DataColors.java │ │ │ │ ├── DataModelAsset.java │ │ │ │ ├── DataModelIndustryJob.java │ │ │ │ ├── DataModelPriceDataSettings.java │ │ │ │ ├── DialoguesAbout.java │ │ │ │ ├── DialoguesAccount.java │ │ │ │ ├── DialoguesExport.java │ │ │ │ ├── DialoguesProfiles.java │ │ │ │ ├── DialoguesSettings.java │ │ │ │ ├── DialoguesStructure.java │ │ │ │ ├── DialoguesUpdate.java │ │ │ │ ├── General.java │ │ │ │ ├── GuiFrame.java │ │ │ │ ├── GuiShared.java │ │ │ │ ├── TabsAgents.java │ │ │ │ ├── TabsAssets.java │ │ │ │ ├── TabsContracts.java │ │ │ │ ├── TabsItems.java │ │ │ │ ├── TabsJobs.java │ │ │ │ ├── TabsJournal.java │ │ │ │ ├── TabsLoadout.java │ │ │ │ ├── TabsLoyaltyPoints.java │ │ │ │ ├── TabsMaterials.java │ │ │ │ ├── TabsMining.java │ │ │ │ ├── TabsNpcStanding.java │ │ │ │ ├── TabsOrders.java │ │ │ │ ├── TabsOverview.java │ │ │ │ ├── TabsPriceChanges.java │ │ │ │ ├── TabsPriceHistory.java │ │ │ │ ├── TabsReprocessed.java │ │ │ │ ├── TabsRouting.java │ │ │ │ ├── TabsSkills.java │ │ │ │ ├── TabsSlots.java │ │ │ │ ├── TabsStockpile.java │ │ │ │ ├── TabsTracker.java │ │ │ │ ├── TabsTransaction.java │ │ │ │ ├── TabsTree.java │ │ │ │ └── TabsValues.java │ │ │ └── io/ │ │ │ ├── esi/ │ │ │ │ ├── AbstractEsiGetter.java │ │ │ │ ├── AuthCodeListener.java │ │ │ │ ├── EsiAccountBalanceGetter.java │ │ │ │ ├── EsiAssetsGetter.java │ │ │ │ ├── EsiAuth.java │ │ │ │ ├── EsiBlueprintsGetter.java │ │ │ │ ├── EsiCallbackURL.java │ │ │ │ ├── EsiClonesGetter.java │ │ │ │ ├── EsiContractItemsGetter.java │ │ │ │ ├── EsiContractsGetter.java │ │ │ │ ├── EsiConverter.java │ │ │ │ ├── EsiDivisionsGetter.java │ │ │ │ ├── EsiFactionWarfareGetter.java │ │ │ │ ├── EsiIndustryJobsGetter.java │ │ │ │ ├── EsiItemsGetter.java │ │ │ │ ├── EsiJournalGetter.java │ │ │ │ ├── EsiLocationsGetter.java │ │ │ │ ├── EsiLoyaltyPointsGetter.java │ │ │ │ ├── EsiManufacturingPrices.java │ │ │ │ ├── EsiMarketOrdersGetter.java │ │ │ │ ├── EsiMiningGetter.java │ │ │ │ ├── EsiNameGetter.java │ │ │ │ ├── EsiNpcStandingGetter.java │ │ │ │ ├── EsiOwnerGetter.java │ │ │ │ ├── EsiPlanetaryInteractionGetter.java │ │ │ │ ├── EsiPublicMarketOrdersGetter.java │ │ │ │ ├── EsiScopes.java │ │ │ │ ├── EsiShipGetter.java │ │ │ │ ├── EsiSkillGetter.java │ │ │ │ ├── EsiStructuresGetter.java │ │ │ │ ├── EsiTransactionsGetter.java │ │ │ │ └── MicroServe.java │ │ │ ├── local/ │ │ │ │ ├── AbstractBackup.java │ │ │ │ ├── AbstractXmlReader.java │ │ │ │ ├── AbstractXmlWriter.java │ │ │ │ ├── AgentsReader.java │ │ │ │ ├── AssetAddedReader.java │ │ │ │ ├── AttributeGetters.java │ │ │ │ ├── CitadelReader.java │ │ │ │ ├── CitadelWriter.java │ │ │ │ ├── CsvWriter.java │ │ │ │ ├── EveFittingReader.java │ │ │ │ ├── EveFittingWriter.java │ │ │ │ ├── FileLock.java │ │ │ │ ├── FlagsReader.java │ │ │ │ ├── HtmlWriter.java │ │ │ │ ├── ItemsReader.java │ │ │ │ ├── ItemsWriter.java │ │ │ │ ├── JumpsReader.java │ │ │ │ ├── LocationsReader.java │ │ │ │ ├── MarketLogReader.java │ │ │ │ ├── NpcCorporationsReader.java │ │ │ │ ├── ProfileFinder.java │ │ │ │ ├── ProfileReader.java │ │ │ │ ├── SettingsReader.java │ │ │ │ ├── SettingsWriter.java │ │ │ │ ├── SoundFinder.java │ │ │ │ ├── SqlWriter.java │ │ │ │ ├── StockpileReader.java │ │ │ │ ├── StockpileWriter.java │ │ │ │ ├── TrackerReader.java │ │ │ │ ├── TrackerWriter.java │ │ │ │ ├── XmlException.java │ │ │ │ ├── profile/ │ │ │ │ │ ├── ProfileAccountBalances.java │ │ │ │ │ ├── ProfileActiveShip.java │ │ │ │ │ ├── ProfileAssetDivisions.java │ │ │ │ │ ├── ProfileAssets.java │ │ │ │ │ ├── ProfileBlueprints.java │ │ │ │ │ ├── ProfileClones.java │ │ │ │ │ ├── ProfileConnection.java │ │ │ │ │ ├── ProfileConnectionData.java │ │ │ │ │ ├── ProfileContracts.java │ │ │ │ │ ├── ProfileDatabase.java │ │ │ │ │ ├── ProfileIndustryJobs.java │ │ │ │ │ ├── ProfileJournals.java │ │ │ │ │ ├── ProfileLoyaltyPoints.java │ │ │ │ │ ├── ProfileMarketOrders.java │ │ │ │ │ ├── ProfileMining.java │ │ │ │ │ ├── ProfileNpcStanding.java │ │ │ │ │ ├── ProfileOwners.java │ │ │ │ │ ├── ProfileSkills.java │ │ │ │ │ ├── ProfileTable.java │ │ │ │ │ ├── ProfileTransactions.java │ │ │ │ │ └── ProfileWalletDivisions.java │ │ │ │ ├── text/ │ │ │ │ │ ├── AbstractTextImport.java │ │ │ │ │ ├── ImportEft.java │ │ │ │ │ ├── ImportEveMultibuy.java │ │ │ │ │ ├── ImportIskPerHour.java │ │ │ │ │ ├── ImportShoppingList.java │ │ │ │ │ └── TextImportType.java │ │ │ │ └── update/ │ │ │ │ ├── LocalUpdate.java │ │ │ │ ├── Update.java │ │ │ │ └── updates/ │ │ │ │ └── Update1To2.java │ │ │ ├── online/ │ │ │ │ ├── CitadelGetter.java │ │ │ │ ├── DataGetter.java │ │ │ │ ├── EveImageGetter.java │ │ │ │ ├── EveRefGetter.java │ │ │ │ ├── PriceDataGetter.java │ │ │ │ ├── UpdateTaskInputStream.java │ │ │ │ ├── Updater.java │ │ │ │ └── ZkillboardPricesHistoryGetter.java │ │ │ └── shared/ │ │ │ ├── AbstractGetter.java │ │ │ ├── AccountAdder.java │ │ │ ├── AccountAdderAdapter.java │ │ │ ├── ApiIdConverter.java │ │ │ ├── DataConverter.java │ │ │ ├── DesktopUtil.java │ │ │ ├── FileUtil.java │ │ │ ├── FileUtilSimple.java │ │ │ ├── RawConverter.java │ │ │ ├── SafeConverter.java │ │ │ └── ThreadWoker.java │ │ └── resources/ │ │ ├── logback.xml │ │ └── net/ │ │ └── nikr/ │ │ └── eve/ │ │ └── jeveasset/ │ │ └── i18n/ │ │ ├── DataColors.properties │ │ ├── DataModelAsset.properties │ │ ├── DataModelIndustryJob.properties │ │ ├── DataModelPriceDataSettings.properties │ │ ├── DialoguesAbout.properties │ │ ├── DialoguesAccount.properties │ │ ├── DialoguesExport.properties │ │ ├── DialoguesProfiles.properties │ │ ├── DialoguesSettings.properties │ │ ├── DialoguesStructure.properties │ │ ├── DialoguesUpdate.properties │ │ ├── General.properties │ │ ├── GuiFrame.properties │ │ ├── GuiShared.properties │ │ ├── TabsAgents.properties │ │ ├── TabsAssets.properties │ │ ├── TabsContracts.properties │ │ ├── TabsItems.properties │ │ ├── TabsJobs.properties │ │ ├── TabsJournal.properties │ │ ├── TabsLoadout.properties │ │ ├── TabsLoyaltyPoints.properties │ │ ├── TabsMaterials.properties │ │ ├── TabsMining.properties │ │ ├── TabsNpcStanding.properties │ │ ├── TabsOrders.properties │ │ ├── TabsOverview.properties │ │ ├── TabsPriceChanges.properties │ │ ├── TabsPriceHistory.properties │ │ ├── TabsReprocessed.properties │ │ ├── TabsRouting.properties │ │ ├── TabsSkills.properties │ │ ├── TabsSlots.properties │ │ ├── TabsStockpile.properties │ │ ├── TabsTracker.properties │ │ ├── TabsTransaction.properties │ │ ├── TabsTree.properties │ │ └── TabsValues.properties │ ├── site/ │ │ └── site.xml │ └── test/ │ ├── java/ │ │ └── net/ │ │ └── nikr/ │ │ └── eve/ │ │ └── jeveasset/ │ │ ├── ProgramTest.java │ │ ├── TestUtil.java │ │ ├── data/ │ │ │ ├── profile/ │ │ │ │ └── StockpileIDsTest.java │ │ │ ├── raw/ │ │ │ │ ├── LocationFlagTest.java │ │ │ │ ├── RawAssetTest.java │ │ │ │ ├── RawBlueprintTest.java │ │ │ │ ├── RawCloneTest.java │ │ │ │ ├── RawContractItemTest.java │ │ │ │ ├── RawContractTest.java │ │ │ │ ├── RawIndustryJobTest.java │ │ │ │ ├── RawJournalTest.java │ │ │ │ ├── RawLoyaltyPointsTest.java │ │ │ │ ├── RawMarketOrderTest.java │ │ │ │ ├── RawNpcStandingTest.java │ │ │ │ ├── RawPublicMarketOrderTest.java │ │ │ │ ├── RawSkillTest.java │ │ │ │ ├── RawTransactionTest.java │ │ │ │ └── RawUtil.java │ │ │ ├── sde/ │ │ │ │ ├── ItemTest.java │ │ │ │ └── StaticDataTest.java │ │ │ └── settings/ │ │ │ ├── ColorThemeTest.java │ │ │ ├── MarketPriceDataTest.java │ │ │ ├── ModuleTest.java │ │ │ ├── ReprocessSettingsTest.java │ │ │ ├── SettingsTest.java │ │ │ └── TrackerDataTest.java │ │ ├── gui/ │ │ │ ├── images/ │ │ │ │ └── ImagesTest.java │ │ │ ├── shared/ │ │ │ │ ├── FormatterTest.java │ │ │ │ ├── components/ │ │ │ │ │ └── CheckBoxNodeTest.java │ │ │ │ ├── filter/ │ │ │ │ │ ├── FilterExportTest.java │ │ │ │ │ └── FilterMatcherTest.java │ │ │ │ └── menu/ │ │ │ │ ├── ExpressionExceptionTest.java │ │ │ │ ├── JMenuInfoTest.java │ │ │ │ └── JMenuLookupOnlineTest.java │ │ │ ├── sounds/ │ │ │ │ └── SoundsTest.java │ │ │ └── tabs/ │ │ │ ├── TableFormatTest.java │ │ │ ├── assets/ │ │ │ │ └── AssetAndTreeTableFormatTest.java │ │ │ ├── orders/ │ │ │ │ └── MarketOrdersTabTest.java │ │ │ ├── routing/ │ │ │ │ ├── TestEditableModel.java │ │ │ │ ├── TestMoveJList.java │ │ │ │ ├── TestRouting.java │ │ │ │ └── mocks/ │ │ │ │ ├── FakeRoutingTab.java │ │ │ │ └── RoutingMockProgram.java │ │ │ ├── stockpile/ │ │ │ │ └── StockpileTest.java │ │ │ └── values/ │ │ │ └── DataSetCreatorTest.java │ │ ├── i18n/ │ │ │ └── TestI18N.java │ │ ├── io/ │ │ │ ├── esi/ │ │ │ │ ├── EsiConverterTest.java │ │ │ │ ├── EsiDeprecationOnlineTest.java │ │ │ │ ├── EsiNameGetterOnlineTest.java │ │ │ │ └── EsiScopesTest.java │ │ │ ├── local/ │ │ │ │ ├── AssetAddedReaderTest.java │ │ │ │ ├── BackupTest.java │ │ │ │ ├── BackwardCompatibilitySettings.java │ │ │ │ ├── FileLockSettings.java │ │ │ │ ├── FileLockTest.java │ │ │ │ ├── ItemFlagsTest.java │ │ │ │ ├── ProfileReadWriteTest.java │ │ │ │ ├── SettingsTest.java │ │ │ │ ├── StockpileDataReadWriteTest.java │ │ │ │ ├── TrackerDataTest.java │ │ │ │ └── text/ │ │ │ │ ├── ImportEftTest.java │ │ │ │ ├── ImportEveMultibuyTest.java │ │ │ │ ├── ImportIskPerHourTest.java │ │ │ │ └── ImportShoppingListTest.java │ │ │ ├── online/ │ │ │ │ ├── EveRefGetterOnlineTest.java │ │ │ │ ├── EveRefGetterTest.java │ │ │ │ ├── PriceDataGetterOnlineTest.java │ │ │ │ ├── ProxyTest.java │ │ │ │ └── ZkillboardPricesHistoryGetterOnlineTest.java │ │ │ └── shared/ │ │ │ ├── ApiIdConverterOnlineTest.java │ │ │ ├── ApiIdConverterTest.java │ │ │ ├── AssetsGetterTest.java │ │ │ ├── ConverterTestOptions.java │ │ │ ├── ConverterTestOptionsGetter.java │ │ │ ├── ConverterTestUtil.java │ │ │ ├── DataConverterTest.java │ │ │ ├── ProfileDatabaseConverterTest.java │ │ │ └── RawConverterTest.java │ │ ├── lib/ │ │ │ └── LibTest.java │ │ └── tests/ │ │ └── mocks/ │ │ ├── FakeProgram.java │ │ ├── FakeProgress.java │ │ ├── FakeSettings.java │ │ └── OverwriteTest.java │ └── resources/ │ ├── 740/ │ │ ├── stockpile_test_0.xml │ │ ├── stockpile_test_1.xml │ │ ├── stockpile_test_10.xml │ │ ├── stockpile_test_11.xml │ │ ├── stockpile_test_2.xml │ │ ├── stockpile_test_3.xml │ │ ├── stockpile_test_4.xml │ │ ├── stockpile_test_5.xml │ │ ├── stockpile_test_6.xml │ │ ├── stockpile_test_7.xml │ │ ├── stockpile_test_8.xml │ │ └── stockpile_test_9.xml │ ├── 750/ │ │ ├── stockpile_test_0.xml │ │ ├── stockpile_test_1.xml │ │ ├── stockpile_test_10.xml │ │ ├── stockpile_test_11.xml │ │ ├── stockpile_test_2.xml │ │ ├── stockpile_test_3.xml │ │ ├── stockpile_test_4.xml │ │ ├── stockpile_test_5.xml │ │ ├── stockpile_test_6.xml │ │ ├── stockpile_test_7.xml │ │ ├── stockpile_test_8.xml │ │ └── stockpile_test_9.xml │ ├── added.json │ ├── data-1-0-0/ │ │ └── settings.xml │ ├── data-1-1-0/ │ │ └── settings.xml │ ├── data-1-2-0/ │ │ └── settings.xml │ ├── data-1-2-1/ │ │ └── settings.xml │ ├── data-1-2-2/ │ │ └── settings.xml │ ├── data-1-2-3/ │ │ └── settings.xml │ ├── data-1-3-0/ │ │ └── settings.xml │ ├── data-1-4-0/ │ │ └── settings.xml │ ├── data-1-4-1/ │ │ └── settings.xml │ ├── data-1-5-0/ │ │ └── settings.xml │ ├── data-1-6-0/ │ │ └── settings.xml │ ├── data-1-6-1/ │ │ └── settings.xml │ ├── data-1-6-2/ │ │ └── settings.xml │ ├── data-1-6-3/ │ │ └── settings.xml │ ├── data-1-6-4/ │ │ └── settings.xml │ ├── data-1-7-0/ │ │ └── settings.xml │ ├── data-1-7-1/ │ │ └── settings.xml │ ├── data-1-7-2/ │ │ └── settings.xml │ ├── data-1-7-3/ │ │ └── settings.xml │ ├── data-1-8-0/ │ │ └── settings.xml │ ├── data-1-8-1/ │ │ └── settings.xml │ ├── data-1-9-0/ │ │ └── settings.xml │ ├── data-1-9-1/ │ │ └── settings.xml │ ├── data-1-9-2/ │ │ └── settings.xml │ ├── data-2-0-0/ │ │ └── settings.xml │ ├── data-2-1-0/ │ │ └── settings.xml │ ├── data-2-1-1/ │ │ └── settings.xml │ ├── data-2-1-2/ │ │ └── settings.xml │ ├── data-2-2-0/ │ │ └── settings.xml │ ├── data-2-3-0/ │ │ └── settings.xml │ ├── data-2-4-0/ │ │ └── settings.xml │ ├── data-2-5-0/ │ │ └── settings.xml │ ├── data-2-6-0/ │ │ └── settings.xml │ ├── data-2-7-0/ │ │ └── settings.xml │ ├── data-fail/ │ │ └── settings.xml │ ├── everefblueprint.json │ ├── evereftype.json │ ├── tracker_empty.json │ ├── tracker_filters.json │ └── tracker_total.json └── tools/ ├── bugs/ │ ├── conn.php │ ├── index.php │ ├── jeveasset.sql │ └── submit.php ├── citadel/ │ └── index.php ├── izpack/ │ ├── ProcessPanel.Spec.xml │ ├── install.xml │ └── izpack-util.jar ├── jarfile.properties ├── jmemory.jar ├── packagemanager.properties └── update/ ├── .htaccess ├── github.update └── list.php ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/codeql-analysis.yml ================================================ name: "CodeQL" on: push: pull_request: schedule: - cron: '39 17 * * 1' jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'java' ] steps: - name: Checkout repository uses: actions/checkout@v4 - name: Cache uses: actions/cache@v4 with: path: ~/.m2/repository key: ${{ matrix.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ matrix.os }}-maven- # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} - name: Autobuild uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 ================================================ FILE: .github/workflows/esi.yml ================================================ name: Esi on: push: schedule: # Daily @ 8:44 - cron: '44 8 * * *' jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Cache uses: actions/cache@v4 with: path: ~/.m2/repository key: build-${{ hashFiles('**/pom.xml') }} restore-keys: | build- - name: JDK uses: actions/setup-java@v2 with: distribution: 'temurin' java-version: 8 - name: Build with Maven env: SSO_CLIENT_ID: ${{ secrets.SSO_CLIENT_ID }} SSO_REFRESH_TOKEN: ${{ secrets.SSO_REFRESH_TOKEN }} run: mvn -Dtest=EsiDeprecationOnlineTest test - name: Send discord notification for new release if: failure() env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} uses: Ilshidur/action-discord@cf9b729d74ae8cd2de75a32a02594d4d4a1d4a77 with: args: ':exclamation: eve-esi library needs to be updated' ================================================ FILE: .github/workflows/tests.yml ================================================ name: Tests on: [push, pull_request] jobs: build: runs-on: ${{ matrix.os }} strategy: matrix: os: [macOS-latest, ubuntu-latest, windows-latest] java: [ 8, 11, 17 ] name: ${{ matrix.os }} (Java ${{ matrix.java }}) steps: - name: Checkout uses: actions/checkout@v4 - name: Cache uses: actions/cache@v4 with: path: ~/.m2/repository key: ${{ matrix.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ matrix.os }}-maven- - name: JDK uses: actions/setup-java@v2 with: distribution: 'temurin' java-version: ${{ matrix.java }} - name: Build with Maven env: SSO_CLIENT_ID: ${{ secrets.SSO_CLIENT_ID }} SSO_REFRESH_TOKEN: ${{ secrets.SSO_REFRESH_TOKEN }} run: mvn -B package --file pom.xml -P skip-online-tests ================================================ FILE: .gitignore ================================================ .idea .vscode target nbactions.xml jeveassets.log nbproject nb-configuration.xml nbactions*.xml jeveassets1.log ================================================ FILE: CONTRIBUTING.md ================================================ # Git Checkout # We usually work in two branches: * New Features: https://github.com/GoldenGnu/jeveassets/tree/develop * Bug Fixes: https://github.com/GoldenGnu/jeveassets/tree/main It's **strongly** advised to make a new branch for each PR in your own fork # Git Clone # https://github.com/GoldenGnu/jeveassets.git # Compile # We compile with the latest version of Oracle Java SE 8 (Yes, still using Java 8). ## Netbeans ## Open the project and compile (F11) ## Other IDEs ## I only use NetBeans. Feel free to make a PR with instructions # Coding Guidelines # * We use tab and not space. Be sure to disable "expand tabs to space" in your IDE. * Swing JComponent variable names should have leading "j". Ex.: `jMyTable` * No other variable names should use [Systems Hungarian](https://en.wikipedia.org/wiki/Hungarian_notation) # Contribute # We are looking for (in random order): * Documentation * Java Programmers * Dedicated Testers * Translators If you want to join the project contract `goldengnu` on the [jEveAssets Discord server](https://discord.gg/8kYZvbM) (PMs welcome). ================================================ FILE: changelog.txt ================================================ ######## ##### ######## ####### ### ### ### # ######## # # #### ######### #### #### #### ##### #### ######## # # # ######### # # # # # # ### # # #### ### ### #### #### #### # #### # ######## #### # ### ### # # # # # # ######## ## #### ### ### #### #### #### # #### # ### #### # # #### # # #### #### # #### #### # # # # # ## # # # # # # # # #### #### #### # ## #### # # # # ## # # # # # # ## # # # # # # # # #### # # # # # # #### #### #### #### #### ________________________________________________________________________________ _8.1.2__________________________________________________________________________ Bug Fixes: -Stockpile locations was empty (issue #572) ________________________________________________________________________________ _8.1.1__________________________________________________________________________ Bug Fixes: -Bad update logic for the industry jobs time left column -Duplicate implants in the assets tool ________________________________________________________________________________ _8.1.0__________________________________________________________________________ New Features: -Added tree map to the assets and overview tools (by Ansirane Solette) -Add journal presets and chart (by Ansirane Solette) -Added new loyalty points tool (issue #48) -Added new npc standing tool (characters and corporations) -Added new skill plans tool with import functionality (by WildGear) -Added new agents tool -Added shopping list button to the group bar in the table -Allow adding multiple filters from the same column at once -Save current sorting -Added jump clones to assets (issue #39) -Added clones group in the location tree -Added avoid filters to the jump columns -Added eve market browser to the lookup menu -Added jita space to the lookup menu -Added eveconomy to the lookup menu -Added Quantum Anomaly loyalty points store to the lookup menu -Added time left column to the industry jobs tool -Added option to open eve gatecamp check when setting in-game route -Lazy initialization of tools (optional, on by default) Changed: -Use " to escape SQL identifiers (instead of `) -Save html and sql text files as UTF-8 -Removed lazy blacksmith from the lookup menu Bug Fixes: -Refresh token can be null (after character transfers) (issue #570) -Workaround for esi contract items rate limit -AssetsToolSettingsPanel always trigger full update -Repaint filter panel on color scheme changes -Mining export never worked -Unable to load column filter in the reprocessed and price changes tools -Fixed duplicates in skills -Routing start system didn't work with stations -EditableListModel had bad logic -Adding subpiles didn't update the stockpile items -Stockpile zero of zero shows red (issue #553) -Slots statusbar manufacturing max had the wrong tooltip -SQL export should use NULL for null values (issue #558) Code: -Updated eve-esi library to version 7.0.0 (2025-09-30) -Updated pricing library to version 3.1.2 (updated janice locations) ________________________________________________________________________________ _8.0.3__________________________________________________________________________ New Features: -Added eve market browser to the lookup menu -Added jita space to the lookup menu Bug Fixes: -Price update would sometimes fail due to a rounding error -Add support for global plex market region to fuzzwork price source -Added global plex market region support to outbid -Duplicates in account balances (BugID: 1323) ________________________________________________________________________________ _8.0.2__________________________________________________________________________ Bug Fixes: -Static files should not be file locked (Issue #528) -Handle when os locks are not supported (Issue #528) -Ignore duplicates in the skills table (BugId: 1315) -Outbid could have the wrong color for types in multiple regions ________________________________________________________________________________ _8.0.1__________________________________________________________________________ New Features: -Added OS file locks (may help prevent errors when syncing data to the cloud) Bug Fixes: -Fixed CtD because of duplicated assets and mining logs -Fixed CtD due to empty tables (users will need to restore a backup) -Archived industry jobs now count as done (again) Code: -Add 30 seconds delay to esi cache expiry to avoid stale responses -Ensure crash on OutOfMemoryError when updating -Moved clones and clone implants to their own table ________________________________________________________________________________ _8.0.0__________________________________________________________________________ New Features: -Import routes from system names/ids in routing tool (Issue #475) -Moved stockpile and reprocessing import format selecting to the import dialog -Save profile data in SQLite -Include plugged implants in assets and tracker (Issue #124) -Automatic naming for loadout EFT export (Issue #471) -Added dotlan lookup link to system on region map -Added contract count to the statusbar (Issue #513) Bug Fixes: -Dotlan constellation lookup didn't replace space -Blueprint runs rounding did not match fuzzwork and IPH -Fixed how flags are handled in the tracker edit dialog -Tracker assets containers not in the correct corp hangar division (Issue #519) Code: -Added email to user agent (thanks to the ccp esi team for making this matter!) ________________________________________________________________________________ _7.9.4__________________________________________________________________________ Bug Fixes: -CtD in the stockpile tool (NPE) -CtD when sorting columns (NPE/ISE) ________________________________________________________________________________ _7.9.3__________________________________________________________________________ Bug Fixes: -Loadout eft export doesn't handle charges (Issue #498) [Tsuro Tsero] -Made string columns sorting case insensitive (Issue #506) -Importing tracker data replaced existing data -Made stockpile match all differentiate between bpc and runs -Stockpile shopping list counted own items double if also in subpile Code: -Optimized JCustomFileChooser (reduced startup time) -Update eve-esi to 5.0.0 (removed esi bookmarks) -Updated logback to 1.3.15 -Updated slf4j to 2.0.16 ________________________________________________________________________________ _7.9.2__________________________________________________________________________ Bug Fixes: -Stockpiles collapsing after adding item (Issue #497) Code: -Optimization of FilterMatcher (Optional, on by default) ________________________________________________________________________________ _7.9.1__________________________________________________________________________ Bug Fixes: -Added contract locations to my stockpile locations -Stockpile my locations contained delivered industry jobs locations -Corporation contract assets owner is now an option: char/corp/both (Issue #476) -Changed http to https in multiple places (contributed by Salartarium) -Reprocessed grand total should never have a color -Reprocessed value and color box was wrong -Mining graph/tracker owners list is not sorted (Issue #491) -Tracker assets location filter others node didn't work (Issue #485) -Tracker add new locations selected is never saved (Issue#488) -Remember what screen to open on (Issue #462) -noformula and nojumps cli arguments not working (Issue #492) -Fixed everef lookup to point to the correct url -Stockpile groups behave incorrectly with filters (Issue #484) -Ensure stockpile cell is visible after being expanded -Industry jobs assets use the wrong location -Ensure reprocess settings are valid -Flagstring attribute was never saved/loaded for assets and blueprints -Expired contracts are not included in tracker/assets (Issue #473) -Stockpile industry copy jobs now output both BPCs and Runs (Issue #482) -Fixed a typo (Issue #479) -Delivered industry jobs was included in assets and stockpiles (Issue #480) -Stockpile target column truncation (Issue #467) -Price history use tick scale of selected items (Issue #466) -Contract/Industry jobs assets was not updated on status change by users Changed: -Reduced throughput for public market orders to 100 -Removed contract status expired and added archived Code: -Minor optimization of the stockpile tool -Updated sqlite to 3.41.2.2 -Updated logback to 1.2.13 -Updated prices library to 3.1.1 (Issue #469) -Updated eve-esi library to 4.9.0 ________________________________________________________________________________ _7.9.0__________________________________________________________________________ New Features: -Keep original name when cloning stockpiles (contributed by Ed Thelleres) -Show/Hide container ItemID in the Assets and Tree tools -Lock tool tabs -Stockpile can now hide the subpile tree -Play sound when outbid data can be updated again -Stockpiles shopping list CSV/Spreadsheet format -Added TypeID column to the materials tool -Added Tags column to the journal tool -Added Tags column to the transactions tool -Stockpile matching/contains all for assets -Added commodity category to the materials tool -Added corporation wallet division 1-7 columns to the isk tool -Added price changes tool -Added date values to formula columns -Save industry jobs history (optional, on by default) -Get missing item data from EveRef (data not in ESI) -Added packaged volume column to the assets and tree tools -Added link to jEveAssets discord server Bug Fixes: -Industry Jobs blueprints show as output material -Stockpile group editing would sometimes lead to visual artifacts -Stockpile target column sometimes truncate editable numbers -Overflow in Formula/Jumps/Tags menus -Lookup menu Eve Tycoon used the wrong link -Fixed reactions calculations (contributed by Ed Thelleres) -Subpile count in the stockpile shopping list was always zero -Tags was bold on first render -CtD when importing stockpile text into new/rename stockpile -CtD in the stockpile tool (BugID 1074 & 1076) Changed: -Removed EveMarketer from the lookup menu -Replaced lazy-blacksmith.space with lzb.eveskillboard.com in lookup menu -Sort stockpile shopping list by name -Improved account import usability Code: -Update multiple missing items at the same time ________________________________________________________________________________ _7.8.1__________________________________________________________________________ Bug Fixes: -Removed outbid auto-update due to impact on esi -Added advanced contracting to the slots tool (Reported by MagnarM) ________________________________________________________________________________ _7.8.0__________________________________________________________________________ New Features: -Rename Stockpile Groups (Issue #379) -Group multiple stockpiles (Issue #377) -Delete multiple stockpiles (Issue #377) -Added income/expenditure/total to the journal statusbar (Issue #17) -Import systems to the routing tool (Issue #208) -Sorting contract columns now sort the contract groups too (Issue #374) -Added ore/ice/gas to the materials tool (Issue #391) -Made each group optional in the materials tool (Issue #391) -Added reprocessed/manufacturing columns to the contracts tool (Issue #412) -Import eve fitting xml to stockpiles (Issue #382) -Added output volume column to the industry jobs tool (Issue #418) -Different color for orders outbid by your own orders (Issue #416) -Added option to ignore multiplier for stockpile items (Issue #411) -Added owned column to industry jobs/market orders/contracts Bug Fixes: -Update table cell on stockpile delete -Reprocessed count/account name/stockpile multiplier require enter (Issue #410) -Stockpile menu wasn't updating on stockpile rename -Added expired status to contracts (Issue #415) -PB materials added to stockpiles are rounded up (Issue #413) Changed: -Removed evemarketer.com API as a market price source Code: -Added fail-safe for endless outbid update loop on error ________________________________________________________________________________ _7.7.0__________________________________________________________________________ New Features: -Added corporation mining ledger (Issue #371) -Added wallet division column to the market orders tool (Issue #375) -Added completed by column to the industry jobs tool (Issue #389) -Allow users to add their own mp3 files for sound alerts (Issue #378) -Manufacturing price column to assets/tree/items/market orders (Issue #138) -Made the stockpile dialog for adding manufacturing materials more detailed -Retry invalid accounts from the account manager -Added options for more visible chart colors (Issue #387 & #404) -Added tooltips for filter buttons Bug Fixes: -Stockpile total for transaction and contract columns showed wrong value -Ensure adding to the reprocessed tool is always great than zero -Industry jobs default filters didn't include cancelled/reverted (Issue #399) -Stockpile menu could overflow (Issue #381) -Shopping list and subpiles didn't work with "matching all" (Issue #403) Changed: -Made it more obvious that reprocessed count is editable -Made it more obvious that stockpile multiplier and target cells are editable -Removed evepraisal from the lookup menu Code: -Moved reprocessed price to the item class (Issue #373) -Changed audio format from wave to mp3 (Issue #378) ________________________________________________________________________________ _7.6.2__________________________________________________________________________ Bug Fixes: -Corporation accounts did not work -Price History remained empty after adding items -Tracker Show icon was not correct on startup -Mining Graph showed wrong values with multiple mining characters Code: -Updated eve-esi to 4.8.1 ________________________________________________________________________________ _7.6.1__________________________________________________________________________ Bug Fixes: -Mining Graph entries was not sorted by date ________________________________________________________________________________ _7.6.0__________________________________________________________________________ New Features: -Added character mining ledger (graph and log) (Issue #20) -Added a new tool with character skills (Issue #345) -Added stockpile groups (issue #321) -Stockpile import now have BPO/PBC/Runs/Materials options (issue #357) -Use item count when add to stockpiles (contributed by Boran Lordsworth) -Added volume packaged column to the items tool -Allowed subpile total rows to be column sorted (issue #352) -Added slot type column to the assets/tree/stockpile/items tools (Issue #89) -Added charge size column to the assets/tree/stockpile/items tools (Issue #89) -Play sound when industry jobs are completed. Off by default (Issue #293) -Play sound when outbid data is updated. Off by default (Issue #287) -Added next x hours/days date filters (Issue #246) -Chart date labels are now scaled according to the shown range (Issue #356) Bug Fixes: -Fixed buttons shapes in separator tables with the FlatLAF -Editing accounts did not update the scopes Changed: -Market orders and transaction volume columns now use packaged volume ________________________________________________________________________________ _7.5.0__________________________________________________________________________ New Features: -Streamlined stockpile import and added import into stockpile (Issue #228) -Including sub items are now optional for stockpile flag filters (Issue #358) -Added SellMin/BuyMax columns to the stockpile tool (Issue #365) -Added Volume/SellMin/BuyMax columns to the market orders tool (Issue #365 #364) -Added journal menu for finding related transactions/contracts/industry jobs -Added context column to the journal -Added Transaction ID column to the Transactions tool -Added Order ID column to the Market Orders tool -Added Job ID column to the Industry Jobs tool Bug Fixes: -Fixed a bug in include sub container filter (always included subs) -Ignore leading/trailing white space on stockpile text import -Stockpile contracts match all wasn't working (Issue #266) -Fix for "Contract not public" and "Contract not found" errors (Issue #360) -Fixed concurrency problem in ApiIdConverter.getItemUpdate() Changed: -Hide zeroes that are stand-in for no data on subpiles rows in stockpile tool Code: -Switch to using the affiliation and names endpoints -Removed the contract price API (Thanks to Rihan for hosting it for so long) ________________________________________________________________________________ _7.4.0__________________________________________________________________________ New Features: -Added evemissioneer.com to the lookup menu (Issue #351) -Added option only including contracts with all the stockpile items (Issue #266) -Blueprint copying output as assets (Optional, off by default) -Set status for Contracts and Market Orders no longer in ESI (Issue #349) -Added Stockpile filter for industry job duration (Issue #348) -Added volume column to the Transaction tool (Issue #350) -Added Completed Date and Paused Date columns to the Industry Jobs tool -Added import to the reprocessing tool (Issue #335) -Display total minerals (minerals*count) in the reprocessed tool (Issue #302) -Added avg/count/max/min of selected numeric cells/column to the table menu -Added market orders and contracts to the slots tool (Issue #347) -Added Availability column to the contracts tool (Public or Private) Changed: -Improved the ToolTip for the Transaction Margin columns -Only include industry jobs if not delivered to assets yet Bug Fixes: -Handle space and comma thousands separators when editing in tables (Issue #344) -Added sum table menu tooltip (was null) -Fixed table header not resizing on sorting (if the table didn't change) -Fixed StatusPanel icon labels having the copy tooltip + handle dynamic icons -Fixed Stockpile text import/export -Do not try to update public market orders with invalid accounts -Exclude invalid accounts from structure updates ________________________________________________________________________________ _7.3.2__________________________________________________________________________ Bug Fixes: -Fixed NPE crash in FilterManager (BugID: 1028, 1029) ________________________________________________________________________________ _7.3.1__________________________________________________________________________ Bug Fixes: -Fixed NPE in MyIndustryJob from MyBlueprint (Issue #342) ________________________________________________________________________________ _7.3.0__________________________________________________________________________ New Features: -Added filters to the Overview Tool (Issue #336) -Added Janice as a price source (Issue #328) -Price History (Issue #76) -Added category column to stockpile table (contributed by Lazaren) -Added various values to the industry slots tool statusbar (Issue #337) -Added various values to the industry slots tool table popup menu (Issue #337) -Added various values to the contracts tool statusbar (Issue #333) -Added various values to the contracts tool table popup menu (Issue #132) -You can now copy statusbar values by clicking on them -Added tool tips explain you can click to copy to the info menu and statusbar -Added Context Type and Context ID columns to the Journal tool -Added ContractID and RecordID columns to the Contracts Tool -Added Market Value and Market Price columns to the Contracts Tool -Added ItemID/Runs/ME/TE columns to the Contracts Tool (only public contracts) -The tracker tool now have prices for blueprints in public contracts -Added placeholder examples for filter import (Issue #282) -Improved market details character selection in the Stockpile tool (Issue #307) -Added mnemonic to the main menu -Added available label to stockpile separator row (Issue #341) Bug Fixes: -Ignore profiles with invalid names -Include private structures in the contract appraisal settings reset on save -Refining equipment option did not accept decimal values (Issue #340) Changed: -Made the business tool menu a bit nicer -Added warning message when hitting the maximum of 25000 blueprints -Better warning for orders in unknown locations on outbid update (Issue #327) -Show warning when Nahimic Overlay is detected (Issue #313) Code: -Update eve-esi to 4.7.0 -Optimized table main menu to only be updated before showing -Updates from setting changes now only update what is needed (Issue #334) -Added info level to UpdateTask (Used by "NOT ALLOWED YET") -Replaced OSXadapter with FlatDesktop from flatlaf (Issue #329) ________________________________________________________________________________ _7.2.1__________________________________________________________________________ Bug Fixes: -Stockpile did not work with BPCs and runs ________________________________________________________________________________ _7.2.0__________________________________________________________________________ New Features: -Added configurable colors to the industry jobs activity column -Adding account automatically update existing account authorization (Issue #306) -Separated ore and scrapmetal reprocessing calculations/settings (Issue #312) -Added buttons to open the online manual (Stockpile/Table Filters/Settings) -Added Eve Tycoon to the lookup menu Bug Fixes: -CLI -droptable -createtable -extended are always true (Issue #310) -CLI tableName is always a empty string, DROP TABLE IF EXISTS `` (Issue #310) -If sqlTableName is set in the GUI, It's not used for CLI export (Issue #310) -Fixed issues with CLI updates for multiple profiles -Fixed delay between starting update and the update window showing (Issue #319) -Fixed public market orders update progress finishing at 80% progress -Fixed Industry Jobs having the wrong default filters (was Transactions filters) -Fixed CLI export logging -Fixed the current filter never being displayed as empty -Overview export using current view (should use all) -Fixed an old bug where Settings dialog would resize after being shown -Fixed painting outside the EDT in JMainTab/MarketOrdersTab/RoutingTab Changed: -Improved the reprocessing settings GUI -Slightly better CLI help message -The Stockpile dialog now better convey that selecting an include is required -Show warning before updating outbid data with orders in unknown locations -Made most toolbars more compressible and normalized icon buttons width -Changed help menu to point to the wiki and wiki's feedback and help Code: -Optimized stockpile New/Clone/Delete/Import/Hide/Show -Optimized subpile updates in the stockpile tool -Upgraded maven plugins to make it work with Java 17 (contributed by Burberius) -Updated all the wiki links to the new site: https://wiki.jeveassets.org -Refactored ProfileManager/Profile/ProfileWriter/ProfileReader to be more OOP -Added test to ensure dev build is always off (false) -Ensure profile names are never duplicated -Better error logging for ESI errors ________________________________________________________________________________ _7.1.1__________________________________________________________________________ Bug Fixes: -Unable to export default filters -Can not reset columns -Fixed number formatting for CSV and HTML export -Exporting from the GUI did not use the filter and column options -Fixed export and filtering for formula and jump columns -Added option to exclude formula and jump columns from the CLI -Force valid separator/column options when exporting from the GUI ________________________________________________________________________________ _7.1.0__________________________________________________________________________ New Features: -Added CLI for exporting table data (Issue #270) -Tool tabs can now be rearranged by dragging the tabs (issue #298) -Tool tabs can now be reopen with [ctrl|command] + [shift] + t (issue #298) -Make a Add button in the Reprocessed tool (Issue #297 - contributed by Inoruuk) -Added Output Name column to the industry jobs tool (Issue #294) -Hide stockpile from stockpile menu (Issue #300) Changed: -Change character/corporation selection in the AccountImportDialog to a ComboBox -Allow manually enabling the eve.nikr.net account import workaround Code: -Updated slf4j library to 1.7.36 -Updated logback library to 1.2.10 -Updated jfreechart library to 1.5.3 -Updated LGoodDatePicker library to 11.2.1 -Updated sqlite-jdbc library to 3.36.0.3 -Updated EvalEx library to 2.7 Bug Fixes: -Updatable didn't check for skill updates -ItemsWriter saved base price as double, ItemsReader expected long -Made SingleInstance handle headless mode -Possible fix for ClassCastException in StockpileItemDialog (BugId: 995) -Possible fix for publicMarketOrders cache time being incorrect ________________________________________________________________________________ _7.0.0__________________________________________________________________________ New Features: -Added support for more multibuy formats (contributed by madetara) -Added 'Added date' columns to Transactions/Journal tool (Issue #269) -Highlight recent changes in the Market Orders tool (Issue #265) -Highlight new items in Assets/Journal/Transactions tool (Issue #269) -Save contract history (optional, on be default) (Issue #258) -Table menu: Select ship in the Fitting Tool from Assets/Tree Tools (Issue #264) -Allow renaming assets in the Tree tool -Added Required and Owned options for the Stockpiles shopping list (Issue #235) -Added placeholder examples for Stockpile imports (Issue #276) -Added Type Name column to Assets/Tree tools (Hidden by default, issue #181) -Added Item Name column to Assets/Tree tools (Hidden by default, issue #181) -Made Market Details column's button clickable with the space key (Issue #137) -Added Market Details column to the Stockpile tool (Issue #256) -Added Average Transaction Price column to the Stockpile tool (Issue #256) -Add Job Cost column to Industry Jobs (Issue #284, contributed by Kaylee Syntax) Changed: -Use AutoCompleteSupport Filter Mode Contains (Issue #274) -Show critical error messages always on top Code: -Updated FlatLaf library to 1.6.4 -Updated eve-esi library to 4.6.1 -Fixed lgtm.com alerts (issue #275) Bug Fixes: -Fixed a case where the changed theme colors was not applied -Fixed changing color settings triggering an eventList update when not needed -Fixed wrong class types in TableFormats (BugId: 969, 971, 972, 979 and more) -Fixed tree table sorting columns really slowly -Fixed settings being saved while columns was being moved -Fixed NPE in XPDefaultRenderer (JDK-6429812, BugId: 959, Issue #279) -Fixed system look and feel being listed twice in the color settings -CDE/Motif did not have windows Copy/Paste/Cut/Select All shortcuts -Fixed Market Detail column's button rendering on various look and feels -Fixed NPE in FlatTitlePane (BugId: 980, Issue #281) -Journal is missing entries (Issue #218, Fixed in ESI by CCP! <3) -Possible fix for CtD on when setting a new price (Issue #277) -Fixed CtD before warning for "in zip file" and "library missing" was shown -Fixed jEveAssets losing focus when loading/creating profiles -Fixed meta and tech level for esi updated items -Added missing read lock for FilterList when updating statusbar ________________________________________________________________________________ _6.9.6__________________________________________________________________________ Bug Fixes: -Possible fix for CtD (BugID: 973, 974, 975, 976, 977, 978) Changed: -Ships are now included in their own totals in the Tree Tool (Issue #271) ________________________________________________________________________________ _6.9.5__________________________________________________________________________ Bug Fixes: -Removed incorrect column tooltip for formula columns -Formula columns did not work with infinity decimals (1.333) AGAIN! (Issue #268) -Exporting table data used disabled filters resulting in incomplete output Code: -Updated eve-esi library to version 4.6.0 (fixing account update) ________________________________________________________________________________ _6.9.4__________________________________________________________________________ Bug Fixes: -Fixed tree tool totals (parent items, statusbar, table menu) -Fixed Formula columns not working with results like 1.333... -Fixed price update failing (now fail when 25% of all price are zero, was 10%) -Table menu sum did not work correct for values between 0.0 and 1.0 (Ex: 0.14) Code: -Better handling of error throwables during update -Optimized Tree tool collapse and expand all -Hopefully fixed very slow sorting with many active filters in the Tree tool ________________________________________________________________________________ _6.9.3__________________________________________________________________________ Bug Fixes: -Formula column precision was set to 7 (now use unlimited) -Tree tool was missing icons for Planetary Industry -Stockpile total row did not work correctly with formula columns (Issue #261) -Fixed ArithmeticException in EnumTableFormatAdaptor (BugId: 951, 952) Code: -Updated eve-esi to version 4.5.0 ________________________________________________________________________________ _6.9.2__________________________________________________________________________ Bug Fixes: -NullPointerException in ExportDialog (BugId: 948, 949) -Fixed Formula columns export -Export column selection list not enabled when selected after restart ________________________________________________________________________________ _6.9.1__________________________________________________________________________ Changed: -Removed zKillboard/HammerTime structure update (Both are dead) Code: -Simplified SettingsUpdateListener calls Bug Fixes: -NPE in ColumnManager (BugId: 941, 947) -Filter logic is not updated when switching between numeric/string/date columns -Fixed IllegalArgumentException in JFormulaDialog (BugId: 944) -Loading filter with formula/jump column crashes jEveAssets (BugId: 943, 942) -Restoring current filter failed for filters with formula/jump columns -Fixed StringIndexOutOfBoundsException in JFormulaDialog (BugID: 946) ________________________________________________________________________________ _6.9.0__________________________________________________________________________ New Features: -As complete a restore at relaunch as possible (Issue #216) [Dultas] -Formula Columns (Issue #45) -Added evecookbook.com to the lookup menu -Added locationID column to the Assets tool (Issue #257) Changed: -Made Midpoint price fallback on a single price if one of the prices is zero Code: -Updated eve-esi library to version 4.4.0 Bug Fixes: -NPE from IndustryJob.getProductTypeID() (BugID: 901, 921) -Fix non extended sql inserts not working [Dultas] -SQL export doubles now use 2 decimals (Issue #252) [Dultas] -Active ships 2nd+ level children didn't have the right locationID -Partial fix for TaskDialog never being garbage collected ________________________________________________________________________________ _6.8.0__________________________________________________________________________ New Features: -Added current location and ship columns to Industry Slot and Isk (by Dutlas) -Added system and constellation columns to all tools with a location column -Added constellation view to Overview -Added constellations to zKillboard and Dotlan location lookup -Added constellations to Stockpile locations Bug Fixes: -Fix spelling error in Tracker delete-item warning (by jhmartin) -NPE in AssetAddedData.getAdd() (BugID: 893) -Outbid did not handle equal prices -Market order outbid was never being cleared of old entries (Issue #239) -Fixed Transactions Profit % column giving the wrong value -Better handle when price APIs return zero prices -Industry Slots won't load filters (Issue #242) -New columns at the end of the TableFormat was added at the wrong index -Ensured Copy, Paste, Cut, and Select All shortcuts works on a Mac (Issue #243) -Fixed corporation transactions wallet division incorrectly showing division 1 ________________________________________________________________________________ _6.7.1__________________________________________________________________________ Bug Fixes: -Crash when copying from tables (BugID: 883, 884, 888, 889) -Possible fix for AIOOBE crash in StockpileDialog (BugID: 887) -Deleting a stockpile did not work correctly for subpiles -Subpiles was missing items (Thanks to Lak Moore) ________________________________________________________________________________ _6.7.0__________________________________________________________________________ New Features: -Add Blueprint materials (with ME) as Stockpile items (Issue #182) -Changeable color for completed/delivered Industry Jobs (Issue #190) -Added Dark Nimbus look and feel -Added toggle all for Tracker skill points filter dialog -Include hidden stockpiles in Export (Issue #211) -Added Outbid delta column to the Market Order tool (Issue #204) -Added Group column to the Market Orders tool (Issue #220) -Added Market Price/Margin/Profit columns to the Market Orders tool (Issue #222) -Highlight Market Orders prior to expiring (Issue #219) -Highlight Market Orders with remaining quantity below x percent (Issue #225) Changed: -Better tool tip for the Market detail column -Added tool tip label for the market orders JComboBoxes -Stockpile "my locations" no longer include closed market order locations -Routing start system is now select via an auto completed JComboBox (Issue #209) -Export DATETIME instead of DATE in SQL Export (Issue #215) -Added thousand separator to HTML export numbers Code: -Updated eve-esi to 4.2.0 -Made Lookup menu links testable Bug Fixes: -Fixed the width for Tracker skill points filter dialog -NumberValue sub classes not respecting the copy decimal separator (Issue #195) -Better look and feel preview (Now use previewed LAF height) -Include "jEveAssets" in error and update message dialogs -All column filters could not be saved/loaded -Overview Tool did not display any data when opened on startup (work from menu) -Workaround JTextField with backgrounds on Nimbus look and feel -Prevent updating outbid when there is no active orders -MarketLog import did not use the latest outbid data -Fixed Overview table menu not work with groups -Update Khon.Space to Lazy-Blacksmith (Issue #217) ________________________________________________________________________________ _6.6.3__________________________________________________________________________ New Features: -Added option to change decimal separator used when copying (Issue #195) -Greatly improved the GUI on the Nimbus and GTK+ (Linux) look and feels -Improved the GUI on all look and feels Changed: -Better error message for invalid authorization (JWT is null) (Issue #193) -Better warning message for "waiting for cache to expire" -Stockpile include now start blank (forcing discovery of the options) Code: -Updated eve-esi to 4.1.0 -Updated all 3rd party libraries to the latest version Bug Fixes: -Skill point filter was always adding 5m (now it just enforce 5m minimum) -NPE in FilterMatcher (BugId: 850) -Components size was not adjusted to LAF -Missing constructor for ContractPriceItem on Java 14 (BugId: 854) -Fixed default market orders table sort order -Incorrectly mark some assets and stockpile items as blueprints -Save/load invalid account state -Only run Faction Warfare once on update -Fixed khon.space invention lookup not working for blueprints -Removed eve-marketdata.com and evemarkethelper.net from the lookup menu -Checks periodical if the marketlogs directory exist (if missing on startup) ________________________________________________________________________________ _6.6.2__________________________________________________________________________ New Features: -Added stockpile multiplier and subpile target in the shopping list (Issue #189) Changed: -Subpiles are now include when hidden (Issue #188) Bug Fixes: -Industry Slots did not include corporation jobs ________________________________________________________________________________ _6.6.1__________________________________________________________________________ New Features: -Skill point filters are now shared between the Isk and Tracker (Issue #187) Bug Fixes: -Stockpile did not handle editing correctly (Issue #186) ________________________________________________________________________________ _6.6.0__________________________________________________________________________ New Features: -Use ZKillboard's Structure API -Transaction Margin (Issue #153) -New Tool: Industry Slots (Issue #179) -Added skill points value to Tracker and Isk Tools (Issue #116) -Import/Export Routes (Issue #167) -Cascading Stockpiles AKA Subpiles (Issue #141) -Toggle reprocessing colors on toolbar Assets/Tree (Issue #151) -Add Transaction Filter Table Menu (Issue #165) Code: -Updated pricing library to 2.1.2 Bug Fixes: -Bad layout in SettingsDialog when opened the first time on some look and feels -Ask before overwriting a route when saving and order saved routes alphabetical -Stockpile EFT import ignore loaded charges (Issue #154) ________________________________________________________________________________ _6.5.1__________________________________________________________________________ Bug Fixes: -Unable to delete/edit stockpile entries (Issue #176) [Thanks to Nickand87] ________________________________________________________________________________ _6.5.0__________________________________________________________________________ New Features: -BPC colors can now be changed (Issue #150) -Added assets colors to the tree table -Better GUI on the color settings panel (tested on Ubuntu and Windows) -Improved math for Transaction Profit/Price columns (Issue #152) -Added option to select what price to use for profit calculations -Added ToolTips to a lot of columns -Changeable Look and Feel + Dark Theme (Issue #66) -Faction warfare system ownership column to Assets/Tree -Added Reprocessed price column to Market Orders tool -Stockpile match installer for industry jobs (Issue #164) Changed: -Stockpiles are now sorted case-insensitive Code: -Updated dom4j library to 2.1.3 (security vulnerability) -Updated eve-esi to 4.0.0 (major change: all enums can now be null) Bug Fixes: -Possible fix for outbid count being wrong (Issue #158) -Possible fix for account error JWT is null (Issue #171) -Contracts Appraisal API failing when including private structures (Issue #172) -Outbid range for sell orders always used region (Issue #170) -Made StatusPanel.progressStatus thread safe (BugID: 830) -Fixed Market Orders export having a bad value for Market Details column -Possible fix for Stockpile CtD (BugId: 833) -Ensure outbid doesn't have outdated data (Possible fix for #158 and #170) ________________________________________________________________________________ _6.4.1__________________________________________________________________________ Bug Fixes: -Isk/Values best fitted ship including stacks of ships -Use universe/names less (since it's being unstable) -Fixed unexpected end of JSON input: Use JWT (Issue #163) -Ensure public market orders are unique (Issue #158) ________________________________________________________________________________ _6.4.0__________________________________________________________________________ New Features: -Customizable colors -Colorblind friendly color theme -Tracker: Edit the order of generated routes -Tracker: Added Logarithmic scaling (linear still default) -Tracker: Remember selected owners between restarts and updates -Added ToolTips to Outbid $/Outbid #/Market Details columns -Added SUM of selection/column to the table menu -Duplicate filter entries -Warning levels for updates -Added update warning for missing corporation roles -Improved setting dialog GUI on ubuntu -Serve html response on SSO callback url instead of redirecting to eve.nikr.net Code: -Updated to routing 2.0.0 and graph 2.0.0 (both now support generics) Bug Fixes: -TaskDialog move a tiny bit when showing/hiding errors -Stockpile import had never ending loop of asking what stockpile to import -Made Stockpile text import more resilient to crashing (BugID: 800) -Made MarketLog import more resilient to crashing (BugID: 823) -Made Xml reader more resilient to crashing (BugID: 822, 821, 820, 819) ________________________________________________________________________________ _6.3.2__________________________________________________________________________ Bug Fixes: -Normalized apostrophe, quotes, and hyphen symbols for filters -Assets names update doesn't include all valid items (Issue #130) -Fixed crash to desktop when copying to the clipboard (BugID: 818) ________________________________________________________________________________ _6.3.1__________________________________________________________________________ Bug Fixes: -Fixed edited accounts using the old access token -Fixed market details column not handling corporation orders ________________________________________________________________________________ _6.3.0__________________________________________________________________________ New Features: -Market Orders: Use Public Market Orders to find outbid orders -Market Orders: Added Market Details column (Button opens market details in-game and copy fixed price to clipboard) -Market Orders: Automatically read Marketlogs exports (Find outbid orders and copy fixed price to clipboard) -Market Orders: Added Edits column -Select tool to show at startup or restore tools from last session -Support LowSec and NullSec regions as price sources locations Code: -Updated to eve-esi-3.7.0 Bug Fixes: -Fixed tracker popup menu getting more and more useless separators -Better error messages for citadel updates ________________________________________________________________________________ _6.2.4__________________________________________________________________________ Bug Fixes: -Fixed splash screen falsely claiming to be a dev build ________________________________________________________________________________ _6.2.3__________________________________________________________________________ Bug Fixes: -Assets update fails with ships in the frigate escape bay (Thanks to Ashterothi) ________________________________________________________________________________ _6.2.2__________________________________________________________________________ Bug Fixes: -Fixed crash to desktop when exporting SQL (Thanks to Neugeniko) ________________________________________________________________________________ _6.2.1__________________________________________________________________________ Bug Fixes: -Fixed crash to desktop in Contracts/Stockpile (thanks to Dak Torin) ________________________________________________________________________________ _6.2.0__________________________________________________________________________ New Features: -Tree now preserve expanded state on update -Added Market Orders column: Issued (first known issued date) -Added Market Orders column: TypeID -Added Market Orders column: Broker's Fee -Added Transaction column: Profit/percent/price -Added Transaction column: Tax -Added Export/Import Stockpiles as Text -Added broker's fee and tax to the table menu selection info -You can now copy selection info from the table menu by clicking the menu item -Added support for column header tooltips -Added tooltip to jumps column headers Changed: -Transactions Value column now include tax -Copyright updated to 2020 -Market Orders column: Issued renamed Updated (last known issued date) Code: -Fixed memory leak in MyLocation/Citadel Bug Fixes: -Possible fix for duplicated value in the tree tool -Better BPO detection for Industry Jobs -Runs column does not match with the value "BPO". Only match "-1" ________________________________________________________________________________ _6.1.3__________________________________________________________________________ Changed: -Removed EveKit (Accounts can be migrated to ESI) Bug Fixes: -Fixed update error on Java 11+ (SSLHandshakeException because of forced SSLv3) ________________________________________________________________________________ _6.1.2__________________________________________________________________________ Code: -Use characters/affiliation instead of characters/{character_id} (faster) -Use universe/names instead of corporations/{corporation_id} (faster) ________________________________________________________________________________ _6.1.1__________________________________________________________________________ Bug Fixes: -Structure updates was failing on 404 -Better handling of fatal errors during updates -Possible fix for market orders never closed Changed: -Added wiki links ________________________________________________________________________________ _6.1.0__________________________________________________________________________ New Features: -Update missing item data from ESI (not all item data is available via ESI, yet) -Tracker: Use asset prices for sell orders (Optional, off by default) -Tree tool: Added more groups -Tree tool: Container types show totals of sup items -Stockpiles: Show/Hide Stockpiles per Profile -Keep the splash screen open after dismissing an update dialog -Better error message for OutOfMemoryErrors Bug Fixes: -Fixed duplicates in the Tree Tool -Better handling of multiple profiles in the tracker Code: -Better support for package managers -Updated evekit library to 6.0.0 -Updated eve-esi library to 3.3.0 -Updated contracts-pricing library to 2.0.0 ________________________________________________________________________________ _6.0.4__________________________________________________________________________ Bug Fixes: -Could not add new accounts (not working with IPv6, now force IPv4) ________________________________________________________________________________ _6.0.3__________________________________________________________________________ Bug Fixes: -Did not respect the expires header on empty items in the Contract Appraisal API ________________________________________________________________________________ _6.0.2__________________________________________________________________________ Bug Fixes: -Fixed CtD (NPE) in Tree and Stockpile Tools (BugID: 755, 756, 757, 758, 759) -Fixed missing contract prices in the Tree tool -Stockpile did not respect BPC contract price settings Changed: -Industry Jobs output column now show total runs when copying ________________________________________________________________________________ _6.0.1__________________________________________________________________________ New Features: -Send feedback to the Contract Appraisal API -Prices for BPCs and BP runs in the stockpile -Added "New" update option for Contract Appraisal Bug Fixes: -Can not set BPC price -Incorrect update time for Contract Appraisal (sometimes missing a day) ________________________________________________________________________________ _6.0.0__________________________________________________________________________ New Features: -Added Contracts Appraisal API -Regular Expression Filter -Added Planetary Facilities -Added undo/redo to all text components -Better planetary assets integration throughout the program Bug Fixes: -Stockpile always showed location all -Excluded planets from the routing tool and UI menu (not valid destinations) -Possible fix for BugId: 750 Changed: -Tracker now ignore sell orders that is still in assets (to avoid duplicates) Code: -Optimization of the Routing and Overview tools -Fixed issues found by LGTM.com -Better Uncaught Exception Handling -Better error handling for JSon reading and writing (BugId: 744) -Fixed problem with Java 11 and Java 12 (still primarily developed on Java 8) ________________________________________________________________________________ _5.9.0__________________________________________________________________________ New Features: -Added meta column to the stockpile -Update from the command line (with -backgroundupdate) -Use Bookmark endpoints to resolve structures (require new scope) -Planetary Assets (require new scope) -Multibuy export in the stockpiles shopping list -Eve multibuy export in the Copy+ menu -Blueprint Runs in the Stockpile tool -Evepraisal in the loopup menu -Adam4EVE in the lookup menu -Eve-MarketData in the lookup menu -eve-hub in the lookup menu -evemarkethelper in the lookup menu -khon.space in the lookup menu Bug Fixes: -Fixed system names in pricing regions selector. (Contributed by AnrDaemon) o7 -Fix for Bug ID: 739 (thread safety) Changed: -Removed eve-markets from the lookup menu (dead) Code: -Better retry logic for ESI requests -Updated EveKit library to 5.0.1 -Updated eve-esi to 3.2.0 (major improvements) -Updated pricing to 2.1.1 ________________________________________________________________________________ _5.8.2__________________________________________________________________________ Bug Fixes: -ESI structure import stops on 404 errors -Minor improvement to thread safety on update ________________________________________________________________________________ _5.8.1__________________________________________________________________________ New Features: -Added fuzzwork as a price data source Bug Fixes: -Fixed price updates continuing download after canceled Changed: -Removed eve-marketdata as a price source and from the lookup menu -Prioritize user and esi citadel data over hammerti.me Code: -Updated eve-esi to 2.4.0 -Updated pricing library to 2.0.0 Notes: -Give the fuzzwork price source a try. It's lightning fast. ________________________________________________________________________________ _5.8.0__________________________________________________________________________ New Features: -Improved Stockpile filters -Advanced Filters (OR groups) -Added zKillboard item database to the lookup menu -Added EVE Ref item database to the lookup menu Bug Fixes: -Crash: NPE in JMenuUI (BugID: 708) -Corporation market orders on characters in the isk/values/tracker tools Code: -Moved asset added data to SQLite ________________________________________________________________________________ _5.7.4__________________________________________________________________________ Bug Fixes: -Better handling of EveKit updates ________________________________________________________________________________ _5.7.3__________________________________________________________________________ Bug Fixes: -All packed assets now have the correct volume (require latest data update) -Better handling of corrupted settings and profile files -Better handling of invalid ESI accounts (auth failures) -Settings not saved when adding items to the stockpiles Code: -Updated eve-esi to 2.3.5 (URL encoding fixed) ________________________________________________________________________________ _5.7.2__________________________________________________________________________ Bug Fixes: -ESI import showed invalid account before authorizing on the EVE SSO web site -ESI workaround for universe names not resolving faction ids -Overview displayed wrong system/region for systems -Wrong count of total rows in some tools -Date filter equals/before/after did not match correctly -Column name was not always fully visible when sorted -Tracker asset filter selecting and filtering was not working correctly -Fixed two crash bugs (BugID: 693 and 687) Changed: -Always show output value in table (table menu and statusbar unchanged) -Ask to include all tracker asset filter locations (once) -Delete unused library files Optimizations: -Column resizing (All tools with tables - also faster filtering) -Materials Tool -Separator Table (Stockpile/Contracts/Materials/Reprocessing/Loadout) Code: -Updated eve-esi to 2.3.4 (Use PKCE, instead of client secret) ________________________________________________________________________________ _5.7.1__________________________________________________________________________ Bug Fixes: -Fixed crash when opening the Tree tool (BugId: 681, 682, 683, 684) -Container column was not updated when changing asset names -Would not always use the newest data -Fixed error with name updates (faction ids) ________________________________________________________________________________ _5.7.0__________________________________________________________________________ New Features: -Major optimization of settings IO -Allow unchecking all unknown locations in the tracker assets filter -Tracker assets filter search -Import tracker data from file -Added issued by column to market orders -Updated jmemory (Warn on 32bit Java and better error messages) -Now run with jmemory after update (if jmemory was used to start jEveAssets) -More memory optimiaztions -Better handling of structure assets Bug Fixes: -Tracker purge removed too much -Asset safety is not an unknown location ________________________________________________________________________________ _5.6.0__________________________________________________________________________ New Features: -Added Fuzzwork Blueprint Calculator to the Lookup menu -Added Fuzzwork Market to the Lookup menu -Added Eve Info item database to the Lookup menu -Delete known invalid tracker asset locations -Major Memory Optimizations -CPU Optimization of Tracker, Routing, Ship Fittings, Stockpile Bug Fixes: -Industry Jobs Assets was missing ME/TE/RUNS and had wrong BPO/BPC -Workaround for deleted PI structures Changed: -Removed Eve-Central from the lookup menu -Removed Conquerable Stations -Ignore Wormhole and Abyssal locations in the routing tool ________________________________________________________________________________ _5.5.1__________________________________________________________________________ New Features: -Backup files are now zipped Bug Fixes: -Failed to exit when a minimized update was running -ESI Contract Items failed with 404 -Stockpile manufacturing did not include reactions -Workaround for ESI universe/names not supporting factions -Better handling of profiles (including a bug fix and optimization) ________________________________________________________________________________ _5.5.0__________________________________________________________________________ Bug Fixes: -New logic to ensure uniqueness of Journal and Transactions -Possible fix for tracker problems -Don't try to update active ship via EveKit for corporations Changed: -Removed support for the now dead XmlAPI -Increased the amount of times ESI retries from 1 to 3 -Update error message from "Not allowed yet" to "Waiting for cache to expire" -Added warning when EveKit accounts have invalid ESI auth -Workaround for 9e18 locations Code: -Updated eve-esi to 2.1.8 -Updated EveKit to 2.4.0.2 ________________________________________________________________________________ _5.4.3__________________________________________________________________________ Code: -Updated EveKit library to 2.4.0 (ESI data model) -Updated EveAPI library to 7.0.4 -Updated eve-esi library to 2.1.5 ________________________________________________________________________________ _5.4.2__________________________________________________________________________ Bug Fixes: -Fixed bug introduced in 5.4.1 (BugId: 641/642/644) ________________________________________________________________________________ _5.4.1__________________________________________________________________________ New Features: -Get closed Market Orders from ESI (new endpoints) Bug Fixes: -Fixed a few bugs (BugId: 635 and 631) Changed: -Split Market Orders quantity into two columns (easier export) ________________________________________________________________________________ _5.4.0__________________________________________________________________________ New Features: -Added Manufacturing/Reactions output to the Assets tool (Optional) -Added shopping list and eve multibuy import to the stockpile Bug Fixes: -Stockpile Shopping List did not distinguish between BPC and BPO -Industry Jobs in the assets list now have the correct flag Code: -Updated glazedlists to 1.11.0 -Updated eve-esi to 2.0.2 (fix missing contracts - x-pages) ________________________________________________________________________________ _5.3.0__________________________________________________________________________ New Features: -Added count to Transactions statusbar and popup menu. -Added difference between start and end date to the Tracker tool statusbar -Last X Hours filter -Unknown locations in the tracker are now resolved by citadel/structure updates -Lookup for fuzzwork item database -Structure update and EveKit tracker import can now be done in the background Bug Fixes: -Old Market Orders from the XmlAPI was never marked as done -ESI error limit did not handle negative wait values -Filter cache was not updated after adding/removing Tags -Stockpile Export/Import could duplicate Tags Code: -Warn about assets with bugged locations -Better handling of settings update failure -Updated JFreeChart to version 1.5.0 (Fix a few problems) -Updated EveKit library to 4.0.2 -Updated eve-esi to 2.0.0 ________________________________________________________________________________ _5.2.0__________________________________________________________________________ New Features: -Added Export in EFT format in Ship Fittings Tool -ESI UI: Lookup owners in-game -Routing: Added stations -Routing: Save/Load calculated routes -Routing: Add locations from other tools -Check for program/data updates once an hour and show result on the statusbar Bug Fixes: -Splash screen disappear before frame is shown -Market Orders missing from Stockpile -Settings closed when pressing Apply -Ignore empty fittings when exporting all fittings to Eve XML fittings format -Fixed locations menus (again) -Fixed BugID: 620 -Possible fix for BugID: 622 621 -Possible fix for BugID 326 Changed: -A few Routing GUI improvements -Added Cargo to Eve XML Fittings export Code: -Updated eve-esi-dev to 1.4.9 (use Double for ISK values) ________________________________________________________________________________ _5.1.1__________________________________________________________________________ Bug Fixes: -ClassCastException in StockpileItemDialog (BugID: 615) -Fixed Eve XML fittings export format to be compatible with pyfa -Tree Tool locations values was wrong -Fixed minor issue with the window settings -Possible fix for Issue #24 (BugID: 616) -Journal error code 500 (ESI Bug FIx) -ESI singleton bug (missing: container/ship names, fittings - ESI Bug FIx) Code: -Memory Optimization -Use the dev version of ESI (eve-esi-dev - fix the singleton bug) ________________________________________________________________________________ _5.1.0__________________________________________________________________________ New Features: -Assets: Include active ship in space (ESI) -Table Menu: Open in-game market/contract windows and set waypoint -Routing Tool: Set in-game waypoints -Support reactions in Industry Jobs and Stockpile (counted as manufacturing) -Added more options to the structure update Bug Fixes: -Jumps menu clear was not working -Jump columns was sometimes empty -Editing unknown locations in the overview tool did not work -Fixed a lot of issues with menus that use locations -Industry Jobs Reactions was marked incorrectly -Industry Jobs now count canceled and reverted as delivered -Better BPO detection for Industry Jobs -Disabled filter was included when exporting -Fixed Journal update errors (ESI bug fix) Changed -Better Account Manager user interface -Better column selection in the export dialog Code: -Better uncaught exception handling -Update eve-esi to 1.4.6 ________________________________________________________________________________ _5.0.5__________________________________________________________________________ Bug Fixes: -Contracts was missing names/locations after update -420 in corporation contract items (rate limit) -Industry Job reactions was not being marked correctly Changed: -Updated the help menu to be more helpful Code: -Updated eve-esi to 1.4.4 -Optimized filtering (with cache) ________________________________________________________________________________ _5.0.4__________________________________________________________________________ Bug Fixes: -Industry jobs was missing reactions activity (Failed update) -Tracker related crash bugs -Structure update failed on Java 9 -Citadels was being incorrectly marked -Profiles was not being saved on shown change -Workaround for crash bug with BugID: 492 (Java Bug) -Fixed problem with Industry Jobs locations Changed: -Better GUI for the structure update Code: -Update jFreeChart to 1.0.19 ________________________________________________________________________________ _5.0.3__________________________________________________________________________ New Features: -Location Settings -Export/Import ESI Keys Bug Fixes: -Fixed the bugs introduced in 5.0.2 Code: -Optimized update of dynamic values (Asset Names/Prices/Locations) ________________________________________________________________________________ _5.0.2__________________________________________________________________________ New Features: -Now shows an animation while doing lengthy tasks Bug Fixes: -Fixed CtD when changing profile -Fixed a few bugs related to price updates (BugID: 559, 558) -Possible fix for XML loading bugs (BugID: 548, 564, 563) -Fixed contracts NPE (BugID: 561, 557, 561, 560) -Fixed ESI corporation contract items update failure (BugID: 555, 565) -Fixed ESI structure update failure -Could not reset user locations Changed: -Now mark ESI market orders no longer in the return as Unknown -ESI Structure updates have been move to Its own update window Code: -Increased the maximum log size -Updated EveAPI library to 7.0.2 -Updated Pricing library 1.8.0 -Update jmemory to 3.0.0 ________________________________________________________________________________ _5.0.1__________________________________________________________________________ New Features: -Added EveMarketer to lookup menu Bug Fixes: -Ignore trained skill -Missing names (again and again) -Manually close ESI orders when they're removed from the return (Workaround) -Contract Items and Assets incorrectly marked as BPO (Workaround) -Orders have wrong owner (when both character and corporation order is present) -Better handling of headless Java -Workaround for Desktop.browse -Fixed another issue with adding ESI accounts -Duplicate assets -Possible fix for errors when updating ESI Contract Items -Possible fix for 502 in ESI Structure endpoint ________________________________________________________________________________ _5.0.0__________________________________________________________________________ New Features: -Support for ESI Corporation accounts Bug Fixes: -Fixed missing names (BugID: 542, 544, 546) -Fixed the compatibility issue with Java 9 (BugID: 545, 547) -Possible fixed for NPE in JContractsTable (BugID: 551) -A few minor bug fixes Code: -Better error handling (again) ________________________________________________________________________________ _4.5.2__________________________________________________________________________ Bug Fixes: -Fixed missing names -Updated BPO/BPC detection code -Better error handling for update threads -Better handling of cancel while updating -Better ESI error limit support -Made RawConverter thread safe -Better ESI migration warning ________________________________________________________________________________ _4.5.1__________________________________________________________________________ Bug Fixes: -Fixed Market orders duplicates -Fixed transactions fail to convert float to integer -Fixed NPE in ProfileWriter (BugID: 539) -Fixed NPE in AbstractEsiGetter -Fixed NPE in MyIndustryJob (BugID: 541) -Possible fix to NPE in UpdateTask (BugID: 540) -Possible fix for universe/names errors (BugID: 542) Code: -Updated eve-esi library to 1.4.1 ________________________________________________________________________________ _4.5.0__________________________________________________________________________ New Features: -Support for ESI characters (shorter cache times, with a few exceptions) -Update ESI/EveKit/EveAPI in threads (faster updates) -Added support for evemarketer.com as a price source Code: -Completely new data backend with support for EveAPI/EveKit/ESI ________________________________________________________________________________ _4.1.5__________________________________________________________________________ Bug Fixes: -ESI was not working Changed: -Eve-Central is disabled (Will use Eve-MarketData instead) ________________________________________________________________________________ _4.1.4__________________________________________________________________________ Bug Fixes: -Failed price updates set all prices to zero (pricing library) -Better handling of corrupted setting/profile files Code: -Updated pricing library -Updated ESI library -Faster price updates (pricing library) ________________________________________________________________________________ _4.1.3__________________________________________________________________________ New Features: -Added support for basic proxy authentication Changed: -New forum thread Bug Fixes: -Fixed proxy support (everything now use the proxy settings) -Fixed Eve-MarketData support -ESI accounts never expire -Fixed two crash bugs and a few of minor ones ________________________________________________________________________________ _4.1.2__________________________________________________________________________ Bug Fixes: -Workaround for java crash: https://bugs.openjdk.java.net/browse/JDK-8179014 -Ignore itemIDs in the structure endpoint Code: -Better logging for API updates ________________________________________________________________________________ _4.1.1__________________________________________________________________________ Bug Fixes: -Stockpile manufacturing jobs used blueprint TypeID instead of product typeID -Update Dialog showed wrong update times (included accounts without permission) ________________________________________________________________________________ _4.1.0__________________________________________________________________________ New Features: -ESI structure endpoint (Resolve structure names, optional) -Tracker: You can now add notes (Limitation: 1 note per day) -Stockpile: Tags (just like in the Assets tool) -Stockpile: Shopping list allow you to hide items above X% full Changed: -Rearranged the tool menu -Creates backup of data when a new version is run for the first time -Made the citadel update more resilient to errors -Use https for updates and bug reports -Stockpile: Optimized -Assets: Type count column now counts BPO and BPC separately Bug Fixes: -Account import: Better handling of cancel and previous -Stockpile: Shopping list did not include contract items -Tree: Containers and ships was missing if their children was filtered out -Tree: Category tool had unknown locations for items without a location -Stockpile: All blueprints match both BPC and BPO ________________________________________________________________________________ _4.0.1__________________________________________________________________________ Code: -Stockpile Optimization Bug Fixes: -Journals and Transactions are missing -Better handling of account editing -Fixed reprocessing calculation ________________________________________________________________________________ _4.0.0__________________________________________________________________________ New Features: -EveKit support -Import tracker data from EveKit -Rename unknown locations -Added unknown locations and citadels to the stockpile tool -Lookup all locations for items with multiple locations (Stockpile/Contracts) -Added option to use stronger colors -Show time until the the first and last account can be updated Changed: -Made it easier to reactivate expired accounts -You can now copy the error message from the update dialog -The Citadel API is now cached at my server Bug Fixes: -Profiles was not saved on creation -Removed wrecks from the Assets Tool -Fixed ISK per Hour import Code: -Moved to glazed list 1.10 ________________________________________________________________________________ _3.1.4__________________________________________________________________________ Bug Fixes: -All Market Order/Journal/Transaction history deleted on update ________________________________________________________________________________ _3.1.3__________________________________________________________________________ Changed: -Assets API to only use flat list now Bug Fixes: -Fixed warning from citadel API -Fixed citadel API progress display Code: -Updated EveAPI to 7.0.1 ________________________________________________________________________________ _3.1.2__________________________________________________________________________ New Features: -Enabled GZip support for the pricing library (faster price update) Bug Fixes: -Better error handling for the the stop.hammerti.me.uk citadel API Known issues: -Blueprint in contracts are always marked as BPC (API Bug) ________________________________________________________________________________ _3.1.1__________________________________________________________________________ Bug Fixes: -Better integration of the stop.hammerti.me.uk citadel API Known issues: -Blueprint in contracts are always marked as BPC (API Bug) ________________________________________________________________________________ _3.1.0__________________________________________________________________________ New Features: -Added support for getting assets in citadels -Added blueprint runs to Assets and Tree tools -Added reset to QuickDate in the tracker tool -Added option to hide zero in the tracker tool Changed -Stockpile: Hide the column text for excluded count columns -Removed eve-online wiki from lookup menu -Updated credits.txt and about dialog Bug Fixes: -Bought contracts always included in stockpile Known issues: -Blueprint in contracts are always marked as BPC (API Bug) ________________________________________________________________________________ _3.0.4__________________________________________________________________________ Bug Fixes: -JAutoCompleteDialog never set strict -JDropDownButton component must be showing on screen (BugID 420 & 281) -Do not try to get expired market orders from the API Changed: -Excluded "Escrows To Cover" from the tracker total Code: -Updated EVEAPI to the latest version -Better error messages for uncaught exceptions -Moved from jCalendar to LGoodDatePicker Known issues: -Assets in citadels are not included in the API (Workaround in the works) -Blueprint in contracts are always marked as BPC (API Bug) ________________________________________________________________________________ _3.0.3__________________________________________________________________________ Bug Fixes: -Fixed problem with updating contracts in citadels -Fixed problem with reading AccessMask in ProfileReader -The price cache time was not loaded on startup Code: -Better handling of old versions of Java Known issues: -Assets in citadels are not included in the API (API Bug) -Blueprint in contracts are always marked as BPC (API Bug) ________________________________________________________________________________ _3.0.2__________________________________________________________________________ Bug Fixes: -Possible fixes for following bugs with BugID: 281, 412, 406, 403 -Fixed crash when removing multiple avoid system from the routing tool -Old market orders are never marked as completed (BugID 410) -Better handling of missing data and library files -Warning when trying to run jEveAssets from inside the zip file Changed: -Blueprints in contracts now use PBC value (zero). See bellow... Known issues: -Assets in citadels are not included in the API (API Bug) -Blueprint in contracts are always marked as BPC (API Bug) ________________________________________________________________________________ _3.0.1__________________________________________________________________________ Bug Fixes: -Possible fix for bugID: 397 (ArrayIndexOutOfBoundsException) -Bug Fix: Journal and Transaction were missing valid duplicates ________________________________________________________________________________ _3.0.0__________________________________________________________________________ New Features: -Transactions: Added average price to status bar and popup menu -Market Orders: Added history -Market Orders: Added last opposite transaction price/profit/percent columns -Tracker: Total now only include selected values (Include/Exclude) -Stockpile: Export/Import to xml -Import/Export Filters -More user friendly import of text -Price Update Options (All/New/None) -Jump columns (via table menu) -Release updates via installer -Stockpile: Exclude Location -Stockpile: Added contracts -Industry Jobs: Added count to status bar and popup menu -Tracker/Isk/Values: Added contracts -Tracker: Added Location/Corporation Hangar and Wallet Division filters Changed: -Use the latest version of EVEAPI -Moved to Java 8: require Java 8 to run (will still compile on Java 7 JDK) Bug Fixes: -Contracts: kept old data after updating from the API -Fixed a lot of GUI problems on Linux (Unity/GNOME/KDE) -File locks was not working correctly -Transactions failed to update ________________________________________________________________________________ _2.10.5_________________________________________________________________________ Changed: -Added User Agent to HTTP requests (Global) -Safer backup and restore of settings files -Don't update missing prices on startup (price 1.4.0) -Changed jUpdate download location (To make sure we have write access) Bug Fixes: -AIOOB EnumTableFormatAdaptor (Critical) -FilterSave deadlock read lock (Critical) -IllegalArgumentException in SeparatorList (Critical) -Stockpile table colors did not working with the default value -Buy/Sell Transaction columns are not grayed out when exclude -Reprocessed grand total remove button not disabled -Removed dead lookup links -Settings -> Window: The order of JTextField are illogical -Stockpile Dialog are not updated before shown (Empty location fields) ________________________________________________________________________________ _2.10.4_________________________________________________________________________ Bug Fixes: -Possible fix for IllegalArgument in getLocalFile() (BugID: 284 and 179) -ConcurrentModificationException in HashMap constructor (BugID: 202 and 282) -NullPointerException in ProfileWriter (BugID: 285) ________________________________________________________________________________ _2.10.3_________________________________________________________________________ Changed: -Changed Google Code links to GitHub -Minor optimization to stockpile tool -Updated Glazed Lists library to 1.9.1 -Removed eve.addicts.nl Bug Fixes: -Added Glazed list read locks (could fix some bugs or not) -Save eve fittings (wrong type name) -Race condition when updating (tracker point creation) -Settings was not saved after deleting stockpile -ArrayIndexOutOfBounds in EnumTableFormatAdaptor ________________________________________________________________________________ _2.10.2_________________________________________________________________________ Bug Fixes: -Saving Journal/Transactions history didn't work -Profile was not always saved when changed in Account Manager ________________________________________________________________________________ _2.10.1_________________________________________________________________________ Bug Fixes: -Possible fix for Update/ISK/Tracker/Values bug ________________________________________________________________________________ _2.10.0_________________________________________________________________________ New Features: -Blueprints API (Asset/Tree/Industry: ME/TE & BPC/BPO) -Added profiles filter to the Tracker tool -Added option to delete data point for all owners -Added Contract Collateral to the Isk/Values/Tracker tools Changed: -Changed the font and formating of the Tracker tool chart -Now remove owner from the Tracker when the last data point is deleted Bug Fixes: -Fixed date format in the Tracker Tool ________________________________________________________________________________ _2.9.1__________________________________________________________________________ Bug Fixes: -Bad layout in the tracker tool -Reprocessing calculations for items ________________________________________________________________________________ _2.9.0__________________________________________________________________________ New Features: -Stockpile: Adjustable percentage grouping -Tracker: Multiple characters select -Date filter: Last X Days Bug Fixes: -Updated reprocessing to the latest formula and fixed reprocessing skills -Accounts was not saved when deleted/added ________________________________________________________________________________ _2.8.7__________________________________________________________________________ Changed: -Assets converted from industry jobs are now always marked as BPC Bug Fixes: -Industry Jobs Output Count/Value was not working (Thanks to Busje Komt Zo) -Tracker manufacturing was always zero (Same bug as above) -Crashed when filters contained removed columns (Thanks to Uber Pie) ________________________________________________________________________________ _2.8.6__________________________________________________________________________ Changed: -Static data updated to Crius 1.0.0 -Removed PE/ME from industry jobs and assets (no longer part of the API) -Removed BPO/PBC from industry jobs (no longer part of the API) Bug Fixes: -Industry Jobs was not updating (due to API changes) ________________________________________________________________________________ _2.8.5__________________________________________________________________________ Changed: -Static data updated to Kronos 1.0.0 Bug Fixes: -Auto update could fail before asked to update ________________________________________________________________________________ _2.8.4__________________________________________________________________________ New Features: -New bug report dialog -Added new column: 'Installer' to the Industry Job Tool Changed: -Better API Update error messages Bug Fixes: -Settings was not saved when editing or deleting Tracker data point -Settings was not saved when changing Stockpile Target or Multiplier -Contracts owners was not updated correct ________________________________________________________________________________ _2.8.3__________________________________________________________________________ Changed: -Better auto update code (update jupdate.jar and validate downloaded files) Source: -Deploy: Upload release automatic Notes: The new auto update code will only be used when updating from 2.8.3 to any later version. Updating to 2.8.3 will still use the old code. ________________________________________________________________________________ _2.8.2__________________________________________________________________________ Bug Fixes: -Routing Mutation 2-opt and Crossover does not work ________________________________________________________________________________ _2.8.1__________________________________________________________________________ Bug Fixes: -Possible fix for BugID: 3, 4, 5, 6 ________________________________________________________________________________ _2.8.0__________________________________________________________________________ New Features: -Tree Tool Sorting -Routing: Avoid System (By name or security) -Industry Jobs: Manufacturing Output Value -Assets: ME/PE columns -Added time to date columns -Added simple bug reporting tool -Added auto update tool (program and static data) Changed: -Date format is now ISO 8601: yyyy-MM-dd (Warning: May break your filters) -Updated static data to Rubicon 1.3.0.95173 -Now save settings when they are changed (disable with "-lazysave") Bug Fixes: -StackOverflowError (PaddingTableCellRenderer) ________________________________________________________________________________ _2.7.3__________________________________________________________________________ Changed: -Updated static data to Rubicon 1.0.4.93577 -Api Keys: Assets access is now optional -Updated eve toolkit copyright Bug Fixes: -Current filter name not displayed -BPO shown as BPC ________________________________________________________________________________ _2.7.2__________________________________________________________________________ New Features: -New Contract Column: Status Bug Fixes: -Assets included completed contracts -Empty accounts was hidden in account manager ________________________________________________________________________________ _2.7.1__________________________________________________________________________ Changed: -Save history for Transactions and Journal (Optional - on by default) -Support for EVE API HTTP errors (Invalid accounts) -Updated static data to Rubicon 1.0.93082 Bug Fixes: -Java 6 could prevent jEveAssets from exiting -Copying from Materials/Loadouts/Overview tables now include all columns -Copying from tables added an extra newline at the end -Stockpile EFT Import could not import drones -Transaction and Journal now supports API walking (Thanks Yinmatook) ________________________________________________________________________________ _2.7.0__________________________________________________________________________ New Features: -New Tool: Wallet Journal -New Tool: Tree (Assets by location or category) -Tool Views (Save/load column presets - works with export as well) -Added manufacturing to Isk and Tracker tools -Added Export to Materials, Ship Loadouts, and Overview tools -Export: Html formatting and in game browser links (both optional) -Export: Use table sort order -New Assets/Tree/Overview column: isk/m3 (Contributed by Saulvin - Thanks!) -Stockpile: Advanced filters (Multiple locations/owners/containers/flags) -Added tags to the Asset and Tree tools -Use base price for PBOs (Optional tech 1/tech 2) -Stockpile: Added transactions (Items bought/sold after last asset update) -Stockpile: Now accepts decimals (always rounded to ceiling) Changed: -Export greatly improved -Table Copy: Now use the shown value Bug Fixes: -Stockpile shopping list could count the same item multiple times -Stockpile: Editing items would leave duplicate items ________________________________________________________________________________ _2.6.3__________________________________________________________________________ Bug Fixes: -Packaged ships showed unpacked volume and vice versa (Thanks llllSeraphimllll) ________________________________________________________________________________ _2.6.2__________________________________________________________________________ Changed: -Updated static data to Odyssey 1.1.91288 ________________________________________________________________________________ _2.6.1__________________________________________________________________________ Bug Fixes: -Active industry jobs incorrectly marked BPO as BPC in the asset tool -More minor bug fixes Changed: -Updated static data to Odyssey 1.0.9.89602 ________________________________________________________________________________ _2.6.0__________________________________________________________________________ New Features: -New Tool: Wallet Transactions (by Ima Sohmbadi) -Routing: Major overhaul -Assets: Rename Container -Account Import: Error handling -Stockpile: Import shopping list from "Eve ISK Per Hour" -Tracker: Edit data points -Items: Reprocessed Column -Optimized many parts of jEveAssets -Many more minor changes and bug fixes Changed: -Better handling of multiple instances of jEveAssets -Library: Updated Glazed Lists to 1.9.0 -Library: Updated EVEAPI to the latest version -Source: Major cleanup of the source code -Source: Made it easy to checkout and compile (maven.nikr.net) ________________________________________________________________________________ _2.5.4__________________________________________________________________________ Changed: -Updated static data to Odyssey 1.0.89097 ________________________________________________________________________________ _2.5.3__________________________________________________________________________ Bug Fixes: -API Bug: The contract API returns alien contracts (Temp ban fix) -Export Bug: Changing the decimal separator was ignored until next export Changed: -Updated static data to Retribution 1.1.84566 ________________________________________________________________________________ _2.5.2__________________________________________________________________________ New Features: -Added "None" container label Bug Fixes: -Industry Jobs failed to update ________________________________________________________________________________ _2.5.1__________________________________________________________________________ Bug Fixes: -Export: Deselecting columns caused a crash ________________________________________________________________________________ _2.5.0__________________________________________________________________________ New Features: -New Tool: Tracker -New Tool: Reprocessed -New Tool: Contracts -New Tool: Isk -New Asset column: Added date -More resilient table selection and expand/collapse state -Stockpile: Add To now merge items instead of overwriting -Major optimization of Stockpile Add/Edit/Delete -A lot of other optimization! -Some minor bug fixes Note: You need to update your API Keys to include contracts ________________________________________________________________________________ _2.4.4__________________________________________________________________________ Bug Fixes: -Fixed table corruption on OpenJDK (Thanks to Jan) -Items Tool got a new icon Changed: -Updated static data to Retribution 1.0.7.463858 ________________________________________________________________________________ _2.4.3__________________________________________________________________________ Bug Fixes: -Crash when sorting stockpile. (Thanks to Mysterion eXe) ________________________________________________________________________________ _2.4.2__________________________________________________________________________ Bug Fixes: -Eve-Central: Can not update price data (Thanks Carten) ________________________________________________________________________________ _2.4.1__________________________________________________________________________ Bug Fixes: -Stockpile ignored everything except typeID ________________________________________________________________________________ _2.4.0__________________________________________________________________________ New Features: -Export: Use tool column selection and order -Export: Html & SQL export -Tables: Save column width (Auto resize off) -Stockpile: Distinction betwen BPC and BPO -Reprocessed Colors: Zero = Gray -New Columns: Reprocessed & Price Difference (Value & Percent) -New Columns: Market Orders price -Overview: Load asset filter -Stockpile: Shopping list for multiple stockpiles -Stockpile: Add to stockpile - can be used to merge (multiple selection) -Better UI for custom Price/Name (multiple selection - prices only) -Price Data: Reprocessed Price selectable seperate Changed: -Updated static data to Inferno 1.2.76477 Bug Fixes: -Stockpile included non-active orders -GMT mixup -IPv6 connection failure (force IPv4) -Some minor bug fixes and optimization ________________________________________________________________________________ _2.3.0__________________________________________________________________________ New Features: -Added "Selection Information" to all tables menus -Added info to the Overview statusbar -Added Station/System selection to the price sources that support it -Added eve.addicts.nl as price source -Added percentile/5% to all price sources Changed: -The stockpile statusbar now show values for shown item (not for all items) Bug Fixes: -Fixed bug: CSV export: New filter is not available -Fixed bug: Incompatible with Java 6u33 & 7u5 (Thank you Flaming Candle!) -Fixed bug: Hide/show columns could crash the program -A lot of minor bug fixes ________________________________________________________________________________ _2.2.0__________________________________________________________________________ New Features: -New Tool: Items (items database) -Table menu now works with multiple selection -Added EveMarketeer (As price source and to the lookup menu) -Added Eve Addicts to the lookup menu (eve.addicts.nl) -Market Orders: Added info to the statusbar -Industry Jobs: Added invention success to the statusbar -Stockpile: Added percent full column -Hide/show columns now has Its own dialog -Market Orders: Joined the Buy and Sell table -Market Orders/Industry Jobs: Added some predefined filters -Filter Manager: Can now delete multiple items at once -Eve-MarketData: Added support for region selection -Added better program icons (for windows 7 taskbar etc.) -Added Flag path (as suggested by Scrapyard Bob) -Added window Always On Top option -Stockpile: Added table sorting -Assets: Added reprocessed value to the statusbar -Assets: Added Buy Orders (Optional) (Sell orders are now optional as well) Changed: -Removed support for prices.c0rporation.com -CSV Export: Now remember selected columns (again) -Tables: Columns auto resizing is now optional (again) -Highlight selected row(s) now work on all filter tools -Only filter on enter now works again and for all filter tools -Static data updated to Inferno 1.0.70633 Bug Fixes: -Fixed a rare bug in the save filter dialog (text was locked) -Fixed a translation bug in Price Data Settings ________________________________________________________________________________ _2.1.2__________________________________________________________________________ Changed: -Static date updated to Escalation 1.0.0 ________________________________________________________________________________ _2.1.1__________________________________________________________________________ Bug Fixes: -CSV Export: Saved/Current Filter is broken -Load Filter: Scroll when needed (Also work with mouse wheel) ________________________________________________________________________________ _2.1.0__________________________________________________________________________ New Features: -Stockpile: Shopping List (With percent full) -Stockpile: Added labels for Location/Owner/Minimum Percent Full -Stockpile: EFT import -Separator Table: double click to expand/collapse -Materials: Moved summary to the top -Materials: Added total for stations -Materials: Added price column -Materials: You can now collapse/expand locations -Assets: Added Tech column (Meta is can now be compared as a number) Bug Fixes: -Stockpile: Cancel refresh stockpile list -CSV Export: Line Delimiter was not added correct... -CSV Export: Float & Integer always had dot as decimal separator Changed: -Static date updated to Crucible 1.6.0 ________________________________________________________________________________ _2.0.0__________________________________________________________________________ New Features: -Date filtering (Before/After/Equals etc.) -Added CSV export to Industry Jobs, Market Orders, Stockpile -Added customizable columns to Industry Jobs, Market Orders, Stockpile -Added filtering to Industry Jobs, Market Orders, Stockpile -Industry Jobs: Added new column "Region" -Assets: Added new column "Total Volume" -Market Orders: Added new columns "Issued", "Owner", "Region" Known Issues: -Missiles are named wrong ________________________________________________________________________________ _1.9.2__________________________________________________________________________ New Features: -Stockpile: Use table menu to edit items -Stockpile: Remember collapsed/expanded state when updating -Stockpile: Now sort by group before name -Stockpile: Assets focus (Optional) -Stockpile: Color coding (Optional) -Stockpile: Performance optimization Bug Fixes: -Stockpile: Items can be added twice Changed: -Static data Updated to Crucible 1.0.0 ________________________________________________________________________________ _1.9.1__________________________________________________________________________ Bug Fixes: -Offices shown as !27 -Stockpile: Corporation items is not added properly -Stockpile: Offices items is not added properly ________________________________________________________________________________ _1.9.0__________________________________________________________________________ New Features: -New Tool: Stockpile ________________________________________________________________________________ _1.8.1__________________________________________________________________________ Bug Fixes: -Now compatible Java 7 (and Java 6) -Materials, Ship Loadouts, and Account Management now use less CPU -Meta column is now filtered correct (again) -Settings.bac is now restored automatically (again) ________________________________________________________________________________ _1.8.0__________________________________________________________________________ New Features: -Overview: Added buttons for views (Instead of the ComboBox) -Overview: Added Security column -Assets: Much better filtering of numbers -Assets: Added Singleton Column -Industry Jobs: Active/Ready/Pending -Materials: Added PI materials (optional) -Third mouse button close tab -Load Filter: CTRL+Click now adds filter instead of overwriting existing filter -Remember CSV Export settings Changed: -Static data Updated to Incarna 1.1.0 Bug Fixes: -Fixed settings dialog height on XFCE 4 ________________________________________________________________________________ _1.7.3__________________________________________________________________________ New Features: -Now use the new Customizable API keys (CAKe) -Automatically mark blueprints as BPO/BPC (except for market orders) Changed: -Static data updated to Incarna 1.0.0 ________________________________________________________________________________ _1.7.2__________________________________________________________________________ Bug Fixes: -Fixed bug that made it impossible to edit price of an item more then once Changed: -Faction prices from prices.c0rporation.com are now optional -Update dialog now use "Today" instead of the weekday name (when eligible) -Now Hide the profile name in the window title, when there is only one profile ________________________________________________________________________________ _1.7.1__________________________________________________________________________ Bug Fixes: -Fix bug that made all faction prices zero -Possible fixed for the StackOverflowError (Issue 146) -Minor optimization ________________________________________________________________________________ _1.7.0__________________________________________________________________________ New Features: -Hide Filters -AssetFilter On/Off -Overview to Routing coupling -Faster Overview Groups -Faction Prices (prices.c0rporation.com) -Set price for BPC -Isk-to-cover -Progress monitor when updating price data on startup -Merge Filters Changed: -Updated the set price/name GUI -Save settings after updating -A lot of i18n ________________________________________________________________________________ _1.6.4__________________________________________________________________________ Bug Fixes: -Fixed missing buttons in the import dialog (Mac Only) -Fixed crash bug in the Industry Jobs tool (When sorting by Activity or Status) -Fixed meta column sorting -Fixed bug that made upgrading from very early version impossible Changed: -Removed Eve-Metrics and Added Eve-Marketdata -Updated static data to Incursion 1.1.0.37959 -Now use EVEAPI 3.0.0 (https!) -Made the yellow cell background darker ________________________________________________________________________________ _1.6.3__________________________________________________________________________ Bug Fixes: -Better handling of price data updates. Changed: -Updated the static data to Incursion 1.0.1.37657 ________________________________________________________________________________ _1.6.2__________________________________________________________________________ Bug Fixes: -MaterialsTab: All corporation materials was ignored ________________________________________________________________________________ _1.6.1__________________________________________________________________________ New Features: -Lookup locations and items on popular eve websites (from the table menu) -Material and Ship Loadout tools have been overhauled -Now compatible with the new 64bit inventory changes Changed: -Better handling of the price data update -A lot of behind the scene changes Bug Fixes: -jeveassets.log is in the wrong location (Mac only) -Packaged ships now have the correct volume -Materials tool contained duplicates in the summary ________________________________________________________________________________ _1.5.0__________________________________________________________________________ -Tools are now tabs in the main window -New Tool: Overview -Now use slf4J and log4j to log events and errors -New layout for the Account Manager -New layout for the Updating Dialog -Numerous bug fixes and minor changes ________________________________________________________________________________ _1.4.1__________________________________________________________________________ Bug fixes: -Routing: Brute Force don't return shortest route (Issue 85) -Conquerable stations are never saved (Issue 98) ________________________________________________________________________________ _1.4.0__________________________________________________________________________ New Features: -Profiles -New API update system (You select what to update) -Enhanced support for mac os x environments -Program update notifications -New settings dialog layout -User settable reprocess efficiency -New special "sell or reprocess" color scheme -Rolling log (prevent the log from ever getting to large) -New pricing option "Midpoint" (sell min + buy max) / 2 -New Column: Reprocessed Value (reprocessed price * count) -Meta Column: Now works as a the other number columns -Asset names can now be changed -Industry Jobs and Market Orders dialogs are now resizable -New API import dialog -Now use EVEAPI 2.0.0 (library) Bug fixes: -Many minor bug fixes... ________________________________________________________________________________ _1.3.0__________________________________________________________________________ New Features: -New Tool: Routing - Find the shortest route between multiple asset locations ________________________________________________________________________________ _1.2.3__________________________________________________________________________ New Features: -Now ignore update timer if the Api Proxy is set Bug fixes: -Possible fix for crash bug in JCustomFileChooser (Java Bug) -Better memory management -Fix minor display bug -Better log output ________________________________________________________________________________ _1.2.2__________________________________________________________________________ Bug fixes: -Fixed bug that would crash jEveAssets when updating assets (industry jobs) -Fixed bug that ignored the update timer for industry jobs Known Issues: -The holiday gift show up as !XXXX ________________________________________________________________________________ _1.2.1__________________________________________________________________________ New Features: -Now backup settings files (on save) Bug fixes: -Fix bug that would sometimes hide industry jobs and market orders -Fixed bug that would crash jEveAssets when updating assets (holiday gift bug) Known Issues: -The holiday gift show up as !XXXX ________________________________________________________________________________ _1.2.0__________________________________________________________________________ New Features: -Added market orders tool -Added industry jobs tool -Now retain window position/size on restart -Added a label to the toolbar that show the current filter -Now show the eve server time on the statusbar -The security column now have the filter modes: "Great than" and "Less than" -Price data from both eve-metrics and eve-central (Candles pricing library) -Added more options to the API Manager -The table now save the selection on update -Added the ability highlight the selected row -The price field in price settings, now have focus when adding a new price Bug fixes: -JTextField swing bug (workaround) -New assets have no price (from Market Orders/Industry Jobs) -Conquerable Stations locations get error string ________________________________________________________________________________ _1.1.0__________________________________________________________________________ New Features: -Added hide/show columns to the main menu -Better error messages when Updating assets -New layout for about dialog -The default eve-central price can now be changed -Added new filter modes: Greater/Less then column (compare two columns) -API keys can now be changed after they have been added -Filtering is now only triggered when no keys have been pressed for 500ms -Now automatically mark blueprints that have been used as copy/original -All settings are now in the same dialog -Improved the way progress is showed when updating assets and price data -New dialog key bindings: Escape cancel and enter saves -Industry jobs: Now adds blueprints in use to the asset list -Market orders: now adds remaining items from sell orders to the assets list -Portable setting: save all files in program directory (see FAQ) -New Column: Reprocessed value -New Column: System security status -Added volume to statusbar and table popup menu Bug fixes: -Fixed bug with invalid proxy settings -Fixed bug with pos and industry jobs -Fixed bug in save filter dialog ________________________________________________________________________________ _1.0.0__________________________________________________________________________ First stable release... ________________________________________________________________________________ ________________________________________________________________________________ ================================================ FILE: checkstyle.xml ================================================ ================================================ FILE: credits.txt ================================================ ######## ##### ######## ####### ### ### ### # ######## # # #### ######### #### #### #### ##### #### ######## # # # ######### # # # # # # ### # # #### ### ### #### #### #### # #### # ######## #### # ### ### # # # # # # ######## ## #### ### ### #### #### #### # #### # ### #### #### #### ### ### ##### #### # # # # # # # # # # #### #### # # # # #### # # # # # # # # # #### # # #### ### ### # #### ________________________________________________________________________________ _CONTRIBUTORS___________________________________________________________________ Developers: Niklas Kyster Rasmussen (Golden Gnu) Dultas Tsuro Tsero Tester: Huzid Contributors: Flaming Candle Jochen Bedersdorfer TryfanMan Jan Ima Sohmbadi Saulvin AnrDaemon Madetara (Ray Kavier) Kaylee Syntax Inoruuk Burberius Lazaren Boran Lordsworth Ed Thelleres Salartarium WildGear snipereagle1 Ansirane Solette Retired Testers: Varo Jan Scrapyard Bob Johann Hemphill Tomasz (kitsibas) Wiktorski ________________________________________________________________________________ _SPECIAL_THANKS_________________________________________________________________ jEveAssets is heavily based on the user interface in EVE Asset Manager Copyright: William J. Rogers Link: http://wiki.heavyduck.com/EveAssetManager License: GNU Lesser General Public License (http://www.gnu.org/licenses/lgpl.html) ________________________________________________________________________________ _EVE-ONLINE_____________________________________________________________________ jEveAssets use EVE-Online API and SDE Link: Main site: https://www.eveonline.com SDE: https://developers.eveonline.com/docs/services/sde/ API: https://developers.eveonline.com/api-explorer SDE License: ©CCP hf. All rights reserved. Used with permission. ________________________________________________________________________________ _FUZZWORK_______________________________________________________________________ jEveAssets use the Fuzzwork API to get price data Link: https://market.fuzzwork.co.uk/api ________________________________________________________________________________ _JANICE_________________________________________________________________________ jEveAssets use the Janice API to get price data Link: https://janice.e-351.com/api/rest/docs/index.html ________________________________________________________________________________ _ZKILLBOARD_____________________________________________________________________ jEveAssets use zKillboard API to get price history Link: https://github.com/zKillboard/zKillboard/wiki/API-(Prices) ________________________________________________________________________________ _EVE_REF________________________________________________________________________ jEveAssets use Reference Data API to get missing item data Link: https://docs.everef.net/datasets/reference-data.html ________________________________________________________________________________ _HOBOLEAKS______________________________________________________________________ jEveAssets use Hoboleaks Data Export via EVE Ref to get missing item data Link: https://sde.hoboleaks.space ________________________________________________________________________________ _SILK_ICONS_____________________________________________________________________ jEveAssets use Silk Icons from famfamfam.com Copyright: Mark James Link: http://www.famfamfam.com/lab/icons/silk License: Creative Commons Attribution 3.0 License http://creativecommons.org/licenses/by/3.0 ________________________________________________________________________________ _GLAZED_LISTS___________________________________________________________________ jEveAssets use Glazed Lists to sort and filter tables Link: http://publicobject.com/glazedlists License: GNU Lesser General Public License (http://www.gnu.org/licenses/lgpl.html) Mozilla Public License (http://www.mozilla.org/MPL/MPL-1.1.html) ________________________________________________________________________________ _SUPER_CSV______________________________________________________________________ jEveAssets use Super CSV to export CSV Link: http://super-csv.github.io/super-csv License: Apache License (http://www.apache.org/licenses/LICENSE-2.0) ________________________________________________________________________________ _EVE-ESI________________________________________________________________________ jEveAssets use eve-esi to get data from ESI Link: https://github.com/burberius/eve-esi License: Apache License (http://www.apache.org/licenses/LICENSE-2.0) ________________________________________________________________________________ _PRICING________________________________________________________________________ jEveAssets use the Pricing library to get price data Link: https://github.com/GoldenGnu/price License: GNU General Public License (http://www.gnu.org/copyleft/gpl.html) ________________________________________________________________________________ _ROUTING________________________________________________________________________ jEveAssets use the Routing library in the routing tool Link: https://github.com/GoldenGnu/routing License: GNU General Public License (http://www.gnu.org/copyleft/gpl.html) ________________________________________________________________________________ _GRAPH__________________________________________________________________________ EveAssets use the Graph library in the routing tool Link: https://github.com/GoldenGnu/graph License: GNU General Public License (http://www.gnu.org/copyleft/gpl.html) ________________________________________________________________________________ _TRANSLATIONS___________________________________________________________________ jEveAssets use the Translations library for i18n Link: https://github.com/GoldenGnu/translations License: GNU General Public License (http://www.gnu.org/copyleft/gpl.html) ________________________________________________________________________________ _SLF4J__________________________________________________________________________ jEveAssets use SLF4J as logging facade Link: http://www.slf4j.org License: MIT License (http://en.wikipedia.org/wiki/MIT_License) ________________________________________________________________________________ _LOGBACK________________________________________________________________________ jEveAssets use logback to log events and errors Link: https://logback.qos.ch License: GNU Lesser General Public License (http://www.gnu.org/licenses/lgpl.html) ________________________________________________________________________________ _SQLITE_________________________________________________________________________ jEveAssets use SQLite for database storage Link: https://github.com/xerial/sqlite-jdbc License: Apache License (http://www.apache.org/licenses/LICENSE-2.0) ________________________________________________________________________________ _JUNIT__________________________________________________________________________ jEveAssets use JUnit for unit testing Link: http://junit.org License: Eclipse Public License (https://junit.org/junit4/license.html) ________________________________________________________________________________ _LGOODDATEPICKER________________________________________________________________ jEveAssets use JCalendar to get user input as a Date Link: https://github.com/LGoodDatePicker/LGoodDatePicker License: MIT License (http://en.wikipedia.org/wiki/MIT_License) ________________________________________________________________________________ _JFREECHART_____________________________________________________________________ jEveAssets use JFreeChart to make charts Link: http://www.jfree.org/jfreechart License: GNU Lesser General Public License (http://www.gnu.org/licenses/lgpl.html) ________________________________________________________________________________ _FLATLAF _______________________________________________________________________ jEveAssets use FlatLaf for themes and enhanced support for mac os x environments Link: https://www.formdev.com/flatlaf License: Apache License (http://www.apache.org/licenses/LICENSE-2.0) ________________________________________________________________________________ _EVALEX_________________________________________________________________________ jEveAssets use EvalEx for formula columns Link: https://github.com/uklimaschewski/EvalEx License: MIT License (http://en.wikipedia.org/wiki/MIT_License) ________________________________________________________________________________ _PICOCLI________________________________________________________________________ jEveAssets use Picocli for the CLI Link: https://picocli.info License: Apache License (http://www.apache.org/licenses/LICENSE-2.0) ________________________________________________________________________________ _COPYRIGHT______________________________________________________________________ Copyright 2009-2026 Contributors (see above) jEveAssets is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. jEveAssets is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with jEveAssets; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. EVE ONLINE COPYRIGHT NOTICE: EVE Online and the EVE logo are the registered trademarks of CCP hf. All rights are reserved worldwide. All other trademarks are the property of their respective owners. EVE Online, the EVE logo, EVE and all associated logos and designs are the intellectual property of CCP hf. All artwork, screenshots, characters, vehicles, storylines, world facts or other recognizable features of the intellectual property relating to these trademarks are likewise the intellectual property of CCP hf. CCP hf. has granted permission to jEveAssets to use EVE Online and all associated logos and designs for promotional and information purposes in this program but does not endorse, and is not in any way affiliated with, jEveAsset. CCP is in no way responsible for the content on or functioning of this website, nor can it be liable for any damage arising from the use of this website. ________________________________________________________________________________ ________________________________________________________________________________ ================================================ FILE: data/agents.xml ================================================ ================================================ FILE: data/flags.xml ================================================ ================================================ FILE: data/items.xml ================================================ [File too large to display: 10.9 MB] ================================================ FILE: data/jumps.xml ================================================ ================================================ FILE: data/locations.xml ================================================ ================================================ FILE: data/npccorporation.xml ================================================ ================================================ FILE: license.txt ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ================================================ FILE: pom.xml ================================================ 4.0.0 net.nikr jeveassets jar 8.1.3-SNAPSHOT jeveassets jEveAssets is an out-of-game asset manager for Eve-Online, written in Java https://eve.nikr.net/jeveasset GitHub https://github.com/GoldenGnu/jeveassets/issues niklas Niklas Kyster Rasmussen niklaskr@gmail.com https://nikr.net/ +1 candle jeveassets@candle.me.uk +1 tryfan TryfanMan beders Jochen Bedersdorfer gavitron Ima Sohmbadi tsurotsero Tsuro Tsero GNU General Public License 2.0 http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt scm:svn:http://svn.candle.me.uk/nikr/jeveassets/trunk/ http://svn.candle.me.uk/nikr/jeveassets/trunk/ org.apache.maven.plugins maven-jar-plugin 2.4 jeveassets ${main.class} net.nikr.eve.jeveasset true lib splash.jpg org.apache.maven.plugins maven-compiler-plugin 2.4 1000 1000 true true ${project.build.sourceVersion} ${project.build.sourceVersion} ${project.build.sourceEncoding} -Xlint org.apache.maven.plugins maven-resources-plugin 2.5 ${project.build.sourceEncoding} maven-antrun-plugin 1.7 process-resources process-resources run copy-to-install package run copy-profiles process-resources run ant-contrib ant-contrib 20020829 commons-net commons-net 1.4.1 ant ant-commons-net 1.6.5 org.apache.maven.plugins maven-dependency-plugin 2.4 copy-dependencies process-test-resources copy-dependencies junit,hamcrest ${project.build.directory}/lib false false true false org.apache.maven.plugins maven-site-plugin 3.3 org.codehaus.mojo exec-maven-plugin 1.4.0 exec java -classpath ${main.class} ${arg1} ${arg2} ${edt.debug} maven-assembly-plugin 2.4 ${project.name}-${project.version} false src/main/assembly/assembly.xml make-assembly package single net.ju-n.maven.plugins checksum-maven-plugin 1.4 files verify ${project.build.directory} *.txt *.jar *.properties lib/*.jar MD5 false true org.codehaus.mojo wagon-maven-plugin 2.0.2 upload-delete deploy sshexec true eve-nikr-net ${upload.url} rm -rf ${upload.program.delete} upload-update deploy upload ${project.build.directory} *.txt,*.jar,*.md5,lib/*,*.dat,*.php,*.properties,.htaccess,*.update eve-nikr-net sftp://${upload.url} ${upload.program.file} upload-zip deploy upload ${project.build.directory} *.zip eve-nikr-net sftp://${upload.url} ${upload.zip} org.apache.maven.plugins maven-deploy-plugin 2.8.1 true org.codehaus.izpack izpack-maven-plugin 5.0.3 izpack package izpack true installer ${project.build.directory}/install ${project.build.directory}/izpack/install.xml org.apache.maven.plugins maven-surefire-plugin 2.22.2 ${tests.to.skip} ${janice} false org.jacoco jacoco-maven-plugin 0.8.8 ${project.build.directory}/jacoco jacoco-initialize prepare-agent jacoco-report package report org.apache.maven.wagon wagon-ftp 3.5.2 org.apache.maven.wagon wagon-ssh 3.5.2 src/main/resources false tools/izpack false **/install.xml ../install/izpack tools/izpack true **/install.xml ../izpack tools/update true **/github.update **/update_version.dat .. org.apache.maven.plugins maven-javadoc-plugin 2.8.1 true false org.apache.maven.plugins maven-jxr-plugin 2.3 org.apache.maven.plugins maven-project-info-reports-plugin 2.4 false false index dependencies dependency-convergence issue-tracking license modules plugin-management plugins project-team scm summary org.apache.maven.plugins maven-surefire-report-plugin 2.12 org.apache.maven.plugins maven-checkstyle-plugin 2.9.1 ${basedir}/checkstyle.xml checkstyle org.codehaus.mojo taglist-maven-plugin 2.4 Important Todo Work fixme ignoreCase Todo Work todo ignoreCase pending ignoreCase Workarounds and other none optimal code xxx ignoreCase org.codehaus.mojo findbugs-maven-plugin 3.0.5 true true target/site org.apache.maven.plugins maven-pmd-plugin 3.8 true ${project.build.sourceEncoding} 100 ${project.build.sourceVersion} **/*Bean.java **/generated/*.java target/generated-sources/stubs true NOTHING RUN-portable -portable RUN-debug -debug RUN-edtdebug RUN-lazysave -lazysave RUN-no-args-profiling RUN-forceupdate -debug -forceupdate RUN-noupdate -debug -noupdate RUNCLI-update -update -portable RUNCLI-export -export -portable RUNCLI-help -help skip-online-tests skip-online-tests true **/*OnlineTest.java skip-all-tests skip-all-tests true true skip-online-price-tests skip-online-price-tests true **/*PriceDataGetterOnlineTest.java jdk11 false 11 11 jdk17 false 17 17 org.codehaus.izpack izpack-maven-plugin 5.0.3 izpack none false central Maven Central https://repo.maven.apache.org/maven2/ maven.nikr.net maven.nikr.net true true https://maven.nikr.net/ jitpack.io https://jitpack.io net.troja.eve eve-esi 7.0.0 uk.me.candle pricing 3.1.2 uk.me.candle routing 2.0.0 uk.me.candle translations 3.1.1 com.glazedlists glazedlists 1.11.0 net.sf.supercsv super-csv 2.4.0 junit junit 4.13.2 test org.hamcrest hamcrest 2.2 test org.slf4j slf4j-api 2.0.16 org.slf4j log4j-over-slf4j 2.0.16 org.slf4j jcl-over-slf4j 2.0.16 org.slf4j jul-to-slf4j 2.0.16 ch.qos.logback logback-classic 1.3.15 ch.qos.logback logback-core 1.3.15 org.jfree jfreechart 1.5.3 com.github.lgooddatepicker LGoodDatePicker 11.2.1 org.xerial sqlite-jdbc 3.50.3.0 info.picocli picocli 4.6.2 javax.xml.bind jaxb-api 2.3.1 org.dom4j dom4j 2.1.3 jaxen jaxen 1.2.0 net.java.dev.jna jna-platform 5.6.0 com.formdev flatlaf 3.4.1 com.formdev flatlaf-extras 3.4.1 com.udojava EvalEx 2.7 com.github.umjammer jlayer 1.0.2 UTF-8 1.8 1.8 net.nikr.eve.jeveasset.Main -edtdebug ================================================ FILE: readme.txt ================================================ ######## ##### ######## ####### ### ### ### # ######## # # #### ######### #### #### #### ##### #### ######## # # # ######### # # # # # # ### # # #### ### ### #### #### #### # #### # ######## #### # ### ### # # # # # # ######## ## #### ### ### #### #### #### # #### # ### #### #### ## ### ## ## #### # # # # # # # # # # # #### #### #### # # # # #### # # # # # # # # # # # # #### # # ### # # #### ________________________________________________________________________________ _ABOUT__________________________________________________________________________ jEveAssets is an out-of-game asset manager for Eve-Online, written in Java ________________________________________________________________________________ _FAQ____________________________________________________________________________ Please see the online FAQ Link: https://wiki.jeveassets.org/faq ________________________________________________________________________________ _CONTACT________________________________________________________________________ www: https://eve.nikr.net/jeveasset email: niklaskr@gmail.com Eve-Online forum thread: https://forums.eveonline.com/t/13255 Discord: https://discord.gg/8kYZvbM ________________________________________________________________________________ ________________________________________________________________________________ ================================================ FILE: src/main/assembly/assembly.xml ================================================ bin / false zip ${project.build.directory} true /jEveAssets/ *.txt jeveassets.jar jmemory.jar *.properties lib/* data/* ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/CliExport.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.matchers.Matcher; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.ExportSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.filter.ExportTableData; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.filter.FilterLogicalMatcher; import net.nikr.eve.jeveasset.gui.shared.filter.SimpleTableFormat; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetsTab; import net.nikr.eve.jeveasset.gui.tabs.contracts.ContractsTab; import net.nikr.eve.jeveasset.gui.tabs.items.ItemsTab; import net.nikr.eve.jeveasset.gui.tabs.jobs.IndustryJobsTab; import net.nikr.eve.jeveasset.gui.tabs.journal.JournalTab; import net.nikr.eve.jeveasset.gui.tabs.loadout.Loadout; import net.nikr.eve.jeveasset.gui.tabs.loadout.LoadoutData; import net.nikr.eve.jeveasset.gui.tabs.loadout.LoadoutsTab; import net.nikr.eve.jeveasset.gui.tabs.materials.MaterialsData; import net.nikr.eve.jeveasset.gui.tabs.materials.MaterialsTab; import net.nikr.eve.jeveasset.gui.tabs.mining.MiningTab; import net.nikr.eve.jeveasset.gui.tabs.orders.MarketOrdersTab; import net.nikr.eve.jeveasset.gui.tabs.overview.Overview; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewData; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab.View; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTableFormat; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedData; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedTab; import net.nikr.eve.jeveasset.gui.tabs.routing.RoutingTab; import net.nikr.eve.jeveasset.gui.tabs.slots.SlotsData; import net.nikr.eve.jeveasset.gui.tabs.slots.SlotsTab; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileData; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileTab; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerTab; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTab; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeData; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTab; import net.nikr.eve.jeveasset.gui.tabs.values.IskData; import net.nikr.eve.jeveasset.gui.tabs.values.ValueTableTab; import net.nikr.eve.jeveasset.io.online.PriceDataGetter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CliExport { private static final Logger LOG = LoggerFactory.getLogger(CliExport.class); public static enum ExportTool { ASSETS("Assets", CliOptions.ASSETS, AssetsTab.NAME), CONTRACTS("Contracts", CliOptions.CONTRACTS, ContractsTab.NAME), INDUSTRY_JOBS("Industry Jobs", CliOptions.INDUSTRY_JOBS, IndustryJobsTab.NAME), SLOTS("Slots", CliOptions.SLOTS, SlotsTab.NAME), ISK("Isk", CliOptions.ISK, ValueTableTab.NAME), ITEMS("Items", CliOptions.ITEMS, ItemsTab.NAME), JOURNAL("Journal", CliOptions.JOURNAL, JournalTab.NAME), LOADOUTS("Ship Fittings", CliOptions.LOADOUTS, LoadoutsTab.NAME), MATERIALS("Materials", CliOptions.MATERIALS, MaterialsTab.NAME), MARKET_ORDERS("Market Orders", CliOptions.MARKET_ORDERS, MarketOrdersTab.NAME), MINING("Mining", CliOptions.MINING, MiningTab.NAME), OVERVIEW_PLANETS("Overview Planets", CliOptions.OVERVIEW, OverviewTab.NAME), OVERVIEW_STATIONS("Overview Stations", CliOptions.OVERVIEW, OverviewTab.NAME), OVERVIEW_SYSTEMS("Overview Systems", CliOptions.OVERVIEW, OverviewTab.NAME), OVERVIEW_CONSTELLATIONS("Overview Constellations", CliOptions.OVERVIEW, OverviewTab.NAME), OVERVIEW_REGIONS("Overview Regions", CliOptions.OVERVIEW, OverviewTab.NAME), OVERVIEW_GROUPS("Overview Groups", CliOptions.OVERVIEW, OverviewTab.NAME), REPROCESSED("Reprocessed", CliOptions.REPROCESSED, ReprocessedTab.NAME), ROUTING("Routing", CliOptions.ROUTING, RoutingTab.NAME), SKILLS("Skills", CliOptions.SKILLS, ValueTableTab.NAME), STOCKPILE("Stockpile", CliOptions.STOCKPILE, StockpileTab.NAME), TRACKER("Tracker", CliOptions.TRACKER, TrackerTab.NAME), TRANSACTIONS("Transactions", CliOptions.TRANSACTIONS, TransactionTab.NAME), TREE_LOCATION("Tree Location", CliOptions.TREE_LOCATION, TreeTab.NAME), TREE_CATEGORY("Tree Category", CliOptions.TREE_CATEGORY, TreeTab.NAME), ; private final String name; private final String exportName; private final String toolName; private ExportTool(String name, String exportName, String toolName) { this.name = name; this.exportName = exportName; this.toolName = toolName; } public String getFilename() { return name.replace(" ", "_").toLowerCase(); } public String getName() { return name; } public String getExportName() { return exportName; } public String getToolName() { return toolName; } } int export() { PriceDataGetter priceDataGetter = new PriceDataGetter(); priceDataGetter.load(); ProfileManager profileManager = new ProfileManager(); profileManager.searchProfile(); profileManager.loadActiveProfile(); ProfileData profileData = new ProfileData(profileManager); profileData.updateEventLists(); int fails = 0; for (Map.Entry> entry : CliOptions.get().getExportSettings().entrySet()) { ExportTool tool = entry.getKey(); String toolName = tool.getToolName(); boolean ok; for (ExportSettings exportSettings : entry.getValue()) { switch (tool) { case ASSETS: ok = export(profileData.getAssetsEventList(), TableFormatFactory.assetTableFormat(), toolName, exportSettings); break; case CONTRACTS: ok = export(profileData.getContractItemEventList(), TableFormatFactory.contractsTableFormat(), toolName, exportSettings); break; case INDUSTRY_JOBS: ok = export(profileData.getIndustryJobsEventList(), TableFormatFactory.industryJobTableFormat(), toolName, exportSettings); break; case SLOTS: ok = export(new SlotsData(profileManager, profileData).getData(), TableFormatFactory.slotTableFormat(), toolName, exportSettings); break; case ISK: ok = export(new IskData(profileManager, profileData).getData(), TableFormatFactory.valueTableFormat(), toolName, exportSettings); break; case ITEMS: ok = export(EventListManager.create(StaticData.get().getItems().values()), TableFormatFactory.itemTableFormat(), toolName, exportSettings); break; case JOURNAL: ok = export(profileData.getJournalEventList(), TableFormatFactory.journalTableFormat(), toolName, exportSettings); break; case LOADOUTS: ok = exportLoadout(profileManager, profileData, exportSettings, toolName); break; case MARKET_ORDERS: ok = export(profileData.getMarketOrdersEventList(), TableFormatFactory.marketTableFormat(), toolName, exportSettings); break; case MATERIALS: ok = export(new MaterialsData(profileManager, profileData).getData(CliOptions.get().getMaterialsOwner(), CliOptions.get().isMaterialsOre(), CliOptions.get().isMaterialsPI(), CliOptions.get().isMaterialsCommodity()), TableFormatFactory.materialTableFormat(), toolName, exportSettings); break; case MINING: ok = export(profileData.getMiningEventList(), TableFormatFactory.miningTableFormat(), toolName, exportSettings); break; case OVERVIEW_STATIONS: ok = exportOverview(profileManager, profileData, exportSettings, toolName, View.STATIONS); break; case OVERVIEW_PLANETS: ok = exportOverview(profileManager, profileData, exportSettings, toolName, View.PLANETS); break; case OVERVIEW_SYSTEMS: ok = exportOverview(profileManager, profileData, exportSettings, toolName, View.SYSTEMS); break; case OVERVIEW_CONSTELLATIONS: ok = exportOverview(profileManager, profileData, exportSettings, toolName, View.CONSTELLATIONS); break; case OVERVIEW_REGIONS: ok = exportOverview(profileManager, profileData, exportSettings, toolName, View.REGIONS); break; case OVERVIEW_GROUPS: ok = exportOverview(profileManager, profileData, exportSettings, toolName, View.GROUPS); break; case REPROCESSED: ok = exportReprocessed(profileManager, profileData, exportSettings, toolName); break; case ROUTING: //ToDo: Not a table tool ok = false; break; case SKILLS: ok = export(profileData.getSkillsEventList(), TableFormatFactory.skillsTableFormat(), toolName, exportSettings); break; case STOCKPILE: ok = export(new StockpileData(profileManager, profileData).getData(), TableFormatFactory.stockpileTableFormat(), toolName, exportSettings); break; case TRACKER: //ToDo: Not a table tool ok = false; break; case TRANSACTIONS: ok = export(profileData.getTransactionsEventList(), TableFormatFactory.transactionTableFormat(), toolName, exportSettings); break; case TREE_LOCATION: ok = export(new TreeData(profileManager, profileData).getDataLocations(), TableFormatFactory.treeTableFormat(), toolName, exportSettings); break; case TREE_CATEGORY: ok = export(new TreeData(profileManager, profileData).getDataCategories(), TableFormatFactory.treeTableFormat(), toolName, exportSettings); break; default: ok = false; } if (!ok) { LOG.error(tool.getName() + " export failed"); fails++; } else { LOG.info(tool.getName() + " data exported"); } } } StringBuilder builder = new StringBuilder(); if (CliOptions.get().getExportSettings().size() == fails) { builder.append("Failed to export data"); } else { builder.append("Data exported"); if (fails == 0) { builder.append(" successfully"); } else { builder.append(" with "); builder.append(fails); builder.append(" error"); if (fails > 1) { builder.append("s"); } } builder.append(" to "); builder.append(CliOptions.get().getOutputDirectory()); } if (fails == 0) { LOG.info(builder.toString()); } else { LOG.warn(builder.toString()); } return -fails; //Return negative exit code } private boolean exportLoadout(ProfileManager profileManager, ProfileData profileData, ExportSettings exportSettings, String toolName) { Set loadoutsNames = CliOptions.get().getLoadoutsNames(); Set loadoutsIDs = CliOptions.get().getLoadoutsIDs(); EventList eventList = new LoadoutData(profileManager, profileData).getData(); if ((loadoutsNames != null && !loadoutsNames.isEmpty()) || (loadoutsIDs != null && !loadoutsIDs.isEmpty())) { FilterList filterList = new FilterList<>(eventList, new LoadoutMatcher(loadoutsNames, loadoutsIDs)); return export(filterList, TableFormatFactory.loadoutTableFormat(), toolName, exportSettings); } else { return export(eventList, TableFormatFactory.loadoutTableFormat(), toolName, exportSettings); } } private boolean exportReprocessed(ProfileManager profileManager, ProfileData profileData, ExportSettings exportSettings, String toolName) { Map items = new HashMap<>(); Set typeIDs = CliOptions.get().getReprocessedIDs(); if (typeIDs != null) { //IDs to Items for (Integer typeID : typeIDs) { Item item = StaticData.get().getItems().get(typeID); if (item != null) { items.put(item, 1L); } } } Set typeNames = CliOptions.get().getReprocessedNames(); if (typeNames != null && !typeNames.isEmpty()) { if (typeNames.size() > 1) { //Build {name, item} Cache Map itemsNyName = new TreeMap<>(StringComparators.CASE_INSENSITIVE); for (Item item : StaticData.get().getItems().values()) { itemsNyName.put(item.getTypeName(), item); } //Names to Items for (String typeName : typeNames) { Item item = itemsNyName.get(typeName); if (item != null) { items.put(item, 1L); } } } else { String typeName = typeNames.iterator().next(); for (Item item : StaticData.get().getItems().values()) { if (typeName.equalsIgnoreCase(item.getTypeName())) { items.put(item, 1L); break; } } } } return export(new ReprocessedData(profileManager, profileData).getData(items), TableFormatFactory.reprocessedTableFormat(), toolName, exportSettings); } private boolean exportOverview(ProfileManager profileManager, ProfileData profileData, ExportSettings exportSettings, String toolName, View view) { String owner = ""; //ToDo: Owner is not settable (yet?) String filterName = exportSettings.getFilterName(); //Assets Filter List filter; if (filterName == null) { filter = new ArrayList<>(); } else if (filterName.isEmpty()) { filter = Settings.get().getCurrentTableFilters(ExportTool.ASSETS.getToolName()); } else { filter = Settings.get().getTableFilters(ExportTool.ASSETS.getToolName()).get(filterName); if (filter == null) { LOG.error(toolName + ": No such saved filter (" + filterName + ")"); return false; } } //Assets Filtered FilterList filterList = new FilterList<>(profileData.getAssetsEventList(), new FilterLogicalMatcher<>(TableFormatFactory.assetTableFormat(), null, filter)); //Overview EnumTableFormatAdaptor tableFormat = TableFormatFactory.overviewTableFormat(); OverviewTab.updateShownColumns(tableFormat, view); return ExportTableData.exportEmpty(new OverviewData(profileManager, profileData).getData(filterList, owner, view), tableFormat, toolName, exportSettings); } private & EnumTableColumn, Q> boolean export(EventList data, final SimpleTableFormat tableFormat, String toolName, ExportSettings exportSettings) { return ExportTableData.exportAutoNoCache(data, tableFormat, toolName, exportSettings); } private static class LoadoutMatcher implements Matcher { private final Set loadoutsNames = new TreeSet<>(StringComparators.CASE_INSENSITIVE); private final Set loadoutsIDs; public LoadoutMatcher(Set loadoutsNames, Set loadoutsIDs) { if (loadoutsNames != null) { this.loadoutsNames.addAll(loadoutsNames); } if (loadoutsIDs != null) { this.loadoutsIDs = loadoutsIDs; } else { this.loadoutsIDs = new HashSet<>(); } } @Override public boolean matches(Loadout item) { if (loadoutsNames.contains(item.getShipItemName())) { return true; } else if (loadoutsNames.contains(item.getShipTypeName())) { return true; } else if (loadoutsIDs.contains(item.getShipTypeID())) { return true; } return false; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/CliOptions.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset; import java.io.File; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import net.nikr.eve.jeveasset.CliExport.ExportTool; import net.nikr.eve.jeveasset.data.settings.ExportSettings; import net.nikr.eve.jeveasset.data.settings.ExportSettings.ColumnSelection; import net.nikr.eve.jeveasset.data.settings.ExportSettings.DecimalSeparator; import net.nikr.eve.jeveasset.data.settings.ExportSettings.ExportFormat; import net.nikr.eve.jeveasset.data.settings.ExportSettings.FilterSelection; import net.nikr.eve.jeveasset.data.settings.ExportSettings.LineDelimiter; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.io.shared.FileUtil; import picocli.CommandLine; import picocli.CommandLine.ArgGroup; import picocli.CommandLine.Command; import picocli.CommandLine.Option; import picocli.CommandLine.PicocliException; @Command(sortOptions = false, synopsisHeading = "", customSynopsis = "Usage: java [-Djava.awt.headless=true] -jar jeveassets.jar [-h] [-v] [-p] [-z] [-u] [-e [OPTIONS]]", description="%n -Djava.awt.headless=true Run without a GUI%n" + " Java parameter (must be specified before -jar)" ) public class CliOptions { private static final Logger LOG = Logger.getLogger(CliOptions.class.getName()); public static final String ASSETS = "assets"; public static final String CONTRACTS = "contracts"; public static final String INDUSTRY_JOBS = "industryjobs"; public static final String SLOTS = "slots"; public static final String ISK = "isk"; public static final String ITEMS = "items"; public static final String JOURNAL = "journal"; public static final String LOADOUTS = "fittings"; public static final String MATERIALS = "materials"; public static final String MARKET_ORDERS = "marketorders"; public static final String MINING = "mining"; public static final String OVERVIEW = "overview"; public static final String REPROCESSED = "reprocessed"; public static final String ROUTING = "routing"; //ToDo public static final String SKILLS = "skills"; public static final String STOCKPILE = "stockpile"; public static final String TRACKER = "tracker"; //ToDo public static final String TRANSACTIONS = "transactions"; public static final String TREE_LOCATION = "tree-location"; public static final String TREE_CATEGORY = "tree-category"; private static final String REPROCESSED_NAMES = "-"+REPROCESSED+"-names"; private static final String REPROCESSED_IDS = "-"+REPROCESSED+"-ids"; private static final String END_GROUP = "%n"; private static final String TOOLS_BEFORE = "Export "; private static final String TOOLS_AFTER = " Data"; private static final String FILTER_BEFORE = "Use saved filter for "; private static final String FILTER_AFTER = " export"; private static final String FILTER_CMD = "-filter"; private static final String FILTER_LABEL = "filter"; private static final String VIEW_BEFORE = "Use saved view for "; private static final String VIEW_AFTER = " export"; private static final String VIEW_CMD = "-view"; private static final String VIEW_LABEL = "view"; private static final CliOptions CLI_OPTIONS = new CliOptions(); public static CliOptions get() { return CLI_OPTIONS; } public static CommandLine set(final String[] args) { CommandLine cmd = new CommandLine(CLI_OPTIONS); try { cmd.parseArgs(args); } catch (PicocliException ex) { LOG.log(Level.SEVERE, ex.getMessage(), ex); System.exit(-1); } if (CLI_OPTIONS.help) { cmd.setUsageHelpWidth(110); cmd.setUsageHelpAutoWidth(true); cmd.usage(System.out); System.exit(0); } if (CLI_OPTIONS.version) { System.out.println(Program.PROGRAM_NAME + " " + Program.PROGRAM_VERSION); System.exit(0); } return cmd; } @Option(names = {"-h", "-help", "/?"}, usageHelp = true, description = "Display this help message") boolean help; @Option(names = {"-v", "-version"}, versionHelp = true, description = "Display version information") boolean version; @Option(names = {"-p", "-portable"}, description = "Run jEveAssets portable%nSave all data in the jEveAssets program directory ") boolean portable; @Option(names = {"-z", "-lazysave"}, description = "Only save to disk on update and exit%n" + " Warning:%n" + " This may cause you to lose data if jEveAssets exit unexpectedly" + END_GROUP) boolean lazySave; @ArgGroup(exclusive = false, heading = "Update Options:%n") UpdateOptions updateOptions; static class UpdateOptions { @Option(names = { "-u", "-update"}, required = true, description = "Update Data%nUpdate all profiles and accounts%nAll data with cache expired will be updated" + END_GROUP) boolean update; } @ArgGroup(exclusive = false, heading = "Export Options:%n") ExportOptions exportOptions; //-u -e -html -csv -sql //-u -e -html -csv -sql -nodate //-u -e -html -csv -sql -nodate -assets-filter "Propulsion Modules" -reprocessed-ids 12066 -reprocessed-names "100MN Afterburner II" //-e -a -html -nodate -assets-filter "Propulsion Modules" -assets-view "Simple" //-e -a -html -nodate -assets-filter -assets-view public static class ExportOptions { @Option(names = { "-e", "-export"}, required = true, description = "Export Data%n") boolean export; @Option(names = { "-f", "-output" }, paramLabel = "directory", description = "Output directory") File output; @Option(names = "-nodate", description = "Do not include date and time in the filenames") boolean noDate; @Option(names = "-noformula", description = "Do not include formula columns") boolean noFormulas; @Option(names = "-nojumps", description = "Do not include jump columns" + END_GROUP + "%nFormat Help:%nYou can select as many formats as you want") boolean noJumps; @ArgGroup(exclusive = false) ExportOptionsFormat exportOptionsFormat; @ArgGroup(exclusive = false) ExportOptionsTools tools; @ArgGroup(exclusive = false) ExportOptionsFilters filters = new ExportOptionsFilters(); @ArgGroup(exclusive = false) ExportOptionsView views = new ExportOptionsView(); } static class ExportOptionsFormat { @ArgGroup(exclusive = false) ExportOptionsCsv csv; @ArgGroup(exclusive = false) ExportOptionsHtml html; @ArgGroup(exclusive = false) ExportOptionsSql sql; } static class ExportOptionsCsv { @Option(names = "-csv", required = true, description = "Export to CSV (default)") boolean csv; @Option(names = "-comma", description = " Use comma as decimal separator and semicolon as field delimiter%n" + " Default is dot as decimal separator and comma as field delimiter") boolean comma; @ArgGroup(exclusive = true) ExportOptionsLine line; } static class ExportOptionsLine { @Option(names = "-dos", description = " Use DOS (\\r\\n) line terminator (default)") boolean dos; @Option(names = "-unix", description = " Use UNIX (\\n) line terminator") boolean unix; @Option(names = "-mac", description = " Use MAC (\\r) line terminator" + END_GROUP) boolean mac; } static class ExportOptionsHtml { @Option(names = "-html", required = true, description = "Export to HTML") boolean html; @Option(names = "-nostyle", description = " Do not style the HTML" ) boolean noStyle; @Option(names = "-igb", description = " Add in-game browser links") boolean igb; @Option(names = "-header", arity = "1", paramLabel = "row", description = " Header every X row" + END_GROUP) int headers = 0; } static class ExportOptionsSql { @Option(names = "-sql", required = true, description = "Export to SQL") boolean sql; @Option(names = "-droptable", description = " Drop Table (if exist)") boolean dropTable; @Option(names = "-createtable", description = " Create Table (if not exist)") boolean createTable; @Option(names = "-extended", description = " Extended Inserts" + END_GROUP +"%nTools Help:%nOmit all the tool parameters to export all tools") boolean extendedInserts; } static class ExportOptionsTools { /** * Free letters: b w */ @Option(names = {"-a" ,"-"+ASSETS}, description = TOOLS_BEFORE+"Assets"+TOOLS_AFTER) boolean assets; @Option(names = {"-c" ,"-"+CONTRACTS}, description = TOOLS_BEFORE+"Contracts"+TOOLS_AFTER) boolean contracts; @Option(names = {"-i" ,"-"+INDUSTRY_JOBS}, description = TOOLS_BEFORE+"Industry Jobs"+TOOLS_AFTER) boolean industryJobs; @Option(names = {"-n" ,"-"+SLOTS}, description = TOOLS_BEFORE+"Slots"+TOOLS_AFTER) boolean slots; @Option(names = {"-k" ,"-"+ISK}, description = TOOLS_BEFORE+"Isk"+TOOLS_AFTER) boolean isk; @Option(names = {"-x" ,"-"+ITEMS}, description = TOOLS_BEFORE+"Items"+TOOLS_AFTER) boolean items; @Option(names = {"-j" ,"-"+JOURNAL}, description = TOOLS_BEFORE+"Journal"+TOOLS_AFTER) boolean journal; @Option(names = {"-y" ,"-"+LOADOUTS}, description = TOOLS_BEFORE+"Ship Fittings"+TOOLS_AFTER) boolean loadouts; @Option(names = {"-m" ,"-"+MATERIALS}, description = TOOLS_BEFORE+"Materials"+TOOLS_AFTER) boolean materials; @Option(names = {"-o" ,"-"+MARKET_ORDERS}, description = TOOLS_BEFORE+"Market Orders"+TOOLS_AFTER) boolean marketOrders; @Option(names = {"-d" ,"-"+MINING}, description = TOOLS_BEFORE+"Mining"+TOOLS_AFTER) boolean mining; @Option(names = {"-q" ,"-"+SKILLS}, description = TOOLS_BEFORE+"Skills"+TOOLS_AFTER) boolean skills; @Option(names = {"-s" ,"-"+STOCKPILE}, description = TOOLS_BEFORE+"Stockpile"+TOOLS_AFTER) boolean stockpile; @Option(names = {"-t" ,"-"+TRANSACTIONS}, description = TOOLS_BEFORE+"Transaction"+TOOLS_AFTER) boolean transaction; @Option(names = {"-g" ,"-"+TREE_CATEGORY}, description = TOOLS_BEFORE+"Tree Category"+TOOLS_AFTER) boolean treeCategory; @Option(names = {"-l" ,"-"+TREE_LOCATION}, description = TOOLS_BEFORE+"Tree Location"+TOOLS_AFTER) boolean treeLocation; @Option(names = {"-vs", "-"+OVERVIEW+"-stations"}, description = TOOLS_BEFORE+"Overview Stations"+TOOLS_AFTER) boolean overviewStations; @Option(names = {"-vp", "-"+OVERVIEW+"-planets"}, description = TOOLS_BEFORE+"Overview Planets"+TOOLS_AFTER) boolean overviewPlanets; @Option(names = {"-vy", "-"+OVERVIEW+"-systems"}, description = TOOLS_BEFORE+"Overview Systems"+TOOLS_AFTER) boolean overviewSystems; @Option(names = {"-vc", "-"+OVERVIEW+"-constellations"}, description = TOOLS_BEFORE+"Overview Constellations"+TOOLS_AFTER) boolean overviewConstellations; @Option(names = {"-vr", "-"+OVERVIEW+"-regions"}, description = TOOLS_BEFORE+"Overview Regions"+TOOLS_AFTER) boolean overviewRegions; @Option(names = {"-vg", "-"+OVERVIEW+"-groups"}, description = TOOLS_BEFORE+"Overview Groups"+TOOLS_AFTER) boolean overviewGroups; @Option(names = {"-rn",REPROCESSED_NAMES}, arity = "1..", split = ",", paramLabel = "typeName", description = TOOLS_BEFORE+"Reprocessed"+TOOLS_AFTER+" for typeName(s)") Set reprocessedNames; @Option(names = {"-ri",REPROCESSED_IDS}, arity = "1..", split = ",", paramLabel = "typeID", description = TOOLS_BEFORE+"Reprocessed"+TOOLS_AFTER+" for typeID(s)" + END_GROUP + END_GROUP + "%nFilters Help:%nOmit the parameter value to use the current filter%nOmit the parameter to use no filter") Set reprocessedIDs; } static class ExportOptionsFilters { @Option(names = "-"+ASSETS+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Assets"+FILTER_AFTER) String assetsFilter; @Option(names = "-"+CONTRACTS+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Contracts"+FILTER_AFTER) String contractsFilter; @Option(names = "-"+INDUSTRY_JOBS+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Industry Jobs"+FILTER_AFTER) String industryJobsFilter; @Option(names = "-"+SLOTS+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Slots"+FILTER_AFTER) String slotsFilter; @Option(names = "-"+ISK+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Isk"+FILTER_AFTER) String iskFilter; @Option(names = "-"+ITEMS+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Items"+FILTER_AFTER) String itemsFilter; @Option(names = "-"+JOURNAL+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Journal"+FILTER_AFTER) String journalFilter; @Option(names = "-"+LOADOUTS+"-names", arity = "1..", split = ",", paramLabel = "typeName|itemName", description = "Export Ship Fittings matching ships typeName or itemName") Set loadoutsNames; @Option(names = "-"+LOADOUTS+"-ids", arity = "1..", split = ",", paramLabel = "typeID", description = "Export Ship Fittings matching ships typeID") Set loadoutsIDs; @Option(names = "-"+MATERIALS+"-owner", fallbackValue = "", arity = "0..1", paramLabel = "owner", description = "Materials owner name") String materialsOwner; @Option(names = "-"+MATERIALS+"-pi", fallbackValue = "", description = "Materials include PI") boolean materialsPI; @Option(names = "-"+MATERIALS+"-ore", fallbackValue = "", description = "Materials include Ore") boolean materialsOre; @Option(names = "-"+MATERIALS+"-commodity", fallbackValue = "", description = "Materials include Commodity") boolean materialsCommodity; @Option(names = "-"+MARKET_ORDERS+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Market Orders"+FILTER_AFTER) String marketOrdersFilter; @Option(names = "-"+MINING+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Mining"+FILTER_AFTER) String miningFilter; //Reprocesseddoes not support filters @Option(names = "-"+OVERVIEW+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Asset filter to use with Overview") String overviewFilter; @Option(names = "-"+SKILLS+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Skills"+FILTER_AFTER) String skillsFilter; @Option(names = "-"+STOCKPILE+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Stockpile"+FILTER_AFTER) String stockpileFilter; @Option(names = "-"+TRANSACTIONS+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Transaction"+FILTER_AFTER) String transactionFilter; @Option(names = "-"+TREE_CATEGORY+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Tree Category"+FILTER_AFTER) String treeFilterCategory; @Option(names = "-"+TREE_LOCATION+FILTER_CMD, fallbackValue = "", arity = "0..1", paramLabel = FILTER_LABEL, description = FILTER_BEFORE+"Tree Location"+FILTER_AFTER + END_GROUP + END_GROUP + "%nViews Help:%nOmit the parameter value to use the current columns%nOmit the parameter to include all columns") String treeFilterLocation; } static class ExportOptionsView { @Option(names = "-"+ASSETS+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Assets"+VIEW_AFTER) String assetsView; @Option(names = "-"+CONTRACTS+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Contracts"+VIEW_AFTER) String contractsView; @Option(names = "-"+INDUSTRY_JOBS+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Industry Jobs"+VIEW_AFTER) String industryJobsView; @Option(names = "-"+SLOTS+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Slots"+VIEW_AFTER) String slotsView; @Option(names = "-"+ISK+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Isk"+VIEW_AFTER) String iskView; @Option(names = "-"+ITEMS+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Items"+VIEW_AFTER) String itemsView; @Option(names = "-"+JOURNAL+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Journal"+VIEW_AFTER) String journalView; //Loadouts does not support views @Option(names = "-"+MATERIALS+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Materials"+VIEW_AFTER) String materialsView; @Option(names = "-"+MARKET_ORDERS+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Market Orders"+VIEW_AFTER) String marketOrdersView; @Option(names = "-"+MINING+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Mining"+VIEW_AFTER) String miningView; @Option(names = "-"+REPROCESSED+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Reprocessed"+VIEW_AFTER) String reprocessedView; //Overview does not support views @Option(names = "-"+SKILLS+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Skills"+VIEW_AFTER) String skillsView; @Option(names = "-"+STOCKPILE+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Stockpile"+VIEW_AFTER) String stockpileView; @Option(names = "-"+TRANSACTIONS+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Transaction"+VIEW_AFTER) String transactionView; @Option(names = "-"+TREE_CATEGORY+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Tree Category"+VIEW_AFTER) String treeViewCategory; @Option(names = "-"+TREE_LOCATION+VIEW_CMD, fallbackValue = "", arity = "0..1", paramLabel = VIEW_LABEL, description = VIEW_BEFORE+"Tree Location"+VIEW_AFTER + END_GROUP + END_GROUP) String treeViewLocation; } @ArgGroup(exclusive = false, heading = "Development Options (use at your own risk):%n") DevOptions devOptions; static class DevOptions { @Option(names = { "-debug" }, description = "Dev Command: Enable debug logging and other debug shenanigans") boolean debug; @Option(names = { "-edtdebug" }, description = "Dev Command: Detect painting outside EDT") boolean edtdebug; @Option(names = { "-noupdate" }, description = "Dev Command: Disable all updates") boolean forceNoUpdate; @Option(names = { "-forceupdate" }, description = "Dev Command: Ignore update times%n" + " Warning:%n" + " Using -forceupdate may get you banned from ESI%n" + " It does not give you access to any new data%n" + " You will just get a cached result and a lot of bad karma… ") boolean forceUpdate; @Option(names = { "-jmemory" }, description = "Dev Command: Notify jEveAssets It's being run with jmemory.jar") boolean jMemory; } private Map> settings = null; public Map> getExportSettings() { if (settings == null) { settings = new HashMap<>(); if (exportOptions == null) { return settings; } ExportOptionsTools tools = exportOptions.tools; ExportOptionsFilters filters = exportOptions.filters; ExportOptionsView views = exportOptions.views; if (tools == null || tools.assets) createExportSettings(ExportTool.ASSETS, filters.assetsFilter, views.assetsView); if (tools == null || tools.contracts) createExportSettings(ExportTool.CONTRACTS, filters.contractsFilter, views.contractsView); if (tools == null || tools.industryJobs) createExportSettings(ExportTool.INDUSTRY_JOBS, filters.industryJobsFilter, views.industryJobsView); if (tools == null || tools.slots) createExportSettings(ExportTool.SLOTS, filters.slotsFilter, views.slotsView); if (tools == null || tools.isk) createExportSettings(ExportTool.ISK, filters.iskFilter, views.iskView); if (tools == null || tools.items) createExportSettings(ExportTool.ITEMS, filters.itemsFilter, views.itemsView); if (tools == null || tools.journal) createExportSettings(ExportTool.JOURNAL, filters.journalFilter, views.journalView); if (tools == null || tools.loadouts) createExportSettings(ExportTool.LOADOUTS, null, null); if (tools == null || tools.materials) createExportSettings(ExportTool.MATERIALS, filters.materialsOwner, views.materialsView); if (tools == null || tools.marketOrders) createExportSettings(ExportTool.MARKET_ORDERS, filters.marketOrdersFilter, views.marketOrdersView); if (tools == null || tools.mining) createExportSettings(ExportTool.MINING, filters.miningFilter, views.miningView); if (tools != null && (tools.reprocessedIDs != null || tools.reprocessedNames != null)) createExportSettings(ExportTool.REPROCESSED, null, views.reprocessedView); if (tools == null || tools.overviewStations) createExportSettings(ExportTool.OVERVIEW_STATIONS, filters.overviewFilter, null); if (tools == null || tools.overviewPlanets) createExportSettings(ExportTool.OVERVIEW_PLANETS, filters.overviewFilter, null); if (tools == null || tools.overviewSystems) createExportSettings(ExportTool.OVERVIEW_SYSTEMS, filters.overviewFilter, null); if (tools == null || tools.overviewConstellations) createExportSettings(ExportTool.OVERVIEW_CONSTELLATIONS, filters.overviewFilter, null); if (tools == null || tools.overviewRegions) createExportSettings(ExportTool.OVERVIEW_REGIONS, filters.overviewFilter, null); if (tools == null || tools.overviewGroups) createExportSettings(ExportTool.OVERVIEW_GROUPS, filters.overviewFilter, null); if (tools == null || tools.skills) createExportSettings(ExportTool.SKILLS, filters.skillsFilter, views.skillsView); if (tools == null || tools.stockpile) createExportSettings(ExportTool.STOCKPILE, filters.stockpileFilter, views.stockpileView); if (tools == null || tools.transaction) createExportSettings(ExportTool.TRANSACTIONS, filters.transactionFilter, views.transactionView); if (tools == null || tools.treeLocation) createExportSettings(ExportTool.TREE_LOCATION, filters.treeFilterLocation, views.treeViewLocation); if (tools == null || tools.treeCategory) createExportSettings(ExportTool.TREE_CATEGORY, filters.treeFilterCategory, views.treeViewCategory); } return settings; } private void createExportSettings(ExportTool exportTool, String filterName, String viewName) { ExportOptionsFormat exportOptionsFormat = exportOptions.exportOptionsFormat; if (exportOptionsFormat != null) { //CSV if (exportOptionsFormat.csv != null && exportOptionsFormat.csv.csv) { ExportSettings exportSettings = new ExportSettings(exportTool.getToolName()); if (exportOptionsFormat.csv.comma) { exportSettings.setDecimalSeparator(DecimalSeparator.COMMA); } if (exportOptionsFormat.csv.line != null) { if (exportOptionsFormat.csv.line.unix) { exportSettings.setCsvLineDelimiter(LineDelimiter.UNIX); } else if (exportOptionsFormat.csv.line.mac) { exportSettings.setCsvLineDelimiter(LineDelimiter.MAC); } } set(exportSettings, exportTool, ExportFormat.CSV, filterName, viewName); } //HTML if (exportOptionsFormat.html != null && exportOptionsFormat.html.html) { ExportSettings exportSettings = new ExportSettings(exportTool.getToolName()); exportSettings.setHtmlRepeatHeader(exportOptionsFormat.html.headers); exportSettings.setHtmlIGB(exportOptionsFormat.html.igb); exportSettings.setHtmlStyled(!exportOptionsFormat.html.noStyle); set(exportSettings, exportTool, ExportFormat.HTML, filterName, viewName); } //SQL if (exportOptionsFormat.sql != null && exportOptionsFormat.sql.sql) { ExportSettings exportSettings = new ExportSettings(exportTool.getToolName()); exportSettings.setSqlDropTable(exportOptionsFormat.sql.dropTable); exportSettings.setSqlCreateTable(exportOptionsFormat.sql.createTable); exportSettings.setSqlExtendedInserts(exportOptionsFormat.sql.extendedInserts); exportSettings.setSqlTableName(Settings.get().getExportSettings(exportTool.getToolName()).getSqlTableName()); set(exportSettings, exportTool, ExportFormat.SQL, filterName, viewName); } } else { //Default CSV set(new ExportSettings(exportTool.getToolName()), exportTool, ExportFormat.CSV, filterName, viewName); } } private void set(ExportSettings exportSettings, ExportTool exportTool, ExportFormat exportFormat, String filterName, String viewName) { StringBuilder builder = new StringBuilder(); builder.append(getOutputDirectory()); builder.append(File.separator); if (!exportOptions.noDate) { builder.append(Formatter.fileDate(new Date())); builder.append("_"); } builder.append(exportTool.getFilename()); builder.append("_export."); builder.append(exportFormat.getExtension()); exportSettings.setFilename(builder.toString()); //Format exportSettings.setExportFormat(exportFormat); //Filter if (filterName == null) { exportSettings.setFilterName(""); exportSettings.setFilterSelection(FilterSelection.NONE); } else if (filterName.isEmpty()) { exportSettings.setFilterName(""); exportSettings.setFilterSelection(FilterSelection.CURRENT); } else { exportSettings.setFilterName(filterName); exportSettings.setFilterSelection(FilterSelection.SAVED); } //Formula Columns exportSettings.setFormulas(!exportOptions.noFormulas); //Jump Columns exportSettings.setJumps(!exportOptions.noJumps); //Columns if (viewName == null) { //All columns exportSettings.setColumnSelection(ColumnSelection.SELECTED); exportSettings.putTableExportColumns(null); //null = all exportSettings.setViewName(null); } else if (viewName.isEmpty()) { //Current shown columns in order exportSettings.setColumnSelection(ColumnSelection.SHOWN); exportSettings.setViewName(null); } else { //Saved View exportSettings.setColumnSelection(ColumnSelection.SAVED); exportSettings.setViewName(viewName); } //Add List list = settings.get(exportTool); if (list == null) { list = new ArrayList<>(); settings.put(exportTool, list); } list.add(exportSettings); } public String getMaterialsOwner() { if (exportOptions == null || exportOptions.filters == null || exportOptions.filters.materialsOwner == null || exportOptions.filters.materialsOwner.isEmpty()) { return null; } return exportOptions.filters.materialsOwner; } public boolean isMaterialsPI() { if (exportOptions == null || exportOptions.filters == null) { return false; } return exportOptions.filters.materialsPI; } public boolean isMaterialsOre() { if (exportOptions == null || exportOptions.filters == null) { return false; } return exportOptions.filters.materialsOre; } public boolean isMaterialsCommodity() { if (exportOptions == null || exportOptions.filters == null) { return false; } return exportOptions.filters.materialsCommodity; } public Set getReprocessedNames() { if (exportOptions == null || exportOptions.tools == null || exportOptions.tools.reprocessedNames == null || exportOptions.tools.reprocessedNames.isEmpty()) { return null; } return exportOptions.tools.reprocessedNames; } public Set getReprocessedIDs() { if (exportOptions == null || exportOptions.tools == null || exportOptions.tools.reprocessedIDs == null || exportOptions.tools.reprocessedIDs.isEmpty()) { return null; } return exportOptions.tools.reprocessedIDs; } public Set getLoadoutsNames() { if (exportOptions == null || exportOptions.filters == null || exportOptions.filters.loadoutsNames == null || exportOptions.filters.loadoutsNames.isEmpty()) { return null; } return exportOptions.filters.loadoutsNames; } public Set getLoadoutsIDs() { if (exportOptions == null || exportOptions.filters == null || exportOptions.filters.loadoutsIDs == null || exportOptions.filters.loadoutsIDs.isEmpty()) { return null; } return exportOptions.filters.loadoutsIDs; } public File getOutputDirectory() { //Output if (exportOptions.output == null) { exportOptions.output = new File(FileUtil.getPathExports()); } return exportOptions.output; } public boolean isPortable() { return portable; } public boolean isLazySave() { return lazySave; } public boolean isDebug() { if (devOptions == null) { return false; } return devOptions.debug; } public boolean isEDTdebug() { if (devOptions == null) { return false; } return devOptions.edtdebug; } public boolean isForceNoUpdate() { if (devOptions == null) { return false; } return devOptions.debug && devOptions.forceNoUpdate; } public boolean isForceUpdate() { if (devOptions == null) { return false; } return devOptions.debug && devOptions.forceUpdate; } public boolean isUpdate() { if (updateOptions == null) { return false; } return updateOptions.update; } public boolean isCLI() { return isUpdate() || isExport(); } public boolean isExport() { if (exportOptions == null) { return false; } return exportOptions.export; } public boolean isJmemory() { if (devOptions == null) { return false; } return devOptions.jMemory; } public void setPortable(boolean portable) { this.portable = portable; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/CliUpdate.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Date; import java.util.List; import net.nikr.eve.jeveasset.data.profile.Profile; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.TrackerData; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateDialog.PriceDataTask; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateDialog.Step1Task; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateDialog.Step2Task; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateDialog.Step3Task; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateDialog.Step4Task; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.gui.tabs.values.AssetValue; import net.nikr.eve.jeveasset.gui.tabs.values.DataSetCreator; import net.nikr.eve.jeveasset.io.online.PriceDataGetter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CliUpdate { private static final Logger LOG = LoggerFactory.getLogger(CliUpdate.class); int update() { PriceDataGetter priceDataGetter = new PriceDataGetter(); priceDataGetter.load(); ProfileManager profileManager = new ProfileManager(); profileManager.searchProfile(); SplashUpdater.setText("Updating DATA"); SplashUpdater.setProgress(0); int count = 0; Date date = Settings.getNow(); boolean ok = true; for (Profile profile : profileManager.getProfiles()) { profileManager.setActiveProfile(profile); if (!profile.load()) { LOG.warn("Failed to load profile"); count++; SplashUpdater.setProgress( (int)(count * 100.0 / profileManager.getProfiles().size())); continue; //Error loading profile } ProfileData profileData = new ProfileData(profileManager); profileData.updateEventLists(); List updateTasks = new ArrayList<>(); updateTasks.add(new Step1Task(profileManager)); updateTasks.add(new Step2Task(profileManager, true, true, true, true, true, true, true, true, true, true, true, true)); updateTasks.add(new Step3Task(profileManager, true)); updateTasks.add(new Step4Task(profileManager)); updateTasks.add(new PriceDataTask(priceDataGetter, profileData, false)); for (UpdateTask updateTask : updateTasks) { updateTask.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { SplashUpdater.setSubProgress(updateTask.getProgress()); } }); SplashUpdater.setSubProgress(0); updateTask.update(); if (updateTask.hasError()) { ok = false; } } //Update tracker locations AssetValue.updateData(); //Update eventlists profileData.updateEventLists(); //Create value tracker point DataSetCreator.createTrackerDataPoint(profileData, date); TrackerData.save("Added", true); //Save settings Settings.saveSettings(); //Save profile profile.save(); //Clean up profile.clear(); //Progress count++; SplashUpdater.setProgress( (int)(count * 100.0 / profileManager.getProfiles().size())); } if (ok) { LOG.info("Data updated successfully"); return 0; } else { LOG.info("Data updated with errors"); return -1; //on error } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/DetectEdtViolationRepaintManager.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset; import javax.swing.JComponent; import javax.swing.RepaintManager; import javax.swing.SwingUtilities; import org.slf4j.LoggerFactory; public class DetectEdtViolationRepaintManager extends RepaintManager { private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(Program.class); /** * Used to ensure we only print a stack trace once per abusing thread. May * be null if the option is disabled. */ private ThreadLocal alreadyWarnedLocal; /** * Installs a new instance of DetectEdtViolationRepaintManager which does * not warn repeatedly, as the current repaint manager. */ public static void install() { install(false); } /** * Installs a new instance of DetectEdtViolationRepaintManager as the * current repaint manager. * * @param warnRepeatedly whether multiple warnings should be logged for each * violating thread */ public static void install(boolean warnRepeatedly) { RepaintManager.setCurrentManager(new DetectEdtViolationRepaintManager(warnRepeatedly)); LOG.info("Installed new DetectEdtViolationRepaintManager"); } /** * Creates a new instance of DetectEdtViolationRepaintManager. * * @param warnRepeatedly whether multiple warnings should be logged for each * violating thread */ private DetectEdtViolationRepaintManager(boolean warnRepeatedly) { if (!warnRepeatedly) { this.alreadyWarnedLocal = new ThreadLocal(); } } /** * {@inheritDoc} */ @Override public synchronized void addInvalidComponent(JComponent component) { checkThreadViolations(); super.addInvalidComponent(component); } /** * {@inheritDoc} */ @Override public synchronized void addDirtyRegion(JComponent component, int x, int y, int w, int h) { checkThreadViolations(); super.addDirtyRegion(component, x, y, w, h); } /** * Checks if the calling thread is called in the event dispatch thread. If * not an exception will be printed to the console. */ private void checkThreadViolations() { if (alreadyWarnedLocal != null && Boolean.TRUE.equals(alreadyWarnedLocal.get())) { return; } if (!SwingUtilities.isEventDispatchThread()) { if (alreadyWarnedLocal != null) { alreadyWarnedLocal.set(Boolean.TRUE); } LOG.warn("painting on non-EDT thread", new Exception()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/LibraryManager.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset; import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.io.online.Updater; import net.nikr.eve.jeveasset.io.shared.FileUtilSimple; public class LibraryManager { private static Set files = null; public static void checkLibraries() { checkMissing(); purge(); } private static void purge() { File lib = new File(FileUtilSimple.getPathLib()); List delete = new ArrayList<>(); int libsFiles = 0; for (File file : lib.listFiles()) { if (getLibFiles().contains(file.getName())) { libsFiles++; continue; } if (!getLibFiles().contains(file.getName()) && file.getName().endsWith(".jar") && !file.isDirectory()) { delete.add(file); } } if (libsFiles != getLibFiles().size()) { return; //Wrong directory? } for (File file : delete) { file.delete(); } } private static void checkMissing() { File jar = new File(FileUtilSimple.getPathRunJar()); boolean temp = false; //Check if trying to run from inside zip file (Windows only) if (jar.getAbsolutePath().contains(".zip") && jar.getAbsolutePath().contains(System.getProperty("java.io.tmpdir")) && System.getProperty("os.name").startsWith("Windows")) { temp = true; } boolean missing = false; //Check if all libraries are pressent for (String filename : getLibFiles()) { File file = new File(FileUtilSimple.getPathLib(filename)); if (!file.exists()) { missing = true; break; } } if (temp && missing) { //Running from zip file... JOptionPane.showMessageDialog(Main.getTop(), "You need to unzip jEveAssets to run it\r\nIt will not work from inside the zip file", Program.PROGRAM_NAME + " - Critical Error", JOptionPane.ERROR_MESSAGE); System.exit(-1); } else if (missing) { //Missing libraries Updater updater = new Updater(); updater.fixLibs(); } } public static synchronized Set getLibFiles() { if (files == null) { //Lazy init files = new HashSet<>(); files.add("asm-9.2.jar"); files.add("dom4j-2.1.3.jar"); files.add("glazedlists-1.11.0.jar"); files.add("graph-2.0.0.jar"); files.add("guava-r09.jar"); files.add("jaxen-1.2.0.jar"); files.add("javax.activation-api-1.2.0.jar"); files.add("guava-r09.jar"); files.add("LGoodDatePicker-11.2.1.jar"); files.add("jfreechart-1.5.3.jar"); files.add("pricing-3.1.2.jar"); files.add("routing-2.0.0.jar"); files.add("super-csv-2.4.0.jar"); files.add("translations-3.1.1.jar"); files.add("annotations-13.0.jar"); files.add("hamcrest-core-1.3.jar"); files.add("hamcrest-core-1.3.jar"); files.add("jaxb-api-2.3.1.jar"); files.add("sqlite-jdbc-3.50.3.0.jar"); files.add("jna-platform-5.6.0.jar"); files.add("jna-5.6.0.jar"); files.add("jsr305-3.0.2.jar"); files.add("flatlaf-3.4.1.jar"); files.add("EvalEx-2.7.jar"); files.add("picocli-4.6.2.jar"); //Logging files.add("slf4j-api-2.0.16.jar"); files.add("jul-to-slf4j-2.0.16.jar"); files.add("jcl-over-slf4j-2.0.16.jar"); files.add("logback-core-1.3.15.jar"); files.add("log4j-over-slf4j-2.0.16.jar"); files.add("logback-classic-1.3.15.jar"); //Native Mac GUI integration files.add("jsvg-1.4.0.jar"); files.add("flatlaf-extras-3.4.1.jar"); //MP3 files.add("jlayer-1.0.2.jar"); //Eve-ESI files.add("eve-esi-7.0.0.jar"); files.add("logging-interceptor-5.1.0.jar"); files.add("okio-jvm-3.15.0.jar"); files.add("kotlin-stdlib-2.2.0.jar"); files.add("okio-3.15.0.jar"); files.add("okhttp-5.1.0.jar"); files.add("okhttp-jvm-5.1.0.jar"); files.add("gson-2.9.0.jar"); files.add("jackson-core-2.14.0-rc2.jar"); files.add("org.apache.oltu.oauth2.common-1.0.2.jar"); files.add("jackson-databind-nullable-0.2.6.jar"); files.add("jackson-annotations-2.14.0-rc2.jar"); files.add("json-20140107.jar"); files.add("commons-codec-1.9.jar"); files.add("org.apache.oltu.oauth2.client-1.0.2.jar"); files.add("jackson-databind-2.14.0-rc2.jar"); files.add("gson-fire-1.9.0.jar"); files.add("commons-lang3-3.18.0.jar"); } return files; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/Main.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset; import java.awt.GraphicsEnvironment; import java.io.File; import java.net.URISyntaxException; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JDialog; import net.nikr.eve.jeveasset.io.local.FileLock; import net.nikr.eve.jeveasset.io.online.Updater; import org.slf4j.bridge.SLF4JBridgeHandler; public final class Main { private static JDialog top; private static Logger log; public static JDialog getTop() { if (top == null) { top = new JDialog(); top.setAlwaysOnTop(true); } return top; } /** * Entry point for jEveAssets. * * @param args the command line arguments */ public static void main(final String[] args) { boolean portable = false; boolean debug = false; for (String arg : args) { if (arg.toLowerCase().equals("-debug")) { debug = true; } if (arg.toLowerCase().equals("-portable")) { portable = true; } } //Force UTF-8 File system System.setProperty("sun.jnu.encoding", "UTF-8"); System.setProperty("file.encoding", "UTF-8"); setLogLocation(portable); // ditto here. if (System.getProperty("log.level") == null) { if (debug) { System.setProperty("log.level", "DEBUG"); } else { System.setProperty("log.level", "INFO"); } } //Set format System.setProperty("java.util.logging.SimpleFormatter.format", "%4$s: %2$s - %5$s%n"); try { SLF4JBridgeHandler.install(); } catch (Throwable t) { //This is ignored } log = Logger.getLogger(Main.class.getName()); //Add user agent to online requests System.setProperty("http.agent", Program.PROGRAM_USER_AGENT); //XXX - Workaround for IPv6 fail (force IPv4) //eveonline.com is not IPv6 ready... System.setProperty("java.net.preferIPv4Stack", "true"); //XXX - Workaround for Java Bug System.setProperty("java.util.Arrays.useLegacyMergeSort", "true"); //XXX - Workaround: Allow basic proxy authorization System.setProperty("jdk.http.auth.tunneling.disabledSchemes", ""); System.setProperty("jdk.http.auth.proxying.disabledSchemes", ""); //XXX - Workaround: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure System.setProperty("https.protocols", "SSLv3,TLSv1,TLSv1.1,TLSv1.2"); //Mac OSX System.setProperty("apple.laf.useScreenMenuBar", "true"); System.setProperty("apple.awt.application.name", Program.PROGRAM_NAME); //Validate directory LibraryManager.checkLibraries(); //install the uncaught exception handlers NikrUncaughtExceptionHandler.install(); //Splash screen if (!GraphicsEnvironment.isHeadless()) { SplashUpdater splashUpdater = new SplashUpdater(); splashUpdater.start(); } //Arguments CliOptions.set(args); //Print program data if (CliOptions.get().isJmemory()) { log.info("jmemory ok"); } log.info("Starting " + Program.PROGRAM_NAME + " " + Program.PROGRAM_VERSION); log.log(Level.INFO, "OS: {0} {1}", new Object[]{System.getProperty("os.name"), System.getProperty("os.version")}); log.log(Level.INFO, "Java: {0} {1}", new Object[]{System.getProperty("java.vendor"), System.getProperty("java.version")}); if (Updater.isPackageManager()) { log.log(Level.INFO, "Package Manager Mode: Enabled"); log.log(Level.INFO, "Package Maintainers: {0}", Updater.getPackageMaintainers()); } //Ensure only one instance is running... SingleInstance instance = new SingleInstance(); if (instance.isSingleInstance()) { FileLock.unlockAll(); } //Command line interface if (CliOptions.get().isCLI()) { Program.init(); } int exitCode = 0; //Update if (CliOptions.get().isUpdate()) { CliUpdate update = new CliUpdate(); exitCode = update.update(); } //Export if (CliOptions.get().isExport()) { CliExport cliExport = new CliExport(); exitCode = cliExport.export(); } if (CliOptions.get().isCLI()) { System.exit(exitCode); } else { //GUI if(GraphicsEnvironment.isHeadless()) { System.err.println("ERROR: Java is running in headless mode"); System.err.println(" jEveAssets can not display a GUI in headless mode"); System.err.println(" use -help to see CLI options available in headless mode"); System.out.println("ERROR: Java is running in headless mode"); System.out.println(" jEveAssets can not display a GUI in headless mode"); System.out.println(" use -help to see CLI options available in headless mode"); System.exit(-1); } javax.swing.SwingUtilities.invokeLater(new Runnable() { @Override public void run() { //Lets go! Program program = new Program(); } }); } } public static void setLogLocation(boolean portable) { // the tests for null indicate that the property is not set // It is possible to set properties using the -Dlog.home=foo/bar // and thus we want to allow this to take priority over the // configuration options here. if (System.getProperty("log.home") == null) { if (portable) { try { //jeveassets.jar directory File file = new File(net.nikr.eve.jeveasset.Program.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParentFile(); System.setProperty("log.home", file.getAbsolutePath() + File.separator); } catch (URISyntaxException ex) { //Working directory System.setProperty("log.home", System.getProperty("user.dir") + File.separator); //Working directory } } else { //Note: We can not use Program.onMac() as that will initialize the Program LOG if (System.getProperty("os.name").toLowerCase().startsWith("mac os x")) { //Mac System.setProperty("log.home", System.getProperty("user.home") + File.separator + "Library" + File.separator + "Preferences" + File.separator + "JEveAssets" + File.separator); } else { //Windows/Linux System.setProperty("log.home", System.getProperty("user.home") + File.separator + ".jeveassets" + File.separator); } } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/NahimicDetector.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class NahimicDetector { private NahimicDetector() { } public static boolean isNahimicRunning() { try { StringBuilder builder = new StringBuilder(); String line; //Process p = Runtime.getRuntime().exec(System.getenv("windir") + File.separator + "system32" + File.separator + "tasklist.exe"); Process p = Runtime.getRuntime().exec("tasklist"); try (BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()))) { while ((line = input.readLine()) != null) { builder.append(line.toLowerCase()); } } String string = builder.toString(); return string.contains("nahimicservice") //exact || string.contains("nahimicsvc64") //exact || string.contains("nahimicsvc32") //exact /* || string.contains("nahimicsvc64run") //Other? || string.contains("nahimicsvc32run") //Other? || string.contains("nahimctask32") //Other? || string.contains("nahimic2uilauncher") //Other? || string.contains("nahimic") //Match all */ ; } catch (IOException ex) { return false; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/NikrUncaughtExceptionHandler.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset; import java.awt.Component; import java.awt.Desktop; import java.awt.GraphicsEnvironment; import java.awt.IllegalComponentStateException; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.URLEncoder; import java.util.HashSet; import java.util.Set; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.io.online.Updater; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class NikrUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { private static final Logger LOG = LoggerFactory.getLogger(NikrUncaughtExceptionHandler.class); private static final String SUBMIT = "https://eve.nikr.net/jeveassets/bugs/submit.php"; private static final String JAVA = "Java 8"; private static boolean error = false; public static void install() { System.setProperty("sun.awt.exception.handler", NikrUncaughtExceptionHandler.class.getName()); Thread.setDefaultUncaughtExceptionHandler(new NikrUncaughtExceptionHandler()); } private NikrUncaughtExceptionHandler() { } @Override public void uncaughtException(final Thread t, final Throwable e) { reportError("Thread", e); } public void handle(final Throwable t) { reportError("AWT", t); } private void reportError(String s, Throwable t) { if (!error) { error = true; LOG.error("Uncaught Exception (" + s + "): " + t.getMessage(), t); //Get root cause Set> causes = new HashSet<>(); Throwable cause = t; while (cause != null) { causes.add(cause.getClass()); cause = cause.getCause(); //Next or null } if (causes.contains(IllegalComponentStateException.class) && t.getMessage().toLowerCase().contains("component must be showing on the screen to determine its location") ) { //XXX - Workaround for Java bug: https://bugs.openjdk.java.net/browse/JDK-8179665 (Ignore error) LOG.warn("Ignoring: component must be showing on the screen to determine its location"); error = false; return; } else if (causes.contains(UnsupportedClassVersionError.class)) { //Old Java showMessageDialog(Main.getTop(), "Please update Java to the latest version.\r\n" + "The minimum supported version is " + JAVA + "\r\n" + "\r\n" + "Press OK to close jEveAssets" + "\r\n" + "\r\n" , Program.PROGRAM_NAME + " - Critical Error", JOptionPane.ERROR_MESSAGE); } else if (causes.contains(OutOfMemoryError.class)) { //Out of memory int value = showConfirmDialog(Main.getTop(), "Java has run out of memory. jEveAssets will now close\r\n" + "Do you want to browse to the wiki article explaining how to fix this?\r\n" + "\r\n" , Program.PROGRAM_NAME + " - Critical Error", JOptionPane.OK_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE); if (value == JOptionPane.OK_OPTION) { try { Desktop.getDesktop().browse(new URI("https://wiki.jeveassets.org/jmemory")); } catch (Throwable ex) { //We tried our best, nothing more to do now... } } } else if (causes.contains(NoClassDefFoundError.class) || causes.contains(ClassNotFoundException.class)) { //Corrupted class files try { Updater updater = new Updater(); updater.fixMissingClasses(); } catch (Throwable ex) { //Better safe than sorry... showMessageDialog(Main.getTop(), "Please, re-download jEveAssets and leave the unzipped directory intact\r\n" + "Press OK to close jEveAssets" , Program.PROGRAM_NAME + " - Critical Error", JOptionPane.ERROR_MESSAGE); } } else { //Bug if (isJavaBug(t)) { //Java Bug showMessageDialog(Main.getTop(), "You have encountered a bug that is most likely a java bug.\r\n" + "Updating to the latest version of java may fix this problem.\r\n" + "It's still very helpful to send the the bug report.\r\n" + "\r\n" + "Press OK to continue\r\n" + "\r\n" + "\r\n" , Program.PROGRAM_NAME + " - Critical Error", JOptionPane.ERROR_MESSAGE); } int value = showConfirmDialog(Main.getTop(), "Send bug report?\r\n" + "\r\n" + "Data send and saved:\r\n" + "-OS (name and version)\r\n" + "-Java (vendor and version)\r\n" + "-Program (name and version)\r\n" + "-Date (current)\r\n" + "-Java stack trace (bug)\r\n" + "\r\n" + "\r\n" , Program.PROGRAM_NAME + " - Critical Error", JOptionPane.OK_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE); if (value == JOptionPane.OK_OPTION) { String result = send(t); showMessageDialog(Main.getTop(), result, "Bug Report", JOptionPane.PLAIN_MESSAGE); } } System.exit(-1); } } private void showMessageDialog(Component parentComponent, Object message, String title, int messageType) { if (GraphicsEnvironment.isHeadless()) { return; } JOptionPane.showMessageDialog(parentComponent, message, title, messageType); } public static int showConfirmDialog(Component parentComponent, Object message, String title, int optionType, int messageType) { if (GraphicsEnvironment.isHeadless()) { return JOptionPane.CANCEL_OPTION; } return JOptionPane.showConfirmDialog(parentComponent, message, title, optionType, messageType); } private static boolean isJavaBug(Throwable t) { for (StackTraceElement stackTraceElement : t.getStackTrace()) { if (stackTraceElement.getClassName().startsWith("net.nikr")) { return false; } } return true; } private String send(Throwable t) { return send(getStackTrace(t)); } public static String send(String bug) { HttpURLConnection connection = null; try { String urlParameters = "os=" + URLEncoder.encode(System.getProperty("os.name") + " " + System.getProperty("os.version"), "UTF-8") + "&java=" + URLEncoder.encode(System.getProperty("java.vendor") + " " + System.getProperty("java.version"), "UTF-8") + "&version=" + URLEncoder.encode(Program.PROGRAM_NAME + " " + Program.PROGRAM_VERSION, "UTF-8") + "&log=" + URLEncoder.encode(bug, "UTF-8"); URL url = new URL(SUBMIT); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); connection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length)); connection.setRequestProperty("Content-Language", "en-US"); connection.setUseCaches(false); connection.setDoInput(true); connection.setDoOutput(true); DataOutputStream wr = new DataOutputStream(connection.getOutputStream()); wr.writeBytes(urlParameters); wr.flush(); wr.close(); InputStream is = connection.getInputStream(); BufferedReader rd = new BufferedReader(new InputStreamReader(is)); String line; StringBuilder response = new StringBuilder(); while ((line = rd.readLine()) != null) { response.append(line); response.append('\r'); } rd.close(); String bugID = response.toString(); if (!bugID.trim().equals("0") && !bugID.trim().isEmpty()) { return "Bug report send. Thank you very much!\r\n" + "\r\n" + "BugID: " + bugID; } } catch (MalformedURLException ex) { LOG.error(ex.getMessage(), ex); } catch (IOException ex) { LOG.error(ex.getMessage(), ex); } finally { if (connection != null) { connection.disconnect(); } } return "Failed to submit bug report..."; } private String getStackTrace(Throwable t) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); if (t != null) { t.printStackTrace(pw); } return sw.toString(); // stack trace as a string } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/Program.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset; import com.formdev.flatlaf.extras.FlatDesktop; import com.formdev.flatlaf.extras.FlatDesktop.QuitResponse; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Consumer; import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.text.DefaultEditorKit; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyAccountBalance; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.AddedData; import net.nikr.eve.jeveasset.data.settings.PriceHistoryDatabase; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.TempDirs; import net.nikr.eve.jeveasset.data.settings.TrackerData; import net.nikr.eve.jeveasset.data.settings.tag.TagUpdate; import net.nikr.eve.jeveasset.gui.dialogs.AboutDialog; import net.nikr.eve.jeveasset.gui.dialogs.account.AccountManagerDialog; import net.nikr.eve.jeveasset.gui.dialogs.profile.ProfileDialog; import net.nikr.eve.jeveasset.gui.dialogs.settings.SettingsDialog; import net.nikr.eve.jeveasset.gui.dialogs.settings.UserLocationSettingsPanel; import net.nikr.eve.jeveasset.gui.dialogs.settings.UserNameSettingsPanel; import net.nikr.eve.jeveasset.gui.dialogs.settings.UserPriceSettingsPanel; import net.nikr.eve.jeveasset.gui.dialogs.update.StructureUpdateDialog; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateDialog; import net.nikr.eve.jeveasset.gui.frame.MainMenu.MainMenuAction; import net.nikr.eve.jeveasset.gui.frame.MainWindow; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.UpdateType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.Updatable; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow.LockWorkerAdaptor; import net.nikr.eve.jeveasset.gui.shared.components.JMainTab; import net.nikr.eve.jeveasset.gui.shared.filter.FilterMatcher; import net.nikr.eve.jeveasset.gui.sounds.SoundPlayer; import net.nikr.eve.jeveasset.gui.tabs.agents.AgentsTab; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetsTab; import net.nikr.eve.jeveasset.gui.tabs.contracts.ContractsTab; import net.nikr.eve.jeveasset.gui.tabs.items.ItemsTab; import net.nikr.eve.jeveasset.gui.tabs.jobs.IndustryJobsTab; import net.nikr.eve.jeveasset.gui.tabs.journal.JournalTab; import net.nikr.eve.jeveasset.gui.tabs.loadout.LoadoutsTab; import net.nikr.eve.jeveasset.gui.tabs.loyalty.LoyaltyPointsTab; import net.nikr.eve.jeveasset.gui.tabs.materials.MaterialsTab; import net.nikr.eve.jeveasset.gui.tabs.mining.ExtractionsTab; import net.nikr.eve.jeveasset.gui.tabs.mining.MiningGraphTab; import net.nikr.eve.jeveasset.gui.tabs.mining.MiningTab; import net.nikr.eve.jeveasset.gui.tabs.orders.MarketOrdersTab; import net.nikr.eve.jeveasset.gui.tabs.orders.OutbidProcesser.OutbidProcesserOutput; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceChangesTab; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceHistoryTab; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedTab; import net.nikr.eve.jeveasset.gui.tabs.routing.RoutingTab; import net.nikr.eve.jeveasset.gui.tabs.skills.SkillsTab; import net.nikr.eve.jeveasset.gui.tabs.skills.SkillsOverviewTab; import net.nikr.eve.jeveasset.gui.tabs.slots.SlotsTab; import net.nikr.eve.jeveasset.gui.tabs.standing.NpcStandingTab; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileTab; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerTab; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTab; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTab; import net.nikr.eve.jeveasset.gui.tabs.values.DataSetCreator; import net.nikr.eve.jeveasset.gui.tabs.values.ValueRetroTab; import net.nikr.eve.jeveasset.gui.tabs.values.ValueTableTab; import net.nikr.eve.jeveasset.i18n.GuiFrame; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.io.local.profile.ProfileDatabase.Table; import net.nikr.eve.jeveasset.io.online.PriceDataGetter; import net.nikr.eve.jeveasset.io.online.Updater; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.DesktopUtil; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Program implements ActionListener { private static final Logger LOG = LoggerFactory.getLogger(Program.class); private enum ProgramAction { TIMER } //Major.Minor.Bugfix [Release Candidate n] [BETA n] [DEV BUILD #n]; public static final String PROGRAM_VERSION = "8.1.3 DEV BUILD 1"; public static final String PROGRAM_NAME = "jEveAssets"; public static final String PROGRAM_HOMEPAGE = "https://eve.nikr.net/jeveasset"; public static final String PROGRAM_USER_AGENT = PROGRAM_NAME + "/" + PROGRAM_VERSION.replace(" ", "_") + " (nkr@niklaskr.dk)"; private static final boolean PROGRAM_DEV_BUILD = false; //Height private static int height = 22; //Defaults to 22 //GUI private MainWindow mainWindow; //Dialogs private AccountManagerDialog accountManagerDialog; private AboutDialog aboutDialog; private ProfileDialog profileDialog; private SettingsDialog settingsDialog; private UpdateDialog updateDialog; private StructureUpdateDialog structureUpdateDialog; //Tabs private ValueRetroTab valueRetroTab; private ValueTableTab valueTableTab; private PriceHistoryTab priceHistoryTab; private MaterialsTab materialsTab; private LoadoutsTab loadoutsTab; private RoutingTab routingTab; private MarketOrdersTab marketOrdersTab; private JournalTab journalTab; private TransactionTab transactionsTab; private IndustryJobsTab industryJobsTab; private SlotsTab slotsTab; private AssetsTab assetsTab; private OverviewTab overviewTab; private StockpileTab stockpileTab; private ItemsTab itemsTab; private TrackerTab trackerTab; private ReprocessedTab reprocessedTab; private ContractsTab contractsTab; private TreeTab treeTab; private SkillsTab skillsTab; private SkillsOverviewTab skillsOverviewTab; private LoyaltyPointsTab loyaltyPointsTab; private NpcStandingTab npcStandingTab; private AgentsTab agentsTab; private MiningTab miningTab; private MiningGraphTab miningGraphTab; private ExtractionsTab extractionsTab; private PriceChangesTab priceChangesTab; //Misc private Updater updater; private Timer timer; private Updatable updatable; private final Map jMainTabs = new HashMap<>(); //Data private final ProfileData profileData; private final ProfileManager profileManager; private final PriceDataGetter priceDataGetter; private final String localData; public Program() { if (CliOptions.get().isDebug() || CliOptions.get().isEDTdebug()) { LOG.info("ForceUpdate: {} NoUpdate: {} Debug: {} EDTDebug: {}", CliOptions.get().isForceUpdate(), CliOptions.get().isForceNoUpdate(), CliOptions.get().isDebug(), CliOptions.get().isEDTdebug()); DetectEdtViolationRepaintManager.install(); } //Load Static Data, Settings, Tracker Data, Added Data, Contract Prices init(); //Look and feel initLookAndFeel(Settings.get().getColorSettings().getLookAndFeelClass()); calcButtonsHeight(); //Must be done after setting the LAF //Check for data/program updates updater = new Updater(); localData = updater.getLocalData(); if (!isDevBuild()) { update(); } //Load profile data profileManager = new ProfileManager(); profileManager.searchProfile(); profileManager.loadActiveProfile(); profileData = new ProfileData(profileManager); //Can not update profile data now - list needs to be empty doing creation... //Load price data priceDataGetter = new PriceDataGetter(); priceDataGetter.load(); SplashUpdater.setProgress(45); //Timer timer = new Timer(15000, this); //4 times each minute timer.setActionCommand(ProgramAction.TIMER.name()); //Updatable updatable = new Updatable(this); //GUI SplashUpdater.setText("Loading GUI"); LOG.info("GUI Loading:"); LOG.info("Loading: Images"); Images.preload(); LOG.info("Loading: Sounds"); SoundPlayer.load(); LOG.info("Loading: Main Window"); mainWindow = new MainWindow(this); SplashUpdater.setProgress(50); //Tools LOG.info("Loading: Assets Tab"); assetsTab = new AssetsTab(this); mainWindow.addTab(assetsTab); SplashUpdater.setProgress(52); if (Settings.get().isLoadToolsStartup()) { ToolLoader.initAllTools(this); } else { ToolLoader.initTools(this,Settings.get().getShowTools()); } //Dialogs LOG.info("Loading: Account Manager Dialog"); accountManagerDialog = new AccountManagerDialog(this); SplashUpdater.setProgress(85); LOG.info("Loading: About Dialog"); aboutDialog = new AboutDialog(this); SplashUpdater.setProgress(86); LOG.info("Loading: Profiles Dialog"); profileDialog = new ProfileDialog(this); SplashUpdater.setProgress(88); LOG.info("Loading: Update Dialog"); updateDialog = new UpdateDialog(this); SplashUpdater.setProgress(90); LOG.info("Loading: Options Dialog"); settingsDialog = new SettingsDialog(this); SplashUpdater.setProgress(96); LOG.info("Loading: Structure UpdateDialog"); structureUpdateDialog = new StructureUpdateDialog(this); //GUI Done LOG.info("GUI loaded"); //Updating data... LOG.info("Updating data..."); updateEventLists(); //OSXAdapter macOsxCode(); //Open Tools ToolLoader.openTools(this, Settings.get().getShowTools()); SplashUpdater.setProgress(100); LOG.info("Showing GUI"); mainWindow.show(); SplashUpdater.hide(); //Start timer timerTicked(); //Background tool loader ToolLoader.init(this); if (Settings.get().isLoadToolsBackground()) { ToolLoader.startBackgroundToolLoading(this); } LOG.info("Startup Done"); if (CliOptions.get().isDebug()) { LOG.info("Show Debug Warning"); JOptionPane.showMessageDialog(mainWindow.getFrame(), "WARNING: Debug is enabled", "Debug", JOptionPane.WARNING_MESSAGE); } if (isDevBuild()) { JOptionPane.showMessageDialog(mainWindow.getFrame(), "WARNING: This is a dev build\r\n\r\nNotes:\r\n- Always run portable\r\n- Settings and profiles are cloned\r\n- Does not check for updates\r\n- Expect bugs!", "DEV BUILD", JOptionPane.WARNING_MESSAGE); } if (Settings.get().isSettingsLoadError()) { JOptionPane.showMessageDialog(mainWindow.getFrame(), GuiShared.get().errorLoadingSettingsMsg(), GuiShared.get().errorLoadingSettingsTitle(), JOptionPane.ERROR_MESSAGE); } if (NahimicDetector.isNahimicRunning()) { JOptionPane.showMessageDialog(mainWindow.getFrame(), "WARNING: Nahimic service detected. It's known to corrupt the jEveAssets GUI", "Nahimic Detected", JOptionPane.WARNING_MESSAGE); } profileManager.showProfileLoadErrorWarning(mainWindow.getFrame()); if (profileManager.getOwnerTypes().isEmpty()) { LOG.info("Show Account Manager"); accountManagerDialog.setVisible(true); } ApiIdConverter.setUpdateItem(true); } /** * To be REMOVED! * @return */ public Map getMainTabs() { return jMainTabs; } /** * Load: Static Data, Settings, Tracker Data, Added Data, Contract Prices. * PROGRAM_DEV_BUILD == true > run portable */ public static void init() { if (isDevBuild()) { CliOptions.get().setPortable(true); } SplashUpdater.setText("Loading DATA"); LOG.info("DATA Loading..."); FileUtil.autoImportFileUtil(); TempDirs.fixTempDir(); StaticData.load(); Settings.load(); TrackerData.load(); AddedData.load(); PriceHistoryDatabase.load(); } /** * * @param load does nothing except change the signature. */ protected Program(final boolean load) { profileData = null; profileManager = null; priceDataGetter = null; localData = null; } private void initLookAndFeel(String lookAndFeel) { initLookAndFeel(lookAndFeel, true); } private void initLookAndFeel(String lookAndFeel, boolean tryDefault) { //Allow users to overwrite LaF if (System.getProperty("swing.defaultlaf") != null) { return; } //lookAndFeel = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"; //lookAndFeel = UIManager.getSystemLookAndFeelClassName(); //System //lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName(); //Java //lookAndFeel = "javax.swing.plaf.nimbus.NimbusLookAndFeel"; //Nimbus //lookAndFeel = "javax.swing.plaf.metal.MetalLookAndFeel"; //Metal //lookAndFeel = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"; //GTK+ //lookAndFeel = "com.sun.java.swing.plaf.motif.MotifLookAndFeel"; //CDE/Motif //flatlaf //lookAndFeel = "com.formdev.flatlaf.FlatLightLaf"; //Flat Light //lookAndFeel = "com.formdev.flatlaf.FlatDarkLaf"; //Flat Dark //lookAndFeel = "com.formdev.flatlaf.FlatIntelliJLaf"; //Flat IntelliJ //lookAndFeel = "com.formdev.flatlaf.FlatDarculaLaf"; //Flat Darcula try { UIManager.setLookAndFeel(lookAndFeel); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { LOG.error(ex.getMessage(), ex); //In case the settings is using an unsupported look and feel //Try system look and feel if (tryDefault) { initLookAndFeel(UIManager.getSystemLookAndFeelClassName(), false); } } setKeys(); // This must be performed immediately after the LaF has been set //Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); JDialog.setDefaultLookAndFeelDecorated(true); } private void setKeys() { // Ensure Max OSX/Windows/Linux key bindings are useable for copy, cut, paste, and select all addKeysText(UIManager.get("EditorPane.focusInputMap")); addKeysText(UIManager.get("FormattedTextField.focusInputMap")); addKeysText(UIManager.get("PasswordField.focusInputMap")); addKeysText(UIManager.get("TextField.focusInputMap")); addKeysText(UIManager.get("TextPane.focusInputMap")); addKeysText(UIManager.get("TextArea.focusInputMap")); addKeysMisc(UIManager.get("Table.ancestorInputMap")); addKeysMisc(UIManager.get("Tree.focusInputMap")); addKeysMisc(UIManager.get("List.focusInputMap")); } private void addKeysText(Object object) { if (object instanceof InputMap) { //Better safe than sorry InputMap inputMap = (InputMap) object; //Mac Keys inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.META_DOWN_MASK), DefaultEditorKit.copyAction); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.META_DOWN_MASK), DefaultEditorKit.cutAction); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK), DefaultEditorKit.pasteAction); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.META_DOWN_MASK), DefaultEditorKit.selectAllAction); //Win Keys inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.copyAction); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.cutAction); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.pasteAction); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.selectAllAction); //Other inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.copyAction); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.cutAction); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK), DefaultEditorKit.pasteAction); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SLASH, KeyEvent.CTRL_DOWN_MASK), DefaultEditorKit.selectAllAction); } } private void addKeysMisc(Object object) { if (object instanceof InputMap) { //Better safe than sorry InputMap inputMap = (InputMap) object; //Mac Keys inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.META_DOWN_MASK), "copy"); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.META_DOWN_MASK), "cut"); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK), "parse"); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.META_DOWN_MASK), "selectAll"); //Win Keys inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK), "copy"); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_DOWN_MASK), "cut"); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK), "parse"); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_DOWN_MASK), "selectAll"); //Other inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.CTRL_DOWN_MASK), "copy"); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, KeyEvent.SHIFT_DOWN_MASK), "cut"); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.SHIFT_DOWN_MASK), "parse"); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SLASH, KeyEvent.CTRL_DOWN_MASK), "selectAll"); } } public static int getButtonsHeight() { return height; } private void calcButtonsHeight() { height = Math.max(height, new JComboBox<>().getPreferredSize().height); height = Math.max(height, new JTextField().getPreferredSize().height); height = Math.max(height, new JButton().getPreferredSize().height); } public static int getButtonsWidth() { return 90; } public static int getIconButtonsWidth() { return 30; } public void addMainTab(final String toolName, final JMainTab jMainTab) { JMainTab old = jMainTabs.put(toolName, jMainTab); if (old != null) { throw new RuntimeException("toolName: " + toolName + " is duplicated"); } } public Map getInitTabs() { return jMainTabs; } private void timerTicked() { if (!timer.isRunning()) { timer.start(); } boolean isUpdatable = updatable.isUpdatable(); this.getStatusPanel().timerTicked(isUpdatable); this.getMainWindow().getMenu().timerTicked(isUpdatable, StructureUpdateDialog.structuresUpdatable(this)); } public final void update() { updater.update(Program.PROGRAM_VERSION, localData, Settings.get().getProxyData()); } public boolean checkProgramUpdate() { return updater.checkProgramUpdate(Program.PROGRAM_VERSION); } public boolean checkDataUpdate() { return updater.checkDataUpdate(localData); } public final void showUpdateStructuresDialog(boolean minimizable) { if (getStatusPanel().updateing(UpdateType.STRUCTURE)) { JOptionPane.showMessageDialog(getMainWindow().getFrame(), GuiFrame.get().updatingInProgressMsg(), GuiFrame.get().updatingInProgressTitle(), JOptionPane.PLAIN_MESSAGE); } else { updateStructures(null, minimizable); } } public final void updateMarketOrdersWithProgress(OutbidProcesserOutput output) { JLockWindow jLockWindow = new JLockWindow(getMainWindow().getFrame()); jLockWindow.show(GuiShared.get().updating(), new LockWorkerAdaptor() { @Override public void task() { updateEventLists(null, null, null, output); } }); } public final void updateMarketOrders(OutbidProcesserOutput output) { updateEventLists(null, null, null, output); } public final void updateLocations(Set locationIDs) { JLockWindow jLockWindow = new JLockWindow(getMainWindow().getFrame()); jLockWindow.show(GuiShared.get().updating(), new LockWorkerAdaptor() { @Override public void task() { updateEventLists(null, locationIDs, null, null); } }); } public final void updatePrices(Set typeIDs) { JLockWindow jLockWindow = new JLockWindow(getMainWindow().getFrame()); jLockWindow.show(GuiShared.get().updating(), new LockWorkerAdaptor() { @Override public void task() { updateEventLists(null, null, typeIDs, null); } }); } public final void updateNames(Set itemIDs) { JLockWindow jLockWindow = new JLockWindow(getMainWindow().getFrame()); jLockWindow.show(GuiShared.get().updating(), new LockWorkerAdaptor() { @Override public void task() { updateEventLists(itemIDs, null, null, null); } }); } public final void updateEventListsWithProgress() { updateEventListsWithProgress(getMainWindow().getFrame()); } public final void updateEventListsWithProgress(final Window parent) { JLockWindow jLockWindow = new JLockWindow(parent); jLockWindow.show(GuiShared.get().updating(), new LockWorkerAdaptor() { @Override public void task() { updateEventLists(); } }); } public final void updateEventLists() { updateEventLists(null, null, null, null); } private synchronized void updateEventLists(Set itemIDs, Set locationIDs, Set typeIDs, OutbidProcesserOutput output) { LOG.info("Updating EventList"); FilterMatcher.clearColumnValueCache(); for (JMainTab jMainTab : mainWindow.getTabs()) { ensureEDT(new Runnable() { @Override public void run() { jMainTab.beforeUpdateData(); } }); } if (output != null) { profileData.updateMarketOrders(output); } else if (itemIDs != null) { profileData.updateNames(itemIDs); } else if (locationIDs != null) { profileData.updateLocations(locationIDs); } else if (typeIDs != null) { profileData.updatePrice(typeIDs); } else { SoundPlayer.cancelAll(); //Stop sounds profileData.updateEventLists(); } if (locationIDs != null) { //Update locations for (JMainTab jMainTab : mainWindow.getTabs()) { ensureEDT(new Runnable() { @Override public void run() { jMainTab.updateLocations(locationIDs); } }); } } else if (typeIDs != null) { //Update prices for (JMainTab jMainTab : mainWindow.getTabs()) { ensureEDT(new Runnable() { @Override public void run() { jMainTab.updatePrices(typeIDs); } }); } } else if (itemIDs != null) { //Update names for (JMainTab jMainTab : mainWindow.getTabs()) { ensureEDT(new Runnable() { @Override public void run() { jMainTab.updateNames(itemIDs); } }); } } else { //Full update for (JMainTab jMainTab : mainWindow.getTabs()) { ensureEDT(new Runnable() { @Override public void run() { jMainTab.updateData(); } }); } } for (JMainTab jMainTab : mainWindow.getTabs()) { ensureEDT(new Runnable() { @Override public void run() { jMainTab.afterUpdateData(); jMainTab.updateCache(); jMainTab.repaintFilters(); } }); } ensureEDT(new Runnable() { @Override public void run() { StockpileTab stockpile = getStockpileTab(false); if (stockpile != null) { stockpile.updateStockpileDialog(); } } }); ensureEDT(new Runnable() { @Override public void run() { timerTicked(); } }); ensureEDT(new Runnable() { @Override public void run() { updateTableMenu(); } }); } public void repaintTables() { for (JMainTab jMainTab : mainWindow.getTabs()) { ensureEDT(new Runnable() { @Override public void run() { jMainTab.repaintTable(); } }); } } public static void ensureEDT(Runnable runnable) { if (SwingUtilities.isEventDispatchThread()) { runnable.run(); } else { try { SwingUtilities.invokeAndWait(runnable); } catch (InterruptedException | InvocationTargetException ex) { throw new RuntimeException(ex); } } } /** * Save Settings ASAP * @param msg Who is saving what? */ public void saveSettings(final String msg) { if (!CliOptions.get().isLazySave() && !Settings.ignoreSave()) { Settings.saveStart(); Thread thread = new SaveSettings(msg, this); thread.start(); } } private void doSaveSettings(final String msg) { LOG.info("Saving Settings: " + msg); Settings.lock("Table (Column/Width/Resize) and Window Settings"); //Lock for Table (Column/Width/Resize) and Window Settings mainWindow.updateSettings(); for (JMainTab jMainTab : getInitTabs().values()) { jMainTab.saveSettings(); } Settings.unlock("Table (Column/Width/Resize) and Window Settings"); //Unlock for Table (Column/Width/Resize) and Window Settings Settings.saveSettings(); } public void saveSettingsAndProfile() { if (CliOptions.get().isLazySave()) { doSaveSettings("API Update"); } else { saveSettings("API Update"); Settings.waitForEmptySaveQueue(); } profileManager.saveProfile(); } public synchronized void saveProfile() { LOG.info("Saving Profile"); profileManager.saveProfile(); } public synchronized void saveTable(Table table) { LOG.info("Saving Profile Table"); profileManager.saveProfileTable(table); } public void exit() { if (safeExit()) { System.exit(0); } } /** * Make ready to exit * @return true for exit and false to cancel exit */ private boolean safeExit() { if (getStatusPanel().updateInProgress() > 0) { int value = JOptionPane.showConfirmDialog(getMainWindow().getFrame(), GuiFrame.get().exitMsg(getStatusPanel().updateInProgress()), GuiFrame.get().exitTitle(getStatusPanel().updateInProgress()), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (value != JOptionPane.OK_OPTION) { return false; } } getStatusPanel().cancelUpdates(); saveExit(); LOG.info("Running shutdown hook(s) and exiting..."); return true; } private void saveExit() { if (CliOptions.get().isLazySave()) { doSaveSettings("Exit"); } else { LOG.info("Waiting for save queue to finish..."); Settings.waitForEmptySaveQueue(); } TrackerData.waitForEmptySaveQueue(); } private void showAbout() { ensureEDT(new Runnable() { @Override public void run() { aboutDialog.setVisible(true); } }); } private void showSettings() { ensureEDT(new Runnable() { @Override public void run() { settingsDialog.setVisible(true); } }); } public String getProgramDataVersion() { return localData; } private void macOsxCode() { if (FileUtil.onMac()) { FlatDesktop.setAboutHandler(new Runnable() { @Override public void run() { showAbout(); } }); FlatDesktop.setPreferencesHandler(new Runnable() { @Override public void run() { showSettings(); } }); FlatDesktop.setQuitHandler(new Consumer() { @Override public void accept(QuitResponse quitResponse) { if (safeExit()) { quitResponse.performQuit(); } else { quitResponse.cancelQuit(); } } }); } } public MainWindow getMainWindow() { return mainWindow; } public AssetsTab getAssetsTab() { return assetsTab; } public ContractsTab getContractsTab(boolean init) { if (init && contractsTab == null) { LOG.info("Loading: Contracts Tab"); contractsTab = new ContractsTab(this); } return contractsTab; } public IndustryJobsTab getIndustryJobsTab(boolean init) { if (init && industryJobsTab == null) { LOG.info("Loading: Industry Jobs Tab"); industryJobsTab = new IndustryJobsTab(this); } return industryJobsTab; } public SlotsTab getSlotsTab(boolean init) { if (init && slotsTab == null) { LOG.info("Loading: Slots Tab"); slotsTab = new SlotsTab(this); } return slotsTab; } public OverviewTab getOverviewTab(boolean init) { if (init && overviewTab == null) { LOG.info("Loading: Overview Tab"); overviewTab = new OverviewTab(this); } return overviewTab; } public TreeTab getTreeTab(boolean init) { if (init && treeTab == null) { LOG.info("Loading: Tree Tab"); treeTab = new TreeTab(this); } return treeTab; } public LoadoutsTab getLoadoutsTab(boolean init) { if (init && loadoutsTab == null) { LOG.info("Loading: Ship Loadouts Tab"); loadoutsTab = new LoadoutsTab(this); } return loadoutsTab; } public StockpileTab getStockpileTab(boolean init) { if (init && stockpileTab == null) { LOG.info("Loading: Stockpile Tab"); stockpileTab = new StockpileTab(this); } return stockpileTab; } public ReprocessedTab getReprocessedTab(boolean init) { if (init && reprocessedTab == null) { LOG.info("Loading: Reprocessed Tab"); reprocessedTab = new ReprocessedTab(this); } return reprocessedTab; } public SkillsOverviewTab getSkillsOverviewTab(boolean init) { if (init && skillsOverviewTab == null) { LOG.info("Loading: Skills Overview Tab"); skillsOverviewTab = new SkillsOverviewTab(this); } return skillsOverviewTab; } public RoutingTab getRoutingTab(boolean init) { if (init && routingTab == null) { LOG.info("Loading: Routing Tab"); routingTab = new RoutingTab(this); } return routingTab; } public TrackerTab getTrackerTab(boolean init) { if (init && trackerTab == null) { LOG.info("Loading: Tracker Tab"); trackerTab = new TrackerTab(this); } return trackerTab; } public ValueRetroTab getValueTab(boolean init) { if (init && valueRetroTab == null) { LOG.info("Loading: Values Tab"); valueRetroTab = new ValueRetroTab(this); } return valueRetroTab; } public ValueTableTab getIskTab(boolean init) { if (init && valueTableTab == null) { LOG.info("Loading: Isk Tab"); valueTableTab = new ValueTableTab(this); } return valueTableTab; } public TransactionTab getTransactionsTab(boolean init) { if (init && transactionsTab == null) { LOG.info("Loading: Transactions Tab"); transactionsTab = new TransactionTab(this); } return transactionsTab; } public PriceHistoryTab getPriceHistoryTab(boolean init) { if (init && priceHistoryTab == null) { LOG.info("Loading: Price History Tab"); priceHistoryTab = new PriceHistoryTab(Program.this); } return priceHistoryTab; } public MarketOrdersTab getMarketOrdersTab(boolean init) { if (init && marketOrdersTab == null) { LOG.info("Loading: Market Orders Tab"); marketOrdersTab = new MarketOrdersTab(this); } return marketOrdersTab; } public MiningTab getMiningTab(boolean init) { if (init && miningTab == null) { LOG.info("Loading: Mining Log Tab"); miningTab = new MiningTab(this); } return miningTab; } public MiningGraphTab getMiningGraphTab(boolean init) { if (init && miningGraphTab == null) { LOG.info("Loading: Mining Graph Tab"); miningGraphTab = new MiningGraphTab(this); } return miningGraphTab; } public ExtractionsTab getExtractionsTab(boolean init) { if (init && extractionsTab == null) { LOG.info("Loading: Extractions Tab"); extractionsTab = new ExtractionsTab(this); } return extractionsTab; } public MaterialsTab getMaterialsTab(boolean init) { if (init && materialsTab == null) { LOG.info("Loading: Materials Tab"); materialsTab = new MaterialsTab(this); } return materialsTab; } public PriceChangesTab getPriceChangesTab(boolean init) { if (init && priceChangesTab == null) { LOG.info("Loading: Price Changes Tab"); priceChangesTab = new PriceChangesTab(this); } return priceChangesTab; } public JournalTab getJournalTab(boolean init) { if (init && journalTab == null) { LOG.info("Loading: Journal Tab"); journalTab = new JournalTab(this); } return journalTab; } public ItemsTab getItemsTab(boolean init) { if (init && itemsTab == null) { LOG.info("Loading: Items Tab"); itemsTab = new ItemsTab(this); } return itemsTab; } public SkillsTab getSkillsTab(boolean init) { if (init && skillsTab == null) { LOG.info("Loading: Skills Tab"); skillsTab = new SkillsTab(this); } return skillsTab; } public LoyaltyPointsTab getLoyaltyPointsTab(boolean init) { if (init && loyaltyPointsTab == null) { LOG.info("Loading: Loyalty Points Tab"); loyaltyPointsTab = new LoyaltyPointsTab(this); } return loyaltyPointsTab; } public NpcStandingTab getNpcStandingTab(boolean init) { if (init && npcStandingTab == null) { LOG.info("Loading: NPC Standing Tab"); npcStandingTab = new NpcStandingTab(this); } return npcStandingTab; } public AgentsTab getAgentsTab(boolean init) { if (init && agentsTab == null) { LOG.info("Loading: Agents Tab"); agentsTab = new AgentsTab(this); } return agentsTab; } public StatusPanel getStatusPanel() { return this.getMainWindow().getStatusPanel(); } public UserNameSettingsPanel getUserNameSettingsPanel() { if (settingsDialog != null) { return settingsDialog.getUserNameSettingsPanel(); } else { return null; } } public UserPriceSettingsPanel getUserPriceSettingsPanel() { if (settingsDialog != null) { return settingsDialog.getUserPriceSettingsPanel(); } else { return null; } } public UserLocationSettingsPanel getUserLocationSettingsPanel() { if (settingsDialog != null) { return settingsDialog.getUserLocationSettingsPanel(); } else { return null; } } public void showJumpsSettingsPanel() { if (settingsDialog != null) { settingsDialog.showJumpsSettingsPanel(); } } public ProfileData getProfileData() { return profileData; } public List getAssetsList() { return profileData.getAssetsList(); } public List getContractList() { return profileData.getContractList(); } public List getContractItemList() { return profileData.getContractItemList(); } public List getIndustryJobsList() { return profileData.getIndustryJobsList(); } public List getMarketOrdersList() { return profileData.getMarketOrdersList(); } public List getJournalList() { return profileData.getJournalList(); } public List getTransactionsList() { return profileData.getTransactionsList(); } public List getAccountBalanceList() { return profileData.getAccountBalanceList(); } public List getOwnerNames(boolean all) { return profileData.getOwnerNames(all); } public Map getOwners() { return profileData.getOwners(); } public List getOwnerTypes() { return profileManager.getOwnerTypes(); } public ProfileManager getProfileManager() { return profileManager; } public PriceDataGetter getPriceDataGetter() { return priceDataGetter; } public void createTrackerDataPoint() { DataSetCreator.createTrackerDataPoint(profileData, Settings.getNow()); TrackerData.save("Added", true); ensureEDT(new Runnable() { @Override public void run() { TrackerTab tracker = getTrackerTab(false); if (tracker != null) { tracker.updateData(); } } }); } public static boolean isDevBuild() { return PROGRAM_DEV_BUILD; } public void updateStructures(Set locations, boolean minimizable) { structureUpdateDialog.show(locations, minimizable); } /** * Called when Tags are changed. */ public void updateTags() { JLockWindow jLockWindow = new JLockWindow(getMainWindow().getFrame()); jLockWindow.show(GuiShared.get().updating(), new LockWorkerAdaptor() { @Override public void task() { for (JMainTab mainTab : getInitTabs().values()) { if (mainTab instanceof TagUpdate) { mainTab.updateCache(); } } } @Override public void gui() { for (JMainTab mainTab : getInitTabs().values()) { if (mainTab instanceof TagUpdate) { TagUpdate tagUpdate = (TagUpdate) mainTab; tagUpdate.updateTags(); } } } }); } /** * Called when Overview Groups are changed. */ public void overviewGroupsChanged() { RoutingTab routing = getRoutingTab(false); if (routing != null) { routing.overviewGroupsChanged(); } } /** * Called when the table menu needs update. */ public void updateTableMenu() { this.getMainWindow().getSelectedTab().updateTableMenu(); } /** * Called when the active tab is change (close/open/change). */ public void tabChanged() { getStatusPanel().tabChanged(); if (industryJobsTab != null) { industryJobsTab.tabChanged(); } updateTableMenu(); } @Override public void actionPerformed(final ActionEvent e) { //Tools if (MainMenuAction.VALUES.name().equals(e.getActionCommand())) { mainWindow.addTab(getValueTab(true)); } else if (MainMenuAction.VALUE_TABLE.name().equals(e.getActionCommand())) { mainWindow.addTab(getIskTab(true)); } else if (MainMenuAction.PRICE_HISTORY.name().equals(e.getActionCommand())) { mainWindow.addTab(getPriceHistoryTab(true)); } else if (MainMenuAction.PRICE_CHANGES.name().equals(e.getActionCommand())) { mainWindow.addTab(getPriceChangesTab(true)); } else if (MainMenuAction.MATERIALS.name().equals(e.getActionCommand())) { mainWindow.addTab(getMaterialsTab(true)); } else if (MainMenuAction.LOADOUTS.name().equals(e.getActionCommand())) { mainWindow.addTab(getLoadoutsTab(true)); } else if (MainMenuAction.MARKET_ORDERS.name().equals(e.getActionCommand())) { mainWindow.addTab(getMarketOrdersTab(true)); } else if (MainMenuAction.JOURNAL.name().equals(e.getActionCommand())) { mainWindow.addTab(getJournalTab(true)); } else if (MainMenuAction.TRANSACTION.name().equals(e.getActionCommand())) { mainWindow.addTab(getTransactionsTab(true)); } else if (MainMenuAction.INDUSTRY_JOBS.name().equals(e.getActionCommand())) { mainWindow.addTab(getIndustryJobsTab(true)); } else if (MainMenuAction.SLOTS.name().equals(e.getActionCommand())) { mainWindow.addTab(getSlotsTab(true)); } else if (MainMenuAction.OVERVIEW.name().equals(e.getActionCommand())) { mainWindow.addTab(getOverviewTab(true)); } else if (MainMenuAction.ROUTING.name().equals(e.getActionCommand())) { mainWindow.addTab(getRoutingTab(true)); } else if (MainMenuAction.STOCKPILE.name().equals(e.getActionCommand())) { mainWindow.addTab(getStockpileTab(true)); } else if (MainMenuAction.ITEMS.name().equals(e.getActionCommand())) { mainWindow.addTab(getItemsTab(true)); } else if (MainMenuAction.TRACKER.name().equals(e.getActionCommand())) { TrackerTab tracker = getTrackerTab(true); mainWindow.addTab(tracker); tracker.checkAll(); } else if (MainMenuAction.REPROCESSED.name().equals(e.getActionCommand())) { mainWindow.addTab(getReprocessedTab(true)); } else if (MainMenuAction.CONTRACTS.name().equals(e.getActionCommand())) { mainWindow.addTab(getContractsTab(true)); } else if (MainMenuAction.TREE.name().equals(e.getActionCommand())) { mainWindow.addTab(getTreeTab(true)); } else if (MainMenuAction.SKILLS.name().equals(e.getActionCommand())) { mainWindow.addTab(getSkillsTab(true)); } else if (MainMenuAction.SKILLS_OVERVIEW.name().equals(e.getActionCommand())) { mainWindow.addTab(getSkillsOverviewTab(true)); } else if (MainMenuAction.LOYALTY_POINTS.name().equals(e.getActionCommand())) { mainWindow.addTab(getLoyaltyPointsTab(true)); } else if (MainMenuAction.NPC_STANDING.name().equals(e.getActionCommand())) { mainWindow.addTab(getNpcStandingTab(true)); } else if (MainMenuAction.AGENTS.name().equals(e.getActionCommand())) { mainWindow.addTab(getAgentsTab(true)); } else if (MainMenuAction.MINING_ALL.name().equals(e.getActionCommand())) { mainWindow.addTab(getMiningTab(true)); mainWindow.addTab(getMiningGraphTab(true)); mainWindow.addTab(getExtractionsTab(true)); } else if (MainMenuAction.MINING_LOG.name().equals(e.getActionCommand())) { mainWindow.addTab(getMiningTab(true)); } else if (MainMenuAction.MINING_GRAPH.name().equals(e.getActionCommand())) { mainWindow.addTab(getMiningGraphTab(true)); } else if (MainMenuAction.EXTRACTIONS.name().equals(e.getActionCommand())) { mainWindow.addTab(getExtractionsTab(true)); } else if (MainMenuAction.ACCOUNT_MANAGER.name().equals(e.getActionCommand())) { //Settings accountManagerDialog.setVisible(true); } else if (MainMenuAction.PROFILES.name().equals(e.getActionCommand())) { profileDialog.setVisible(true); } else if (MainMenuAction.OPTIONS.name().equals(e.getActionCommand())) { showSettings(); } else if (MainMenuAction.UPDATE.name().equals(e.getActionCommand())) { //Update updateDialog.setVisible(true); } else if (MainMenuAction.UPDATE_STRUCTURE.name().equals(e.getActionCommand())) { showUpdateStructuresDialog(true); } else if (MainMenuAction.ABOUT.name().equals(e.getActionCommand())) { //Others showAbout(); } else if (MainMenuAction.LINK_WIKI.name().equals(e.getActionCommand())) { DesktopUtil.browse("https://wiki.jeveassets.org", this); //Links } else if (MainMenuAction.LINK_FEEDBACK_AND_HELP.name().equals(e.getActionCommand())) { DesktopUtil.browse("https://wiki.jeveassets.org/faq#feedback_and_help", this); } else if (MainMenuAction.LINK_DISCORD.name().equals(e.getActionCommand())) { DesktopUtil.browse("https://discord.gg/8kYZvbM", this); } else if (MainMenuAction.README.name().equals(e.getActionCommand())) { //External Files DesktopUtil.open(FileUtil.getPathReadme(), this); } else if (MainMenuAction.LICENSE.name().equals(e.getActionCommand())) { DesktopUtil.open(FileUtil.getPathLicense(), this); } else if (MainMenuAction.CREDITS.name().equals(e.getActionCommand())) { DesktopUtil.open(FileUtil.getPathCredits(), this); } else if (MainMenuAction.CHANGELOG.name().equals(e.getActionCommand())) { DesktopUtil.open(FileUtil.getPathChangeLog(), this); } else if (MainMenuAction.EXIT_PROGRAM.name().equals(e.getActionCommand())) { //Exit exit(); } else if (ProgramAction.TIMER.name().equals(e.getActionCommand())) { //Ticker timerTicked(); } } private static class SaveSettings extends Thread { private static int counter = 0; private final String msg; private final Program program; private final int id; public SaveSettings(String msg, Program program) { super("Save Settings " + counter++ + ": " + msg); this.msg = msg; this.program = program; this.id = counter; } @Override public void run() { long before = System.currentTimeMillis(); program.doSaveSettings(msg); Settings.saveEnd(); long after = System.currentTimeMillis(); LOG.debug("Settings saved in: " + (after - before) + "ms"); } @Override public int hashCode() { int hash = 7; hash = 67 * hash + this.id; return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final SaveSettings other = (SaveSettings) obj; return this.id == other.id; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/SingleInstance.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * Original code from: http://ganeshtiwaridotcomdotnp.blogspot.dk/2012/01/java-single-instance-of-application.html * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset; import java.awt.GraphicsEnvironment; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.i18n.General; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SingleInstance { private static final Logger LOG = LoggerFactory.getLogger(SingleInstance.class); private final String HOST = "127.0.0.1"; private final int PORT = 2222; private final DetectForNew thread; private boolean msgShown = false; public SingleInstance() { // try to connect to server test(); // start detecting server thread thread = new DetectForNew(); thread.start(); } public boolean isSingleInstance() { return thread.isSingleInstance() && !msgShown; } private void test() { if (!msgShown && findExisting()) { msgShown = true; if(GraphicsEnvironment.isHeadless()) { LOG.error("jEveAssets is already running"); LOG.error("jEveAssets do not support running more than one instance"); LOG.error("To avoid losing or corrupting data jEveAssets will now exit"); LOG.error("Goodbye..."); System.exit(-1); } int value = JOptionPane.showConfirmDialog(Main.getTop(), General.get().singleInstanceMsg(), General.get().singleInstanceTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); if (value != JOptionPane.YES_OPTION) { System.exit(-1); } } } private boolean findExisting() { LOG.info("Check for existing instances"); try { new Socket(HOST, PORT); return true; } catch (Exception e) { return false; } } class DetectForNew extends Thread { private ServerSocket serverSocket; private boolean singleInstance = true; public DetectForNew() { createServerSocket(); } public boolean isSingleInstance() { return singleInstance && serverSocket != null; } @Override public void run() { while (true) { if (serverSocket == null && !findExisting()) { createServerSocket(); } try { if (serverSocket != null) { serverSocket.accept(); singleInstance = false; } else { Thread.sleep(2000); //Wait a bit and try again... } } catch (IOException ex) { //Ignore IO error } catch (InterruptedException ex) { return; //We are done (exiting program) } } } private void createServerSocket() { LOG.info("Creating instance blocker"); try { serverSocket = new ServerSocket(PORT); } catch (IOException ex) { test(); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/SplashUpdater.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset; import java.awt.AlphaComposite; import java.awt.Canvas; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.SplashScreen; import java.awt.image.BufferStrategy; import java.awt.image.BufferedImage; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.JWindow; import javax.swing.SwingUtilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SplashUpdater { private static final Logger LOG = LoggerFactory.getLogger(SplashUpdater.class); private static int progress = 0; private static int subProgress = 0; private static String text = ""; private static int currentLoadingImage = 0; private static BufferedImage[] loadingImages; private static SplashScreen splashScreen; private static JWindow splashWindow; private static Canvas splashWindowCanvas; private static final int UPDATE_DELAY = 200; private static final Object PAINT_LOCK = new Object(); private static BufferedImage splashImage; private static boolean showSplashWindow = true; private static long delta = 0; private static Long lastPaint = null; /** Creates a new instance of SplashUpdater. */ public SplashUpdater() { splashScreen = SplashScreen.getSplashScreen(); loadingImages = new BufferedImage[8]; for (int i = 0; i < 8; i++) { try { loadingImages[i] = ImageIO.read(getClass().getResource("gui/images/loading0" + (i + 1) + ".png")); } catch (IOException ex) { LOG.warn("SplashScreen: loading0{}.png (NOT FOUND)", (i + 1)); } } try { splashImage = ImageIO.read(getClass().getResource("/splash.jpg")); } catch (IOException | IllegalArgumentException ex) { splashImage = null; } splashWindow = new JWindow(); splashWindowCanvas = new Canvas(); splashWindowCanvas.setIgnoreRepaint(true); splashWindowCanvas.setFocusable(false); splashWindowCanvas.setFont(new Font("Dialog.plain", 0, 12)); splashWindow.add(splashWindowCanvas); if (splashScreen != null) { splashWindow.setBounds(splashScreen.getBounds()); } else if (splashImage != null) { splashWindow.setSize(splashImage.getWidth(), splashImage.getHeight()); } splashWindow.setLocationRelativeTo(null); } public static void hide() { showSplashWindow = false; splashWindow.setVisible(false); } public void start() { Animator animator = new Animator(); animator.start(); Paineter paineter = new Paineter(); paineter.start(); } public synchronized static void nextLoadingImage() { currentLoadingImage++; if (currentLoadingImage >= 8) { currentLoadingImage = 0; } } /** * Set splash screen text. * @param s String to show on splash screen */ public synchronized static void setText(final String s) { text = s; } /** * Set subprogress of splash screen progressbar in the range 0-100. * @param n Set progress in the range 0-100 */ public synchronized static void setSubProgress(final int n) { int number = n; if (number >= 100) { number = 0; } if (number < 0) { number = 0; } if (subProgress != number) { if ((number > subProgress || number == 0)) { subProgress = number; update(true); } } } /** * Set progress of splash screen progressbar in the range 0-100. * @param n Set progress in the range 0-100 */ public synchronized static void setProgress(final int n) { int number = n; if (number > 100) { number = 100; } if (number < 0) { number = 0; } if (progress != number) { if (number > progress) { progress = number; update(false); } } } private static void update(boolean sub) { if (isVisible()) { synchronized (PAINT_LOCK) { PAINT_LOCK.notify(); } } else if (SwingUtilities.isEventDispatchThread()) { showSplashWindow(); paintSplashWindow(sub); } } private static void showSplashWindow() { if (showSplashWindow && splashWindow != null && !splashWindow.isVisible()) { splashWindow.setVisible(true); splashWindow.toFront(); } } private static void paintSplashWindow(boolean sub) { synchronized (PAINT_LOCK) { if (splashWindow != null && splashWindow.isVisible()) { if (lastPaint != null) { delta = delta + (System.currentTimeMillis() - lastPaint); } boolean paint = sub || (lastPaint == null || (System.currentTimeMillis() - lastPaint) > 16); if (delta > UPDATE_DELAY) { nextLoadingImage(); delta = 0; paint = true; } if (paint) { lastPaint = System.currentTimeMillis(); nextLoadingImage(); BufferStrategy bufferStrategy = splashWindowCanvas.getBufferStrategy(); if (bufferStrategy == null) { splashWindowCanvas.createBufferStrategy(2); bufferStrategy = splashWindowCanvas.getBufferStrategy(); } Graphics g = bufferStrategy.getDrawGraphics(); g.drawImage(splashImage, 0, 0, null); paint((Graphics2D) g); g.dispose(); splashWindowCanvas.getBufferStrategy().show(); } } } } private static void paintSplashScreen() { if (isVisible()) { try { if (splashScreen != null) { Graphics2D g = splashScreen.createGraphics(); if (g != null) { g.setComposite(AlphaComposite.Clear); Dimension size = splashScreen.getSize(); g.fillRect(0, 0, size.width, size.height); g.setPaintMode(); paint(g); splashScreen.update(); } } } catch (IllegalStateException ex) { LOG.info("SplashScreen: Closed before painting ended (NO PROBLEM)"); } } } private static void paint(final Graphics2D g) throws IllegalStateException { //Clear Screen if (CliOptions.get().isDebug()) { g.setColor(Color.DARK_GRAY); g.drawString("DEBUG", 344, 232); g.setColor(Color.WHITE); g.drawString("DEBUG", 343, 231); } if (!text.isEmpty()) { g.setColor(Color.BLACK); g.fillRect(0, 235, 90, 24); g.setColor(Color.WHITE); g.drawString(text, 5, 252); } g.setColor(Color.WHITE); g.fillRect(106, 242, (int) (progress * 2.6), 12); if (subProgress > 0) { g.setColor(Color.LIGHT_GRAY); g.fillRect(106, 248, (int) (subProgress * 2.6), 6); } if (loadingImages[currentLoadingImage] != null) { g.drawImage(loadingImages[currentLoadingImage], 368, 238, null); } } private static boolean isVisible() { return (splashScreen != null && splashScreen.isVisible()); } private class Paineter extends Thread { @Override public void run() { while (isVisible()) { synchronized (PAINT_LOCK) { try { PAINT_LOCK.wait(); } catch (InterruptedException ex) { } paintSplashScreen(); } } } } private class Animator extends Thread { @Override public void run() { while (isVisible()) { nextLoadingImage(); update(false); synchronized (this) { try { wait(UPDATE_DELAY); } catch (InterruptedException ex) { break; } } } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/ToolLoader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset; import java.awt.AWTEvent; import java.awt.Component; import java.awt.KeyboardFocusManager; import java.awt.Toolkit; import java.awt.Window; import java.awt.event.AWTEventListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.swing.AbstractButton; import javax.swing.JComboBox; import javax.swing.SwingUtilities; import javax.swing.Timer; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.Progress; import net.nikr.eve.jeveasset.gui.shared.components.JMainTab; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.tabs.agents.AgentsTab; import net.nikr.eve.jeveasset.gui.tabs.agents.AgentsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetTableFormat; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetsTab; import net.nikr.eve.jeveasset.gui.tabs.contracts.ContractsTab; import net.nikr.eve.jeveasset.gui.tabs.contracts.ContractsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.items.ItemTableFormat; import net.nikr.eve.jeveasset.gui.tabs.items.ItemsTab; import net.nikr.eve.jeveasset.gui.tabs.jobs.IndustryJobTableFormat; import net.nikr.eve.jeveasset.gui.tabs.jobs.IndustryJobsTab; import net.nikr.eve.jeveasset.gui.tabs.journal.JournalTab; import net.nikr.eve.jeveasset.gui.tabs.journal.JournalTableFormat; import net.nikr.eve.jeveasset.gui.tabs.loadout.LoadoutExtendedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.loadout.LoadoutTableFormat; import net.nikr.eve.jeveasset.gui.tabs.loadout.LoadoutsTab; import net.nikr.eve.jeveasset.gui.tabs.loyalty.LoyaltyPointsTab; import net.nikr.eve.jeveasset.gui.tabs.loyalty.LoyaltyPointsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.materials.MaterialExtendedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.materials.MaterialTableFormat; import net.nikr.eve.jeveasset.gui.tabs.materials.MaterialsTab; import net.nikr.eve.jeveasset.gui.tabs.mining.ExtractionsTab; import net.nikr.eve.jeveasset.gui.tabs.mining.ExtractionsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.mining.MiningGraphTab; import net.nikr.eve.jeveasset.gui.tabs.mining.MiningTab; import net.nikr.eve.jeveasset.gui.tabs.mining.MiningTableFormat; import net.nikr.eve.jeveasset.gui.tabs.orders.MarketOrdersTab; import net.nikr.eve.jeveasset.gui.tabs.orders.MarketTableFormat; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTableFormat; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceChangesTab; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceChangesTableFormat; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceHistoryTab; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedExtendedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedTab; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.routing.RoutingTab; import net.nikr.eve.jeveasset.gui.tabs.skills.SkillsTab; import net.nikr.eve.jeveasset.gui.tabs.skills.SkillsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.slots.SlotsTab; import net.nikr.eve.jeveasset.gui.tabs.slots.SlotsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.standing.NpcStandingTab; import net.nikr.eve.jeveasset.gui.tabs.standing.NpcStandingTableFormat; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileExtendedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileTab; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileTableFormat; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerTab; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTab; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTableFormat; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTab; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTableFormat; import net.nikr.eve.jeveasset.gui.tabs.values.ValueRetroTab; import net.nikr.eve.jeveasset.gui.tabs.values.ValueTableFormat; import net.nikr.eve.jeveasset.gui.tabs.values.ValueTableTab; import net.nikr.eve.jeveasset.i18n.TabsAgents; import net.nikr.eve.jeveasset.i18n.TabsAssets; import net.nikr.eve.jeveasset.i18n.TabsContracts; import net.nikr.eve.jeveasset.i18n.TabsItems; import net.nikr.eve.jeveasset.i18n.TabsJobs; import net.nikr.eve.jeveasset.i18n.TabsJournal; import net.nikr.eve.jeveasset.i18n.TabsLoadout; import net.nikr.eve.jeveasset.i18n.TabsLoyaltyPoints; import net.nikr.eve.jeveasset.i18n.TabsMaterials; import net.nikr.eve.jeveasset.i18n.TabsMining; import net.nikr.eve.jeveasset.i18n.TabsNpcStanding; import net.nikr.eve.jeveasset.i18n.TabsOrders; import net.nikr.eve.jeveasset.i18n.TabsOverview; import net.nikr.eve.jeveasset.i18n.TabsPriceChanges; import net.nikr.eve.jeveasset.i18n.TabsPriceHistory; import net.nikr.eve.jeveasset.i18n.TabsReprocessed; import net.nikr.eve.jeveasset.i18n.TabsRouting; import net.nikr.eve.jeveasset.i18n.TabsSkills; import net.nikr.eve.jeveasset.i18n.TabsSlots; import net.nikr.eve.jeveasset.i18n.TabsStockpile; import net.nikr.eve.jeveasset.i18n.TabsTracker; import net.nikr.eve.jeveasset.i18n.TabsTransaction; import net.nikr.eve.jeveasset.i18n.TabsTree; import net.nikr.eve.jeveasset.i18n.TabsValues; public class ToolLoader implements ActionListener, KeyListener, MouseListener, MouseWheelListener, AWTEventListener, PropertyChangeListener { public static enum ToolTab { ASSETS(TabsAssets.get().assets(), AssetsTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getAssetsTab(); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return AssetTableFormat.valueOf(column); } }, VALUE(TabsValues.get().oldTitle(), ValueRetroTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getValueTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return null; } }, ISK(TabsValues.get().title(), ValueTableTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getIskTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return ValueTableFormat.valueOf(column); } }, PRICE_HISTORY(TabsPriceHistory.get().title(), PriceHistoryTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getPriceHistoryTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return null; } }, PRICE_CHANGES(TabsPriceChanges.get().title(), PriceChangesTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getPriceChangesTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return PriceChangesTableFormat.valueOf(column); } }, MATERIALS(TabsMaterials.get().materials(), MaterialsTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getMaterialsTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { try { return MaterialExtendedTableFormat.valueOf(column); } catch (IllegalArgumentException ex) { return MaterialTableFormat.valueOf(column); } } }, LOADOUTS(TabsLoadout.get().ship(), LoadoutsTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getLoadoutsTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { try { return LoadoutExtendedTableFormat.valueOf(column); } catch (IllegalArgumentException ex) { return LoadoutTableFormat.valueOf(column); } } }, MARKET_ORDERS(TabsOrders.get().market(), MarketOrdersTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getMarketOrdersTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return MarketTableFormat.valueOf(column); } }, JOURNAL(TabsJournal.get().title(), JournalTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getJournalTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return JournalTableFormat.valueOf(column); } }, TRANSACTION(TabsTransaction.get().title(), TransactionTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getTransactionsTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return TransactionTableFormat.valueOf(column); } }, INDUSTRY_JOBS(TabsJobs.get().industry(), IndustryJobsTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getIndustryJobsTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return IndustryJobTableFormat.valueOf(column); } }, INDUSTRY_SLOTS(TabsSlots.get().title(), SlotsTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getSlotsTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return SlotsTableFormat.valueOf(column); } }, OVERVIEW(TabsOverview.get().overview(), OverviewTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getOverviewTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return OverviewTableFormat.valueOf(column); } }, ROUTING(TabsRouting.get().routingTitle(), RoutingTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getRoutingTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return null; } }, STOCKPILE(TabsStockpile.get().stockpile(), StockpileTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getStockpileTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { try { return StockpileExtendedTableFormat.valueOf(column); } catch (IllegalArgumentException exception) { return StockpileTableFormat.valueOf(column); } } }, ITEMS(TabsItems.get().items(), ItemsTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getItemsTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return ItemTableFormat.valueOf(column); } }, TRACKER(TabsTracker.get().title(), TrackerTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getTrackerTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return null; } }, REPROCESSED(TabsReprocessed.get().title(), ReprocessedTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getReprocessedTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { try { return ReprocessedExtendedTableFormat.valueOf(column); } catch (IllegalArgumentException ex) { return ReprocessedTableFormat.valueOf(column); } } }, CONTRACTS(TabsContracts.get().title(), ContractsTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getContractsTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return ContractsTableFormat.valueOf(column); } }, TREE(TabsTree.get().title(), TreeTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getTreeTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return TreeTableFormat.valueOf(column); } }, SKILLS(TabsSkills.get().skills(), SkillsTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getSkillsTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return SkillsTableFormat.valueOf(column); } }, MINING_LOG(TabsMining.get().miningLog(), MiningTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getMiningTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return MiningTableFormat.valueOf(column); } }, MINING_GRAPH(TabsMining.get().miningGraph(), MiningGraphTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getMiningGraphTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return null; } }, EXTRACTIONS(TabsMining.get().extractions(), ExtractionsTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getExtractionsTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return ExtractionsTableFormat.valueOf(column); } }, LOYALTY_POINTS(TabsLoyaltyPoints.get().loyaltyPoints(), LoyaltyPointsTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getLoyaltyPointsTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return LoyaltyPointsTableFormat.valueOf(column); } }, NPC_STANDING(TabsNpcStanding.get().npcStanding(), NpcStandingTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getNpcStandingTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return NpcStandingTableFormat.valueOf(column); } }, AGENTS(TabsAgents.get().agents(), AgentsTab.NAME){ @Override public JMainTab getTool(Program program, boolean init) { return program.getAgentsTab(init); } @Override public EnumTableColumn getColumn(String column) throws IllegalArgumentException { return AgentsTableFormat.valueOf(column); } }; private final String title; private final String name; private ToolTab(String title, String name) { this.title = title; this.name = name; } public String getTitle() { return title; } public String getName() { return name; } public abstract JMainTab getTool(Program program, boolean init); public abstract EnumTableColumn getColumn(final String column) throws IllegalArgumentException; public EnumTableColumn getColumn(final String column, final String toolName) { if (toolName.equals(getName())) { try { return getColumn(column); } catch (IllegalArgumentException exception) { } } return null; } } private static final int IDLE_DELAY_MS = 10000; private static ToolLoader loader; private static double max; private static Map toolTabs; private final Object SYNC_LOCK = new Object(); private final Program program; private final Set tools = new HashSet<>(); private boolean ok = false; private Timer timer; private String tool = null; private Progress progress = null; private Component lastFocusOwner; private ToolLoader(Program program) { this.program = program; tools.addAll(getToolTitles(program)); tools.removeAll(Settings.get().getShowTools()); if (tools.isEmpty()) { stopBackgroundToolLoading(); return; } timer = new Timer(IDLE_DELAY_MS, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ok = true; openTool(); } }); Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.MOUSE_MOTION_EVENT_MASK); KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener("permanentFocusOwner", this); timer.start(); } public static synchronized Map getTools(Program program) { if (toolTabs == null) { toolTabs = new HashMap<>(); for (ToolTab toolTab : ToolTab.values()) { toolTabs.put(toolTab.getTitle(), toolTab); } } return toolTabs; } private static void openTool(Program program, String title) { ToolTab tool = getTools(program).get(title); if (tool != null) { program.getMainWindow().addTab(tool.getTool(program, true), false); } } private static void initTool(Program program, String title) { ToolTab tool = getTools(program).get(title); if (tool != null) { tool.getTool(program, true); } } public static void initTools(Program program, Collection titles) { int index = 0; int size = titles.size(); for (String title : titles) { initTool(program, title); index++; setProgress(index, size); } } public static void initAllTools(Program program) { SplashUpdater.setProgress(52); Collection values = getTools(program).values(); int index = 0; int size = values.size(); for (ToolTab tool : values) { tool.getTool(program, true); index++; setProgress(index, size); } } private static void setProgress(final float done, final float end) { setProgress(done, end, 53, 84); } private static void setProgress(final float done, final float end, final int minimum, final int maximum) { int progress = Math.round(((done / end) * (maximum - minimum)) + minimum); if (progress > 100) { progress = 100; } else if (progress < 0) { progress = 0; } SplashUpdater.setProgress(progress); } public static void openTools(Program program, Collection titles) { for (String title : titles) { openTool(program, title); } } public static HashSet getToolTitles(Program program) { return new HashSet<>(getTools(program).keySet()); } public static synchronized void init(Program program) { Set tools = new HashSet<>(); tools.addAll(getToolTitles(program)); tools.removeAll(Settings.get().getShowTools()); max = tools.size(); } public static synchronized void startBackgroundToolLoading(Program program) { if (loader == null) { loader = new ToolLoader(program); } } public static synchronized void stopBackgroundToolLoading() { if (loader != null) { loader.done(); loader = null; } } private void openTool() { Window currentWindow = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); boolean window = currentWindow == null || currentWindow.equals(program.getMainWindow().getFrame()); if (ok && window && tool == null && !tools.isEmpty()) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { openToolInner(); } }); } else { synchronized (SYNC_LOCK) { if (timer != null) { timer.start(); } } } } private void openToolInner() { synchronized (SYNC_LOCK) { if (timer != null) { timer.stop(); } } addProgress(); tool = tools.iterator().next(); tools.remove(tool); initTool(program, tool); tool = null; progress.setValue((int)((max - tools.size()) / max * 100.0)); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { openTool(); } }); if (tools.isEmpty()) { stopBackgroundToolLoading(); removeProgress(); } } private void addProgress() { if (progress == null) { progress = program.getStatusPanel().addProgress(StatusPanel.UpdateType.TOOLS, new StatusPanel.ProgressControl() { @Override public boolean isAuto() { return true; } @Override public void show() { } @Override public void cancel() { } @Override public void setPause(boolean pause) { } }); progress.setVisible(true); } } private void removeProgress() { program.getStatusPanel().removeProgress(progress); progress = null; } private void done() { removeProgress(); KeyboardFocusManager.getCurrentKeyboardFocusManager().removePropertyChangeListener("permanentFocusOwner", this); Toolkit.getDefaultToolkit().removeAWTEventListener(this); removeListeners(); synchronized (SYNC_LOCK) { timer.stop(); timer = null; } } private void updateListeners() { Component currentFocusOwner = program.getMainWindow().getFrame().getFocusOwner(); if (lastFocusOwner != null && (currentFocusOwner == null || !lastFocusOwner.equals(currentFocusOwner))) { removeListeners(); } if (currentFocusOwner != null && !tools.isEmpty()) { addListeners(); } } private void removeListeners() { if (lastFocusOwner != null) { lastFocusOwner.removeKeyListener(this); lastFocusOwner.removeMouseListener(this); } if (lastFocusOwner instanceof JComboBox) { ((JComboBox)lastFocusOwner).removeActionListener(this); } if (lastFocusOwner instanceof AbstractButton) { ((AbstractButton)lastFocusOwner).removeActionListener(this); } } private void addListeners() { Component currentFocusOwner = program.getMainWindow().getFrame().getFocusOwner(); lastFocusOwner = currentFocusOwner; lastFocusOwner.addMouseListener(this); lastFocusOwner.addKeyListener(this); if (lastFocusOwner instanceof JComboBox) { ((JComboBox)lastFocusOwner).addActionListener(this); } if (lastFocusOwner instanceof AbstractButton) { ((AbstractButton)lastFocusOwner).addActionListener(this); } } private void restart() { synchronized (SYNC_LOCK) { if (timer != null) { timer.stop(); timer.start(); } } removeProgress(); ok = false; } @Override public void eventDispatched(AWTEvent event) { restart(); } @Override public void mouseWheelMoved(MouseWheelEvent e) { restart(); } @Override public void mouseClicked(MouseEvent e) { restart(); } @Override public void mousePressed(MouseEvent e) { restart(); } @Override public void mouseReleased(MouseEvent e) { restart(); } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void actionPerformed(final ActionEvent e) { restart(); } @Override public void keyTyped(KeyEvent e) { restart(); } @Override public void keyPressed(KeyEvent e) { restart(); } @Override public void keyReleased(KeyEvent e) { restart(); } @Override public void propertyChange(PropertyChangeEvent evt) { updateListeners(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/accounts/AbstractOwner.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.accounts; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.my.MyAccountBalance; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyExtraction; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.api.my.MyShip; import net.nikr.eve.jeveasset.data.api.my.MySkill; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.api.raw.RawBlueprint; import net.nikr.eve.jeveasset.data.api.raw.RawClone; import net.nikr.eve.jeveasset.data.settings.Settings; public abstract class AbstractOwner implements OwnerType { private List accountBalances = new ArrayList<>(); private Set marketOrders = new HashSet<>(); private Set transactions = new HashSet<>(); private Set journal = new HashSet<>(); private Set industryJobs = new HashSet<>(); private Map> contracts = new HashMap<>(); private List assets = new ArrayList<>(); private Map blueprints = new HashMap<>(); private Map walletDivisions = new HashMap<>(); private Map assetDivisions = new HashMap<>(); private List skills = new ArrayList<>(); private List clones = new ArrayList<>(); private Set mining = new HashSet<>(); private Set extractions = new HashSet<>(); private Set loyaltyPoints = new HashSet<>(); private Set npcStanding = new HashSet<>(); private Long totalSkillPoints = null; private Integer unallocatedSkillPoints = null; private final String accountID; private String ownerName; private String corporationName = null; private long ownerID; private boolean showOwner = true; private boolean invalid = false; private MyShip activeShip; private Date assetLastUpdate = null; private Date assetNextUpdate = Settings.getNow(); private Date balanceLastUpdate = null; private Date balanceNextUpdate = Settings.getNow(); private Date marketOrdersNextUpdate = Settings.getNow(); private Date journalNextUpdate = Settings.getNow(); private Date transactionsNextUpdate = Settings.getNow(); private Date industryJobsNextUpdate = Settings.getNow(); private Date contractsNextUpdate = Settings.getNow(); private Date locationsNextUpdate = Settings.getNow(); private Date blueprintsNextUpdate = Settings.getNow(); private Date skillsNextUpdate = Settings.getNow(); private Date loyaltyPointsNextUpdate = Settings.getNow(); private Date npcStandingNextUpdate = Settings.getNow(); private Date miningNextUpdate = Settings.getNow(); public AbstractOwner(String uniqueID) { this.accountID = uniqueID; } public AbstractOwner(AbstractOwner abstractOwner) { accountID = abstractOwner.accountID; accountBalances.addAll(abstractOwner.accountBalances); marketOrders.addAll(abstractOwner.marketOrders); transactions.addAll(abstractOwner.transactions); journal.addAll(abstractOwner.journal); industryJobs.addAll(abstractOwner.industryJobs); contracts.putAll(abstractOwner.contracts); assets.addAll(abstractOwner.assets); blueprints.putAll(abstractOwner.blueprints); walletDivisions.putAll(abstractOwner.walletDivisions); assetDivisions.putAll(abstractOwner.assetDivisions); skills.addAll(abstractOwner.skills); loyaltyPoints.addAll(abstractOwner.loyaltyPoints); npcStanding.addAll(abstractOwner.npcStanding); clones.addAll(abstractOwner.clones); mining.addAll(abstractOwner.mining); extractions.addAll(abstractOwner.extractions); this.totalSkillPoints = abstractOwner.totalSkillPoints; this.unallocatedSkillPoints = abstractOwner.unallocatedSkillPoints; this.ownerName = abstractOwner.ownerName; this.corporationName = abstractOwner.corporationName; this.ownerID = abstractOwner.ownerID; this.showOwner = abstractOwner.showOwner; this.invalid = abstractOwner.invalid; this.activeShip = abstractOwner.activeShip; this.assetLastUpdate = abstractOwner.assetLastUpdate; this.assetNextUpdate = abstractOwner.assetNextUpdate; this.balanceLastUpdate = abstractOwner.balanceLastUpdate; this.balanceNextUpdate = abstractOwner.balanceNextUpdate; this.marketOrdersNextUpdate = abstractOwner.marketOrdersNextUpdate; this.journalNextUpdate = abstractOwner.journalNextUpdate; this.transactionsNextUpdate = abstractOwner.transactionsNextUpdate; this.industryJobsNextUpdate = abstractOwner.industryJobsNextUpdate; this.contractsNextUpdate = abstractOwner.contractsNextUpdate; this.locationsNextUpdate = abstractOwner.locationsNextUpdate; this.blueprintsNextUpdate = abstractOwner.blueprintsNextUpdate; this.skillsNextUpdate = abstractOwner.skillsNextUpdate; this.loyaltyPointsNextUpdate = abstractOwner.loyaltyPointsNextUpdate; this.npcStandingNextUpdate = abstractOwner.npcStandingNextUpdate; this.miningNextUpdate = abstractOwner.miningNextUpdate; } @Override public String getAccountID() { return accountID; } @Override public synchronized void setAssetNextUpdate(final Date nextUpdate) { this.assetNextUpdate = nextUpdate; } @Override public synchronized void setBalanceNextUpdate(final Date balanceNextUpdate) { this.balanceNextUpdate = balanceNextUpdate; } @Override public synchronized void setBlueprintsNextUpdate(final Date blueprintsNextUpdate) { this.blueprintsNextUpdate = blueprintsNextUpdate; } @Override public synchronized void setContractsNextUpdate(final Date contractsNextUpdate) { this.contractsNextUpdate = contractsNextUpdate; } @Override public synchronized void setIndustryJobsNextUpdate(final Date industryJobsNextUpdate) { this.industryJobsNextUpdate = industryJobsNextUpdate; } @Override public synchronized void setLocationsNextUpdate(final Date locationsNextUpdate) { this.locationsNextUpdate = locationsNextUpdate; } @Override public synchronized void setMarketOrdersNextUpdate(final Date marketOrdersNextUpdate) { this.marketOrdersNextUpdate = marketOrdersNextUpdate; } @Override public synchronized void setJournalNextUpdate(final Date journalNextUpdate) { this.journalNextUpdate = journalNextUpdate; } @Override public void setSkillsNextUpdate(Date skillsNextUpdate) { this.skillsNextUpdate = skillsNextUpdate; } @Override public Date getLoyaltyPointsNextUpdate() { return loyaltyPointsNextUpdate; } @Override public Date getNpcStandingNextUpdate() { return npcStandingNextUpdate; } @Override public synchronized void setTransactionsNextUpdate(final Date transactionsNextUpdate) { this.transactionsNextUpdate = transactionsNextUpdate; } @Override public synchronized Date getTransactionsNextUpdate() { return transactionsNextUpdate; } @Override public synchronized Date getAssetNextUpdate() { return assetNextUpdate; } @Override public synchronized Date getBalanceNextUpdate() { return balanceNextUpdate; } @Override public synchronized Date getBlueprintsNextUpdate() { return blueprintsNextUpdate; } @Override public synchronized Date getContractsNextUpdate() { return contractsNextUpdate; } @Override public synchronized Date getIndustryJobsNextUpdate() { return industryJobsNextUpdate; } @Override public synchronized Date getLocationsNextUpdate() { return locationsNextUpdate; } @Override public synchronized Date getMarketOrdersNextUpdate() { return marketOrdersNextUpdate; } @Override public synchronized Date getJournalNextUpdate() { return journalNextUpdate; } @Override public Date getSkillsNextUpdate() { return skillsNextUpdate; } @Override public void setLoyaltyPointsNextUpdate(Date loyaltyPointsNextUpdate) { this.loyaltyPointsNextUpdate = loyaltyPointsNextUpdate; } @Override public void setNpcStandingNextUpdate(Date npcStandingNextUpdate) { this.npcStandingNextUpdate = npcStandingNextUpdate; } @Override public abstract int hashCode(); @Override public abstract boolean equals(Object obj); @Override public final void setOwnerName(final String ownerName) { this.ownerName = ownerName; } @Override public final void setAssetLastUpdate(final Date assetLastUpdate) { this.assetLastUpdate = assetLastUpdate; } @Override public final void setBalanceLastUpdate(final Date balanceLastUpdate) { this.balanceLastUpdate = balanceLastUpdate; } @Override public final void setOwnerID(final long ownerID) { this.ownerID = ownerID; } @Override public final String toString() { return getOwnerName(); } @Override public final boolean isCharacter() { return !isCorporation(); } @Override public final boolean isExpired() { if (getExpire() == null) { return false; } else { return getExpire().before(new Date()); } } @Override public final String getOwnerName() { if (ownerName == null || ownerName.isEmpty()) { return "Owner #" + getOwnerID(); } else { return ownerName; } } @Override public final boolean isShowOwner() { return showOwner; } @Override public synchronized boolean isInvalid() { return invalid; } @Override public final Date getAssetLastUpdate() { return assetLastUpdate; } @Override public final Date getBalanceLastUpdate() { return balanceLastUpdate; } @Override public final long getOwnerID() { return ownerID; } @Override public String getCorporationName() { return corporationName; } @Override public MyShip getActiveShip() { return activeShip; } @Override public void setCorporationName(String corporationName) { this.corporationName = corporationName; } @Override public final List getAccountBalances() { return accountBalances; } @Override public synchronized final Set getMarketOrders() { return marketOrders; } @Override public Date getMiningNextUpdate() { return miningNextUpdate; } @Override public final Set getTransactions() { return transactions; } @Override public final Set getJournal() { return journal; } @Override public final Set getIndustryJobs() { return industryJobs; } @Override public final Map> getContracts() { return contracts; } @Override public final synchronized List getAssets() { return assets; } public final synchronized void addAsset(MyAsset asset) { assets.add(asset); } public final synchronized void removeAssets(List remove) { assets.removeAll(remove); } @Override public final Map getBlueprints() { return blueprints; } @Override public List getSkills() { return skills; } @Override public Set getLoyaltyPoints() { return loyaltyPoints; } @Override public Set getNpcStanding() { return npcStanding; } @Override public List getClones() { return clones; } @Override public Set getMining() { return mining; } @Override public Set getExtractions() { return extractions; } @Override public Long getTotalSkillPoints() { return totalSkillPoints; } @Override public Integer getUnallocatedSkillPoints() { return unallocatedSkillPoints; } @Override public final void setShowOwner(final boolean showOwner) { this.showOwner = showOwner; } @Override public synchronized void setInvalid(boolean invalid) { this.invalid = invalid; } @Override public final void setBlueprints(final Map blueprints) { this.blueprints = blueprints; } @Override public final void setIndustryJobs(final Set industryJobs) { this.industryJobs = industryJobs; } @Override public final void setTransactions(final Set transactions) { this.transactions = transactions; } @Override public final void setJournal(final Set journal) { this.journal = journal; } @Override public final void setMarketOrders(final Set marketOrders) { this.marketOrders = marketOrders; } @Override public void setMiningNextUpdate(Date miningNextUpdate) { this.miningNextUpdate = miningNextUpdate; } @Override public final void setContracts(final Map> contracts) { this.contracts = contracts; } @Override public final synchronized void setAssets(final List assets) { this.assets = assets; } @Override public final void setAccountBalances(final List accountBalances) { this.accountBalances = accountBalances; } @Override public Map getWalletDivisions() { return walletDivisions; } @Override public void setWalletDivisions(Map walletDivisions) { this.walletDivisions = walletDivisions; } @Override public Map getAssetDivisions() { return assetDivisions; } @Override public void setAssetDivisions(Map assetDivisions) { this.assetDivisions = assetDivisions; } @Override public void setSkills(List skills) { this.skills = skills; } @Override public void setLoyaltyPoints(Set loyaltyPoints) { this.loyaltyPoints = loyaltyPoints; } @Override public void setNpcStanding(Set npcStanding) { this.npcStanding = npcStanding; } @Override public void setClones(List clones) { this.clones = clones; } @Override public void setMining(Set mining) { this.mining = mining; } @Override public void setExtractions(Set extractions) { this.extractions = extractions; } @Override public void setTotalSkillPoints(Long totalSkillPoints) { this.totalSkillPoints = totalSkillPoints; } @Override public void setUnallocatedSkillPoints(Integer unallocatedSkillPoints) { this.unallocatedSkillPoints = unallocatedSkillPoints; } @Override public void setActiveShip(MyShip activeShip) { this.activeShip = activeShip; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/accounts/ApiType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.accounts; public enum ApiType { ESI } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/accounts/EsiOwner.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.accounts; import java.util.Arrays; import java.util.Date; import java.util.EnumSet; import java.util.HashSet; import java.util.Objects; import java.util.Set; import java.util.UUID; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.io.esi.AbstractEsiGetter; import net.nikr.eve.jeveasset.io.esi.EsiCallbackURL; import net.nikr.eve.jeveasset.io.esi.EsiScopes; import net.troja.eve.esi.ApiClient; import net.troja.eve.esi.ApiClientBuilder; import net.troja.eve.esi.api.AssetsApi; import net.troja.eve.esi.api.CharacterApi; import net.troja.eve.esi.api.ClonesApi; import net.troja.eve.esi.api.ContractsApi; import net.troja.eve.esi.api.CorporationApi; import net.troja.eve.esi.api.IndustryApi; import net.troja.eve.esi.api.LocationApi; import net.troja.eve.esi.api.LoyaltyApi; import net.troja.eve.esi.api.MarketApi; import net.troja.eve.esi.api.PlanetaryInteractionApi; import net.troja.eve.esi.api.SkillsApi; import net.troja.eve.esi.api.UniverseApi; import net.troja.eve.esi.api.UserInterfaceApi; import net.troja.eve.esi.api.WalletApi; import net.troja.eve.esi.auth.OAuth; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; public class EsiOwner extends AbstractOwner implements OwnerType { private final ApiClient apiClient = new ApiClientBuilder().okHttpClient(AbstractEsiGetter.getHttpClient()).build(); private final MarketApi marketApi = new MarketApi(apiClient); private final IndustryApi industryApi = new IndustryApi(apiClient); private final CharacterApi characterApi = new CharacterApi(apiClient); private final ClonesApi clonesApi = new ClonesApi(apiClient); private final AssetsApi assetsApi = new AssetsApi(apiClient); private final WalletApi walletApi = new WalletApi(apiClient); private final UniverseApi universeApi = new UniverseApi(apiClient); private final ContractsApi contractsApi = new ContractsApi(apiClient); private final CorporationApi corporationApi = new CorporationApi(apiClient); private final LocationApi locationApi = new LocationApi(apiClient); private final PlanetaryInteractionApi planetaryInteractionApi = new PlanetaryInteractionApi(apiClient); private final UserInterfaceApi userInterfaceApi = new UserInterfaceApi(apiClient); private final SkillsApi skillsApi = new SkillsApi(apiClient); private final LoyaltyApi loyaltyApi = new LoyaltyApi(apiClient); private String accountName; private Set scopes = new HashSet<>(); private Date structuresNextUpdate = Settings.getNow(); private Date accountNextUpdate = Settings.getNow(); private EsiCallbackURL callbackURL; private Set roles = EnumSet.noneOf(RolesEnum.class); public static EsiOwner create() { return new EsiOwner(); } private EsiOwner() { super(UUID.randomUUID().toString()); } public EsiOwner(String uniqueID) { super(uniqueID); } public EsiOwner(EsiOwner esiOwner) { super(esiOwner); this.accountName = esiOwner.accountName; this.scopes = esiOwner.scopes; this.structuresNextUpdate = esiOwner.structuresNextUpdate; this.accountNextUpdate = esiOwner.accountNextUpdate; this.roles = esiOwner.roles; setAuth(esiOwner.callbackURL, esiOwner.getOAuth().getRefreshToken(), esiOwner.getOAuth().getAccessToken()); } public synchronized String getRefreshToken() { return getOAuth().getRefreshToken(); } public Set getScopes() { return scopes; } public void setScopes(String scopes) { this.scopes = new HashSet<>(Arrays.asList(scopes.split(" "))); } public final void setScopes(Set scopes) { this.scopes = new HashSet<>(scopes); } public synchronized Date getStructuresNextUpdate() { return structuresNextUpdate; } public synchronized void setStructuresNextUpdate(Date structuresNextUpdate) { this.structuresNextUpdate = structuresNextUpdate; } public Date getAccountNextUpdate() { return accountNextUpdate; } public void setAccountNextUpdate(Date accountNextUpdate) { this.accountNextUpdate = accountNextUpdate; } public EsiCallbackURL getCallbackURL() { return callbackURL; } public Set getRoles() { return roles; } public void setRoles(Set roles) { this.roles = roles; } @Override public boolean isCorporation() { return isRoles(); } @Override public Date getExpire() { return null; } @Override public String getComparator() { return "esi" + getAccountName() + getRefreshToken(); } @Override public String getAccountName() { if (accountName == null || accountName.isEmpty()) { accountName = getOwnerName(); } return accountName; } @Override public ApiType getAccountAPI() { return ApiType.ESI; } @Override public void setResetAccountName() { accountName = getOwnerName(); } @Override public void setAccountName(String accountName) { this.accountName = accountName; } @Override public boolean isAssetList() { if (isCorporation()) { return EsiScopes.CORPORATION_ASSETS.isInScope(scopes) && roles.contains(RolesEnum.DIRECTOR); } else { return EsiScopes.CHARACTER_ASSETS.isInScope(scopes); } } private boolean isWallet() { if (isCorporation()) { return EsiScopes.CORPORATION_WALLET.isInScope(scopes) && (roles.contains(RolesEnum.JUNIOR_ACCOUNTANT) || roles.contains(RolesEnum.ACCOUNTANT) || roles.contains(RolesEnum.DIRECTOR)); } else { return EsiScopes.CHARACTER_WALLET.isInScope(scopes); } } @Override public boolean isClones() { if (isCorporation()) { return false; //Character Endpoint } else { return EsiScopes.CHARACTER_CLONE.isInScope(scopes); } } @Override public boolean isImplants() { if (isCorporation()) { return false; //Character Endpoint } else { return EsiScopes.CHARACTER_IMPLANT.isInScope(scopes); } } @Override public boolean isAccountBalance() { return isWallet(); } @Override public boolean isBlueprints() { if (isCorporation()) { return EsiScopes.CORPORATION_BLUEPRINTS.isInScope(scopes) && roles.contains(RolesEnum.DIRECTOR); } else { return EsiScopes.CHARACTER_BLUEPRINTS.isInScope(scopes); } } @Override public boolean isDivisions() { if (isCorporation()) { return EsiScopes.CORPORATION_DIVISIONS.isInScope(scopes) && roles.contains(RolesEnum.DIRECTOR); } else { return false; } } @Override public boolean isIndustryJobs() { if (isCorporation()) { return EsiScopes.CORPORATION_INDUSTRY_JOBS.isInScope(scopes) && (roles.contains(RolesEnum.FACTORY_MANAGER) || roles.contains(RolesEnum.DIRECTOR)); } else { return EsiScopes.CHARACTER_INDUSTRY_JOBS.isInScope(scopes); } } @Override public boolean isMarketOrders() { if (isCorporation()) { return EsiScopes.CORPORATION_MARKET_ORDERS.isInScope(scopes) && (roles.contains(RolesEnum.ACCOUNTANT) || roles.contains(RolesEnum.TRADER) || roles.contains(RolesEnum.DIRECTOR)); } else { return EsiScopes.CHARACTER_MARKET_ORDERS.isInScope(scopes); } } @Override public boolean isPlanetaryInteraction() { if (isCorporation()) { return false; //Character Endpoint } else { return EsiScopes.CHARACTER_PLANETARY_INTERACTION.isInScope(scopes); } } @Override public boolean isTransactions() { return isWallet(); } @Override public boolean isJournal() { return isWallet(); } @Override public boolean isContracts() { if (isCorporation()) { return EsiScopes.CORPORATION_CONTRACTS.isInScope(scopes); } else { return EsiScopes.CHARACTER_CONTRACTS.isInScope(scopes); } } @Override public boolean isLocations() { return isAssetList(); } @Override public boolean isStructures() { if (isCorporation()) { return false; //Character Endpoint } else { return EsiScopes.CHARACTER_STRUCTURES.isInScope(scopes); } } @Override public boolean isMarketStructures() { if (isCorporation()) { return false; //Character Endpoint } else { return EsiScopes.CHARACTER_MARKET_STRUCTURES.isInScope(scopes); } } @Override public boolean isShip() { if (isCorporation()) { return false; //Character Endpoint } else { return EsiScopes.CHARACTER_SHIP_TYPE.isInScope(scopes) && EsiScopes.CHARACTER_SHIP_LOCATION.isInScope(scopes); } } @Override public boolean isOpenWindows() { if (isCorporation()) { return false; //Character Endpoint } else { return EsiScopes.CHARACTER_OPEN_WINDOWS.isInScope(scopes); } } @Override public boolean isAutopilot() { if (isCorporation()) { return false; //Character Endpoint } else { return EsiScopes.CHARACTER_AUTOPILOT.isInScope(scopes); } } @Override public boolean isPrivilegesLimited() { return EsiScopes.isPrivilegesLimited(isCorporation(), scopes); } @Override public boolean isPrivilegesInvalid() { return EsiScopes.isPrivilegesInvalid(isCorporation(), scopes); } @Override public boolean isSkills() { return EsiScopes.CHARACTER_SKILLS.isInScope(scopes); } @Override public boolean isLoyaltyPoints() { return EsiScopes.CHARACTER_LOYALTY_POINTS.isInScope(scopes); } @Override public boolean isNpcStanding() { if (isCorporation()) { return EsiScopes.CORPORATION_NPC_STANDING.isInScope(scopes); } else { return EsiScopes.CHARACTER_NPC_STANDING.isInScope(scopes); } } @Override public boolean isMining() { if (isCorporation()) { return EsiScopes.CORPORATION_MINING.isInScope(scopes) && ((roles.contains(RolesEnum.ACCOUNTANT) && roles.contains(RolesEnum.STATION_MANAGER)) || roles.contains(RolesEnum.DIRECTOR)); } else { return EsiScopes.CHARACTER_MINING.isInScope(scopes); } } public boolean isRoles() { return EsiScopes.CORPORATION_ROLES.isInScope(scopes); } public final void updateAuth(EsiOwner esiOwner) { OAuth oAuth = esiOwner.getOAuth(); setAuth(esiOwner.getCallbackURL(), oAuth.getRefreshToken(), oAuth.getAccessToken()); setScopes(esiOwner.getScopes()); //Is bound to the access token, so should be updated here setInvalid(false); } public synchronized final void setAuth(EsiCallbackURL callbackURL, String refreshToken, String accessToken) { if (callbackURL != null) { this.callbackURL = callbackURL; } if (callbackURL != null && refreshToken != null) { getOAuth().setAuth(callbackURL.getA(), refreshToken); getOAuth().setAccessToken(accessToken); } } private OAuth getOAuth() { return (OAuth) apiClient.getAuthentication(ApiClientBuilder.AUTHENTICATION); } public synchronized ApiClient getApiClient() { return apiClient; } public MarketApi getMarketApiAuth() { return marketApi; } public IndustryApi getIndustryApiAuth() { return industryApi; } public CharacterApi getCharacterApiAuth() { return characterApi; } public AssetsApi getAssetsApiAuth() { return assetsApi; } public WalletApi getWalletApiAuth() { return walletApi; } public UniverseApi getUniverseApiAuth() { return universeApi; } public ClonesApi getClonesApiAuth() { return clonesApi; } public ContractsApi getContractsApiAuth() { return contractsApi; } public CorporationApi getCorporationApiAuth() { return corporationApi; } public LocationApi getLocationApiAuth() { return locationApi; } public UserInterfaceApi getUserInterfaceApiAuth() { return userInterfaceApi; } public PlanetaryInteractionApi getPlanetaryInteractionApiAuth() { return planetaryInteractionApi; } public SkillsApi getSkillsApiAuth() { return skillsApi; } public LoyaltyApi getLoyaltyApiAuth() { return loyaltyApi; } @Override public int hashCode() { int hash = 5; hash = 61 * hash + Objects.hashCode(this.getRefreshToken()); hash = 61 * hash + Objects.hashCode(this.scopes); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final EsiOwner other = (EsiOwner) obj; if (!Objects.equals(this.getRefreshToken(), other.getRefreshToken())) { return false; } if (!Objects.equals(this.scopes, other.scopes)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/accounts/OwnerType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.accounts; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.my.MyAccountBalance; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyExtraction; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.api.my.MyShip; import net.nikr.eve.jeveasset.data.api.my.MySkill; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.api.raw.RawBlueprint; import net.nikr.eve.jeveasset.data.api.raw.RawClone; public interface OwnerType extends SimpleOwner { //Info public String getAccountID(); public String getCorporationName(); public void setOwnerName(final String ownerName); public void setCorporationName(String corporationName); public void setOwnerID(final long ownerID); public boolean isShowOwner(); public Date getExpire(); public String getComparator(); public String getAccountName(); public boolean isExpired(); public boolean isInvalid(); public ApiType getAccountAPI(); public void setShowOwner(final boolean showOwner); public void setInvalid(boolean invalid); public void setResetAccountName(); public void setAccountName(final String accountName); public void setActiveShip(MyShip activeShip); //Data public List getAccountBalances(); public Set getMarketOrders(); public Set getTransactions(); public Set getJournal(); public Set getIndustryJobs(); public Map> getContracts(); public List getAssets(); public Map getBlueprints(); public Map getWalletDivisions(); public List getSkills(); public Long getTotalSkillPoints(); public Integer getUnallocatedSkillPoints(); public Set getMining(); public Set getExtractions(); public Set getLoyaltyPoints(); public Set getNpcStanding(); public List getClones(); public void setBlueprints(final Map blueprints); public void setIndustryJobs(final Set industryJobs); public void setTransactions(final Set transactions); public void setJournal(final Set journal); public void setMarketOrders(final Set marketOrders); public void setContracts(final Map> contracts); public void setAssets(final List assets); public void setAccountBalances(final List accountBalances); public void setWalletDivisions(final Map walletDivisions); public void setAssetDivisions(final Map assetDivisions); public void setSkills(final List skills); public void setTotalSkillPoints(final Long totalSkillPoints); public void setUnallocatedSkillPoints(final Integer unallocatedSkillPoints); public void setMining(Set mining); public void setExtractions(Set extractions); public void setClones(List clones); public void setLoyaltyPoints(Set loyaltyPoints); public void setNpcStanding(Set npcStanding); //Account Mask public boolean isCharacter(); public boolean isAssetList(); public boolean isClones(); public boolean isImplants(); public boolean isAccountBalance(); public boolean isIndustryJobs(); public boolean isMarketOrders(); public boolean isTransactions(); public boolean isJournal(); public boolean isContracts(); public boolean isLocations(); public boolean isStructures(); public boolean isMarketStructures(); public boolean isBlueprints(); public boolean isShip(); public boolean isOpenWindows(); public boolean isPlanetaryInteraction(); public boolean isAutopilot(); public boolean isDivisions(); public boolean isPrivilegesLimited(); public boolean isPrivilegesInvalid(); public boolean isSkills(); public boolean isMining(); public boolean isLoyaltyPoints(); public boolean isNpcStanding(); //Last Update public Date getAssetLastUpdate(); public Date getBalanceLastUpdate(); public void setAssetLastUpdate(final Date assetLastUpdate); public void setBalanceLastUpdate(final Date balanceLastUpdate); //Next Update public void setAssetNextUpdate(final Date nextUpdate); public void setBalanceNextUpdate(final Date balanceNextUpdate); public void setBlueprintsNextUpdate(Date blueprintsNextUpdate); public void setContractsNextUpdate(final Date contractsNextUpdate); public void setIndustryJobsNextUpdate(final Date industryJobsNextUpdate); public void setLocationsNextUpdate(final Date locationsNextUpdate); public void setMarketOrdersNextUpdate(final Date marketOrdersNextUpdate); public void setJournalNextUpdate(final Date journalNextUpdate); public void setTransactionsNextUpdate(final Date transactionsNextUpdate); public void setSkillsNextUpdate(final Date skillsNextUpdate); public void setLoyaltyPointsNextUpdate(final Date loyaltyPointsNextUpdate); public void setNpcStandingNextUpdate(Date npcStandingNextUpdate); public void setMiningNextUpdate(final Date miningNextUpdate); public Date getTransactionsNextUpdate(); public Date getAssetNextUpdate(); public Date getBalanceNextUpdate(); public Date getBlueprintsNextUpdate(); public Date getContractsNextUpdate(); public Date getIndustryJobsNextUpdate(); public Date getLocationsNextUpdate(); public Date getMarketOrdersNextUpdate(); public Date getJournalNextUpdate(); public Date getSkillsNextUpdate(); public Date getLoyaltyPointsNextUpdate(); public Date getNpcStandingNextUpdate(); public Date getMiningNextUpdate(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/accounts/SimpleOwner.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.accounts; import java.util.HashMap; import java.util.Map; import javax.annotation.Nullable; import net.nikr.eve.jeveasset.data.api.my.MyShip; public interface SimpleOwner extends Comparable { public long getOwnerID(); public String getOwnerName(); public boolean isCorporation(); default Map getAssetDivisions() { return new HashMap<>(); } @Nullable default MyShip getActiveShip() { return null; } @Override default int compareTo(final SimpleOwner o) { return this.getOwnerName().compareToIgnoreCase(o.getOwnerName()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MyAccountBalance.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.raw.RawAccountBalance; public class MyAccountBalance extends RawAccountBalance { private final OwnerType owner; public MyAccountBalance(RawAccountBalance rawAccountBalance, OwnerType owner) { super(rawAccountBalance); this.owner = owner; } public String getOwnerName() { return owner.getOwnerName(); } public long getOwnerID() { return owner.getOwnerID(); } public boolean isCorporation() { return owner.isCorporation(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MyAsset.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.SimpleOwner; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob.IndustryActivity; import net.nikr.eve.jeveasset.data.api.raw.RawAsset; import net.nikr.eve.jeveasset.data.api.raw.RawClone; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.MarketPriceData; import net.nikr.eve.jeveasset.data.settings.PriceData; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.data.settings.tag.TagID; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.data.settings.types.BlueprintType; import net.nikr.eve.jeveasset.data.settings.types.EditableLocationType; import net.nikr.eve.jeveasset.data.settings.types.EditablePriceType; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.data.settings.types.OwnersType; import net.nikr.eve.jeveasset.data.settings.types.TagsType; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.InfoItem; import net.nikr.eve.jeveasset.gui.shared.table.containers.AssetContainer; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetsTab; import net.nikr.eve.jeveasset.i18n.DataModelAsset; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class MyAsset extends RawAsset implements Comparable, InfoItem, ItemType, BlueprintType, EditablePriceType, TagsType, EditableLocationType, OwnersType { //Static values (set by constructor) private final List assets = new ArrayList<>(); private final RawAsset rawAsset; private final Item item; private final SimpleOwner owner; private final List parents; private final Set owners; private final boolean generated; private final long count; private final float volume; //Static values cache (set by constructor) private String typeName; private String flagName; private boolean bpo; private boolean bpc; //Dynamic values private String name; private String itemName = null; private AssetContainer container = new AssetContainer(); private PriceData priceData = new PriceData(); private UserItem userPrice; private long typeCount = 0; private MarketPriceData marketPriceData; private Date added; private double price; private Tags tags; private MyBlueprint blueprint; private MyLocation location; //Dynamic values cache private boolean userNameSet = false; private boolean eveNameSet = false; private boolean userPriceSet = false; protected MyAsset(MyAsset asset) { this(asset.rawAsset, asset.item, asset.owner, asset.parents); this.name = asset.name; this.itemName = asset.itemName; this.container = asset.container; this.priceData = asset.priceData; this.userPrice = asset.userPrice; this.typeCount = asset.typeCount; this.marketPriceData = asset.marketPriceData; this.added = asset.added; this.price = asset.price; this.tags = asset.tags; this.blueprint = asset.blueprint; this.location = asset.location; this.userNameSet = asset.userNameSet; this.eveNameSet = asset.eveNameSet; this.userPriceSet = asset.userPriceSet; } public MyAsset(MyLocation location) { super(RawAsset.create()); this.rawAsset = RawAsset.create(); this.item = new Item(0); this.owner = null; this.parents = new ArrayList<>(); this.location = location; this.owners = new HashSet<>(); this.generated = true; if (getQuantity() == null || getQuantity() <= 0) { this.count = 1; } else { this.count = getQuantity(); } this.volume = 0; this.flagName = ApiIdConverter.getFlagName(ApiIdConverter.getFlag(0)); setItemID(0L); setItemFlag(ApiIdConverter.getFlag(0)); setLocationID(location.getLocationID()); } public MyAsset(final RawAsset rawAsset, final Item item, final SimpleOwner owner, final List parents) { super(rawAsset); this.rawAsset = rawAsset; this.item = item; this.owner = owner; this.parents = parents; this.volume = ApiIdConverter.getVolume(item, !rawAsset.isSingleton()); this.typeName = item.getTypeName(); this.name = item.getTypeName(); this.itemName = null; this.owners = Collections.singleton(owner.getOwnerID()); this.generated = getFlag().equals(General.get().marketOrderSellFlag()) //market sell orders || getFlag().equals(General.get().marketOrderBuyFlag()) //market buy orders || getFlag().equals(General.get().contractIncluded()) //contracts included || getFlag().equals(General.get().contractExcluded()) //contracts excluded || getFlag().equals(IndustryActivity.ACTIVITY_MANUFACTURING.toString()) //industry job manufacturing || getFlag().equals(IndustryActivity.ACTIVITY_REACTIONS.toString()) //industry job reactions || getFlag().equals(IndustryActivity.ACTIVITY_COPYING.toString()) //industry job copying || getFlag().equals(General.get().jumpClone()) //jump clone || getFlag().equals(General.get().activeClone()) //active clone || getFlagID() == 89 //plugged in implant ; if (getQuantity() == null || getQuantity() <= 0) { this.count = 1; } else { this.count = getQuantity(); } updateBlueprint(); } private void updateBlueprint() { if (item.isBlueprint()) { //if this is a blueprint //Try to figure out if it's a copy (BPC) or a original (BPO) if (blueprint != null) { //Best this.bpo = blueprint.getRuns() <= 0; this.bpc = blueprint.getRuns() > 0; } else { //2nd best //rawQuantity: -1 = BPO. Only BPOs can be packaged (singleton == false). Only packaged items can be stacked (count > 1) this.bpo = (getQuantity() == -1 || !isSingleton() || getQuantity() > 1); //rawQuantity: -2 = BPC this.bpc = getQuantity() == -2; } if (bpo) { //Found BPO this.typeName = item.getTypeName() + " (BPO)"; } else if (bpc) { //Found BPC this.typeName = item.getTypeName() + " (BPC)"; } else { //Could not figure it out, assume copy this.bpc = true; this.typeName = item.getTypeName() + " (BP)"; } if (!userNameSet || !eveNameSet) { //No other name set, update name this.name = this.typeName; } } this.flagName = ApiIdConverter.getFlagName(rawAsset.getItemFlag(), owner); } public MyAsset(MyIndustryJob industryJob, boolean output) { this(new RawAsset(industryJob, output), industryJob.isManufacturing() && output ? ApiIdConverter.getItemUpdate(industryJob.getProductTypeID()) : industryJob.getItem(), industryJob.getOwner(), new ArrayList<>()); } public MyAsset(MyMarketOrder marketOrder) { this(new RawAsset(marketOrder), marketOrder.getItem(), marketOrder.getOwner(), new ArrayList<>()); } public MyAsset(MyContractItem contractItem, final SimpleOwner owner) { this(new RawAsset(contractItem), contractItem.getItem(), owner, new ArrayList<>()); } public MyAsset(RawClone clone, Integer impantTypeID, final SimpleOwner owner, List parents) { this(new RawAsset(clone, impantTypeID), ApiIdConverter.getItem(impantTypeID), owner, parents); } public MyAsset(RawClone clone, final SimpleOwner owner) { this(new RawAsset(clone), getJumpCloneItem(clone), owner, new ArrayList<>()); } private static Item getJumpCloneItem(RawClone clone) { Item omegaClone = ApiIdConverter.getItem(29143); //Clone Grade Omega String name; if (clone.isActive()) { name = General.get().activeClone(); } else { name = General.get().jumpClone(); } return new Item(0, name, omegaClone.getGroup(), omegaClone.getCategory(), 900000, omegaClone.getVolume(), omegaClone.getVolumePackaged(), omegaClone.getCapacity(), omegaClone.getMeta(), omegaClone.getTech(), omegaClone.isMarketGroup(), omegaClone.getPortion(), omegaClone.getProductTypeID(), omegaClone.getProductQuantity(), omegaClone.getSlot(), omegaClone.getChargeSize(), null); } public void addAsset(final MyAsset asset) { assets.add(asset); } public Date getAdded() { return added; } public List getAssets() { return assets; } public String getContainer() { return container.getContainer(); } public AssetContainer getAssetContainer() { return container; } public boolean isGenerated() { return generated; } @Override public long getCount() { return count; } public String getFlagName() { return flagName; } public final String getFlag() { if (getItemFlag() != null) { return getItemFlag().getFlagName(); } else { return null; } } public final Integer getFlagID() { if (getItemFlag() != null) { return getItemFlag().getFlagID(); } else { return null; } } @Override public Item getItem() { return item; } @Override public long getItemCount() { return getCount(); } @Override public MyLocation getLocation() { return location; } @Override public void setLocation(MyLocation location) { this.location = location; } public MarketPriceData getMarketPriceData() { if (marketPriceData != null) { return marketPriceData; } else { return new MarketPriceData(); } } public String getName() { return name; } public String getOwnerName() { return owner.getOwnerName(); } public SimpleOwner getOwner() { return owner; } @Override public Set getOwners() { return owners; } public long getOwnerID() { return owner.getOwnerID(); } public List getParents() { return parents; } public MyAsset getParent() { if (parents.isEmpty()) { return null; } return parents.get(parents.size() - 1); } @Override public Double getDynamicPrice() { return price; } @Override public void setDynamicPrice(double price) { this.price = price; } public double getPriceBuyMax() { return priceData.getBuyMax(); } public double getPriceReprocessed() { return item.getPriceReprocessed(); } public double getPriceReprocessedDifference() { return getPriceReprocessed() - getDynamicPrice(); } public double getPriceReprocessedPercent() { if (getDynamicPrice() > 0 && getPriceReprocessed() > 0) { return (getPriceReprocessed() / getDynamicPrice()); } else { return 0; } } public double getPriceSellMin() { return priceData.getSellMin(); } @Override public Tags getTags() { return tags; } @Override public TagID getTagID() { return new TagID(AssetsTab.NAME, getItemID()); } public long getTypeCount() { return typeCount; } public final String getTypeName() { return typeName; } public String getItemName() { return itemName; } public UserItem getUserPrice() { return userPrice; } @Override public double getValue() { return Formatter.round(this.getDynamicPrice() * getCount(), 2); } @Override public double getValueReprocessed() { return Formatter.round(this.getPriceReprocessed() * getCount(), 2); } public float getVolume() { return volume; } public double getValuePerVolume() { if (getVolume() > 0 && getDynamicPrice() > 0) { return getDynamicPrice() / getVolume(); } else { return 0; } } @Override public double getVolumeTotal() { return volume * getCount(); } @Override public final boolean isBPO() { return bpo; } @Override public final boolean isBPC() { return bpc; } @Override public int getMaterialEfficiency() { if (blueprint != null) { return blueprint.getMaterialEfficiency(); } else { return 0; } } @Override public int getTimeEfficiency() { if (blueprint != null) { return blueprint.getTimeEfficiency(); } else { return 0; } } @Override public int getRuns() { if (blueprint != null) { return blueprint.getRuns(); } else { return 0; } } public boolean isCorporation() { return owner.isCorporation(); } public boolean isEveName() { return eveNameSet; } public String getSingleton() { if (isSingleton()) { return DataModelAsset.get().unpackaged(); } else { return DataModelAsset.get().packaged(); } } public boolean isUserName() { return userNameSet; } public boolean isUserPrice() { return userPriceSet; } public void setAdded(final Date added) { this.added = added; } public void setBlueprint(MyBlueprint blueprint) { this.blueprint = blueprint; updateBlueprint(); } public void updateContainer() { this.container = new AssetContainer(this); } public void setMarketPriceData(final MarketPriceData marketPriceData) { this.marketPriceData = marketPriceData; } public void setName(UserItem customItem, String eveName) { this.userNameSet = customItem != null; this.eveNameSet = customItem == null && eveName != null; if (customItem != null) { name = customItem.getValue(); itemName = customItem.getValue(); } else if (eveName != null) { name = eveName + " (" + typeName + ")"; itemName = eveName; } else { name = typeName; itemName = null; } } public void setPriceData(final PriceData priceData) { this.priceData = priceData; } @Override public void setTags(Tags tags) { this.tags = tags; } public void setTypeCount(final long typeCount) { this.typeCount = typeCount; } public void setUserPrice(final UserItem userPrice) { this.userPrice = userPrice; userPriceSet = (this.getUserPrice() != null); } @Override public String toString() { return this.getName(); } @Override public int compareTo(final MyAsset o) { return this.getName().compareToIgnoreCase(o.getName()); } @Override public int hashCode() { int hash = 7; hash = 97 * hash + (this.owner != null ? this.owner.hashCode() : 0); hash = 97 * hash + (int) (this.getItemID() ^ (this.getItemID() >>> 32)); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final MyAsset other = (MyAsset) obj; if (this.owner != other.owner && (this.owner == null || !this.owner.equals(other.owner))) { return false; } return Objects.equals(this.getItemID(), other.getItemID()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MyBlueprint.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import net.nikr.eve.jeveasset.data.api.raw.RawBlueprint; import net.nikr.eve.jeveasset.data.api.raw.RawContractItem; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob; public class MyBlueprint { private final int runs; private final int materialEfficiency; private final int timeEfficiency ; /** * Contract Item * @param contractItem */ public MyBlueprint(RawContractItem contractItem) { this(contractItem.getLicensedRuns(), contractItem.getME(), contractItem.getTE()); } /** * Blueprint * @param blueprint */ public MyBlueprint(RawBlueprint blueprint) { this(blueprint.getRuns(), blueprint.getMaterialEfficiency(), blueprint.getTimeEfficiency()); } /** * IndustryJob * @param industryJob */ public MyBlueprint(RawIndustryJob industryJob) { this(industryJob.getLicensedRuns(), null, null); } public MyBlueprint(Integer runs, Integer materialEfficiency, Integer timeEfficiency) { this.runs = notNull(runs); this.materialEfficiency = notNull(materialEfficiency); this.timeEfficiency = notNull(timeEfficiency); } private int notNull(Integer value) { if (value != null) { return value; } else { return 0; } } public int getRuns() { return runs; } public int getMaterialEfficiency() { return materialEfficiency; } public int getTimeEfficiency() { return timeEfficiency; } @Override public int hashCode() { int hash = 5; hash = 23 * hash + this.runs; hash = 23 * hash + this.materialEfficiency; hash = 23 * hash + this.timeEfficiency; return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final MyBlueprint other = (MyBlueprint) obj; if (this.runs != other.runs) { return false; } if (this.materialEfficiency != other.materialEfficiency) { return false; } return this.timeEfficiency == other.timeEfficiency; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MyContract.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import java.util.Date; import java.util.HashSet; import java.util.Objects; import java.util.Set; import net.nikr.eve.jeveasset.data.api.raw.RawContract; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.types.LocationsType; import net.nikr.eve.jeveasset.data.settings.types.OwnersType; import net.nikr.eve.jeveasset.i18n.TabsContracts; import net.nikr.eve.jeveasset.data.settings.types.EsiType; public class MyContract extends RawContract implements Comparable, LocationsType, OwnersType, EsiType { private MyLocation endLocation; private MyLocation startLocation; private String acceptor = ""; private String assignee = ""; private String issuerCorp = ""; private String issuer = ""; private final Set owners = new HashSet<>(); private boolean esi = true; private boolean owned; private boolean issuerAfterAssets = false; private boolean acceptorAfterAssets = false; public MyContract(RawContract rawContract) { super(rawContract); this.owners.add(getIssuerID()); this.owners.add(getIssuerCorpID()); this.owners.add(getAssigneeID()); this.owners.add(getAcceptorID()); this.owned = !rawContract.isForCorp(); } public String getTypeName() { switch (getType()) { case AUCTION: return TabsContracts.get().auction(); case COURIER: return TabsContracts.get().courier(); case ITEM_EXCHANGE: return TabsContracts.get().itemExchange(); case LOAN: return TabsContracts.get().loan(); default: return TabsContracts.get().unknown(); } } public String getAcceptor() { if (acceptor.isEmpty()) { return TabsContracts.get().notAccepted(); } else { return acceptor; } } public String getAssignee() { if (assignee.isEmpty()) { return TabsContracts.get().publicContract(); } else { return assignee; } } public String getIssuerCorp() { return issuerCorp; } public String getIssuer() { return issuer; } public void setAcceptor(String acceptor) { this.acceptor = acceptor; } public void setAssignee(String assignee) { this.assignee = assignee; } public void setIssuerCorp(String issuerCorp) { this.issuerCorp = issuerCorp; } public void setIssuer(String issuer) { this.issuer = issuer; } public MyLocation getEndLocation() { return endLocation; } public boolean isIssuerAfterAssets() { return issuerAfterAssets; } public void setIssuerAfterAssets(Date date) { if (date != null && isCompletedSuccessful()) { this.issuerAfterAssets = getDateCompleted().after(date); } else { this.issuerAfterAssets = false; } } public boolean isAcceptorAfterAssets() { return acceptorAfterAssets; } public void setAcceptorAfterAssets(Date date) { if (date != null && isCompletedSuccessful()) { this.acceptorAfterAssets = getDateCompleted().after(date); } else { this.acceptorAfterAssets = false; } } @Override public Set getLocations() { Set locations = new HashSet<>(); if (startLocation != null) { locations.add(startLocation); } if (endLocation != null) { locations.add(endLocation); } return locations; } @Override public Set getOwners() { return owners; } public final void setEndLocation(MyLocation endLocation) { this.endLocation = endLocation; } public final void setStartLocation(MyLocation startLocation) { this.startLocation = startLocation; } public MyLocation getStartLocation() { return startLocation; } public boolean isCourierContract() { return getType() == ContractType.COURIER; } public boolean isPublic() { return getAvailability() == ContractAvailability.PUBLIC; } public boolean isItemContract() { return getType() == ContractType.AUCTION || getType() == ContractType.ITEM_EXCHANGE; } public boolean isIgnoreContract() { return getType() != ContractType.AUCTION && getType() != ContractType.ITEM_EXCHANGE; } public boolean isOpen() { //Note: expired isn't a contract completion return getStatus() == ContractStatus.OUTSTANDING; } public boolean isInProgress() { //Note: expired isn't a contract completion return getStatus() == ContractStatus.IN_PROGRESS; } public boolean isDeleted() { return getStatus() == ContractStatus.DELETED; } public boolean isCompletedSuccessful() { return getDateCompleted() != null; } public boolean isExpired() { return Settings.getNow().after(getDateExpired()); } public boolean isOwned() { return owned; } public void setOwned(boolean owned) { this.owned = owned; } public String getStatusFormatted() { return getStatusName(super.getStatus()); } public static String getStatusName(ContractStatus status) { switch (status) { case CANCELLED: return TabsContracts.get().statusCancelled(); case FINISHED: return TabsContracts.get().statusCompleted(); case FINISHED_CONTRACTOR: return TabsContracts.get().statusCompletedByContractor(); case FINISHED_ISSUER: return TabsContracts.get().statusCompletedByIssuer(); case DELETED: return TabsContracts.get().statusDeleted(); case FAILED: return TabsContracts.get().statusFailed(); case IN_PROGRESS: return TabsContracts.get().statusInProgress(); case OUTSTANDING: return TabsContracts.get().statusOutstanding(); case REJECTED: return TabsContracts.get().statusRejected(); case REVERSED: return TabsContracts.get().statusReversed(); case ARCHIVED: return TabsContracts.get().statusArchived(); default: return TabsContracts.get().statusUnknown(); } } public String getAvailabilityFormatted() { if (isPublic()) { return TabsContracts.get().availabilityPublic(); } else { return TabsContracts.get().availabilityPrivate(); } } @Override public boolean archive() { boolean update = esi; //Update if in esi if (esi && (getStatus() == ContractStatus.OUTSTANDING || getStatus() == ContractStatus.IN_PROGRESS)) { setStatus(ContractStatus.ARCHIVED); } this.esi = false; return update; } @Override public boolean isESI() { return esi; } @Override public void setESI(boolean esi) { this.esi = esi; } @Override public int hashCode() { int hash = 7; hash = 71 * hash + Objects.hashCode(this.getContractID()); hash = 71 * hash + (int) (this.getIssuerID() ^ (this.getIssuerID() >>> 32)); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final MyContract other = (MyContract) obj; if (!Objects.equals(this.getContractID(), other.getContractID())) { return false; } return Objects.equals(this.getIssuerID(), other.getIssuerID()); } @Override public int compareTo(MyContract o) { return Integer.compare(this.getContractID(), o.getContractID()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MyContractItem.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import java.util.Objects; import java.util.Set; import net.nikr.eve.jeveasset.data.api.raw.RawContractItem; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.types.BlueprintType; import net.nikr.eve.jeveasset.data.settings.types.EditablePriceType; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.data.settings.types.LocationsType; import net.nikr.eve.jeveasset.data.settings.types.OwnersType; import net.nikr.eve.jeveasset.gui.shared.CopyHandler.CopySeparator; import net.nikr.eve.jeveasset.i18n.TabsContracts; import net.nikr.eve.jeveasset.io.shared.RawConverter; public class MyContractItem extends RawContractItem implements Comparable, LocationsType, ItemType, BlueprintType, EditablePriceType, CopySeparator, OwnersType { private MyContract contract; private final Item item; private double price; public MyContractItem(MyContract contract) { super(RawContractItem.create()); this.contract = contract; this.item = new Item(0); setIncluded(true); setQuantity(0); setRecordID(RawConverter.toLong(contract.getContractID())); setSingleton(false); setTypeID(0); setRawQuantity(0); } public MyContractItem(RawContractItem rawContractItem, MyContract contract, Item item) { super(rawContractItem); this.contract = contract; this.item = item; } public MyContract getContract() { return contract; } public void setContract(MyContract contract) { this.contract = contract; } public String getIncluded() { if (getContract().isCourierContract()) { return TabsContracts.get().courier(); } else if (getTypeID() == 0) { return TabsContracts.get().missing(); } else if (isIncluded()) { return TabsContracts.get().included(); } else { return TabsContracts.get().excluded(); } } public String getSingleton() { if (getContract().isCourierContract()) { return TabsContracts.get().courier(); } else if (getTypeID() == 0) { return TabsContracts.get().missing(); } else if (isSingleton()) { return TabsContracts.get().unpackaged(); } else { return TabsContracts.get().packaged(); } } public String getName() { if (item.isEmpty()) { return contract.getTypeName(); } else { return item.getTypeName(); } } @Override public void setDynamicPrice(double price) { this.price = price; } @Override public Double getDynamicPrice() { return price; } @Override public boolean isBPO() { //Blueprint && RawQuantity > -2 return (item.isBlueprint() && this.getRawQuantity() != null && this.getRawQuantity() > -2); } @Override public boolean isBPC() { return (item.isBlueprint() && this.getRawQuantity() != null && this.getRawQuantity() == -2); } @Override public int getRuns() { Integer runs = getLicensedRuns(); if (runs != null) { return runs; } else if (isBPC()) { return 1; //BPC } else if (isBPO()) { return -1; //BPO } else { return 0; //Default unknown } } @Override public int getMaterialEfficiency() { Integer materialEfficiency = getME(); if (materialEfficiency != null) { return materialEfficiency; } else { return 0; } } @Override public int getTimeEfficiency() { Integer timeEfficiency = getTE(); if (timeEfficiency != null) { return timeEfficiency; } else { return 0; } } @Override public Set getLocations() { return getContract().getLocations(); } @Override public Set getOwners() { return getContract().getOwners(); } @Override public Item getItem() { return item; } @Override public long getItemCount() { return getQuantity(); } @Override public String getCopyString() { StringBuilder builder = new StringBuilder(); builder.append(getContract().getTitle()); builder.append("\t"); builder.append(getContract().getTypeName()); return builder.toString(); } @Override public int compareTo(MyContractItem o) { return 0; } @Override public int hashCode() { int hash = 3; hash = 37 * hash + (this.contract != null ? this.contract.hashCode() : 0); hash = 37 * hash + (int) (getRecordID() ^ (getRecordID() >>> 32)); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final MyContractItem other = (MyContractItem) obj; if (this.contract != other.contract && (this.contract == null || !this.contract.equals(other.contract))) { return false; } return Objects.equals(this.getRecordID(), other.getRecordID()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MyExtraction.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import java.util.Objects; import net.nikr.eve.jeveasset.data.api.raw.RawExtraction; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.types.EditableLocationType; public class MyExtraction extends RawExtraction implements EditableLocationType, Comparable { private final MyLocation moon; private MyLocation location; public MyExtraction(RawExtraction extraction, MyLocation moon) { super(extraction); this.moon = moon; } public MyLocation getMoon() { return moon; } @Override public MyLocation getLocation() { return location; } @Override public void setLocation(MyLocation location) { this.location = location; } @Override public long getLocationID() { return getStructureID(); } @Override public int compareTo(MyExtraction o) { int compared = o.getChunkArrivalTime().compareTo(this.getChunkArrivalTime()); if (compared != 0) { return compared; } return this.moon.compareTo(o.moon); } @Override public int hashCode() { int hash = 7; hash = 59 * hash + Objects.hashCode(this.getExtractionStartTime()); hash = 59 * hash + Objects.hashCode(this.getMoonID()); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final RawExtraction other = (RawExtraction) obj; if (!Objects.equals(this.getExtractionStartTime(), other.getExtractionStartTime())) { return false; } return Objects.equals(this.getMoonID(), other.getMoonID()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MyIndustryJob.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import java.util.Date; import java.util.HashSet; import java.util.Objects; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.types.BlueprintType; import net.nikr.eve.jeveasset.data.settings.types.EditableLocationType; import net.nikr.eve.jeveasset.data.settings.types.EditablePriceType; import net.nikr.eve.jeveasset.data.settings.types.EsiType; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.data.settings.types.OwnersType; import net.nikr.eve.jeveasset.gui.shared.table.containers.Duration; import net.nikr.eve.jeveasset.i18n.DataModelIndustryJob; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class MyIndustryJob extends RawIndustryJob implements Comparable, EditableLocationType, ItemType, EditablePriceType, BlueprintType, OwnersType, EsiType { public enum IndustryActivity { ACTIVITY_ALL() { @Override String getI18N() { return DataModelIndustryJob.get().activityAll(); } }, ACTIVITY_NONE() { @Override String getI18N() { return DataModelIndustryJob.get().activityNone(); } }, ACTIVITY_MANUFACTURING() { @Override String getI18N() { return DataModelIndustryJob.get().activityManufacturing(); } }, ACTIVITY_RESEARCHING_TECHNOLOGY() { @Override String getI18N() { return DataModelIndustryJob.get().activityResearchingTechnology(); } }, ACTIVITY_RESEARCHING_TIME_PRODUCTIVITY() { @Override String getI18N() { return DataModelIndustryJob.get().activityResearchingTimeProductivity(); } }, ACTIVITY_RESEARCHING_METERIAL_PRODUCTIVITY() { @Override String getI18N() { return DataModelIndustryJob.get().activityResearchingMeterialProductivity(); } }, ACTIVITY_COPYING() { @Override String getI18N() { return DataModelIndustryJob.get().activityCopying(); } @Override public String getDescriptionOf(final MyIndustryJob job) { // "Copying: Xyz Blueprint making 5 copies with 1500 runs each." return DataModelIndustryJob.get().descriptionCopying( String.valueOf(job.getBlueprintTypeID()), job.getRuns(), job.getLicensedRuns() ); } }, ACTIVITY_DUPLICATING() { @Override String getI18N() { return DataModelIndustryJob.get().activityDuplicating(); } }, ACTIVITY_REVERSE_ENGINEERING() { @Override String getI18N() { return DataModelIndustryJob.get().activityReverseEngineering(); } }, ACTIVITY_REVERSE_INVENTION() { @Override String getI18N() { return DataModelIndustryJob.get().activityReverseInvention(); } }, ACTIVITY_REACTIONS() { @Override String getI18N() { return DataModelIndustryJob.get().activityReactions(); } }, ACTIVITY_UNKNOWN() { @Override String getI18N() { return DataModelIndustryJob.get().activityUnknown(); } }; abstract String getI18N(); @Override public String toString() { return getI18N(); } /** * * @param job * @return a single line, human readable description of the job. */ public String getDescriptionOf(final MyIndustryJob job) { return toString(); } } private IndustryActivity activity; private final Item item; private final Item output; private final OwnerType owner; private final String name; private final Set owners = new HashSet<>(); private final int outputCount; private double price; private double outputValue; private String installer = ""; private String completedCharacter = ""; private MyBlueprint blueprint; private MyLocation location; private boolean esi = true; private boolean owned; public MyIndustryJob(final RawIndustryJob rawIndustryJob, final Item item, final Item output, final OwnerType owner) { super(rawIndustryJob); this.item = item; this.output = output; this.owner = owner; this.owners.add(getInstallerID()); this.owners.add(owner.getOwnerID()); this.owned = owner.isCharacter(); switch (getActivityID()) { case 0: activity = IndustryActivity.ACTIVITY_NONE; break; case 1: activity = IndustryActivity.ACTIVITY_MANUFACTURING; break; case 2: activity = IndustryActivity.ACTIVITY_RESEARCHING_TECHNOLOGY; break; case 3: activity = IndustryActivity.ACTIVITY_RESEARCHING_TIME_PRODUCTIVITY; break; case 4: activity = IndustryActivity.ACTIVITY_RESEARCHING_METERIAL_PRODUCTIVITY; break; case 5: activity = IndustryActivity.ACTIVITY_COPYING; break; case 6: activity = IndustryActivity.ACTIVITY_DUPLICATING; break; case 7: activity = IndustryActivity.ACTIVITY_REVERSE_ENGINEERING; break; case 8: activity = IndustryActivity.ACTIVITY_REVERSE_INVENTION; break; case 9: activity = IndustryActivity.ACTIVITY_REACTIONS; break; case 11: activity = IndustryActivity.ACTIVITY_REACTIONS; break; default: activity = IndustryActivity.ACTIVITY_UNKNOWN; break; } switch (activity) { case ACTIVITY_MANUFACTURING: outputCount = getRuns() * item.getProductQuantity(); break; case ACTIVITY_REACTIONS: outputCount = getRuns() * item.getProductQuantity(); break; case ACTIVITY_COPYING: if (getLicensedRuns() != null) { outputCount = getRuns() * getLicensedRuns(); } else { //Should never happen, but, better safe than sorry outputCount = getRuns(); } break; default: outputCount = 1; break; } this.name = item.getTypeName(); } @Override public int compareTo(final MyIndustryJob o) { return 0; } public void setBlueprint(MyBlueprint blueprint) { this.blueprint = blueprint; } @Override public boolean isBPO() { if (blueprint != null) { return blueprint.getRuns() <= 0; } else { return (getLicensedRuns() == null || getLicensedRuns() <= 0 //BPO should have value -1 || activity == IndustryActivity.ACTIVITY_COPYING //BPO only || activity == IndustryActivity.ACTIVITY_RESEARCHING_METERIAL_PRODUCTIVITY //BPO only || activity == IndustryActivity.ACTIVITY_RESEARCHING_TIME_PRODUCTIVITY) //BPO only && activity != IndustryActivity.ACTIVITY_REVERSE_INVENTION //BPC only ; } } @Override public boolean isBPC() { return !isBPO(); } @Override public int getMaterialEfficiency() { if (blueprint != null) { return blueprint.getMaterialEfficiency(); } else { return 0; } } @Override public int getTimeEfficiency() { if (blueprint != null) { return blueprint.getTimeEfficiency(); } else { return 0; } } public Duration getTimeLeft() { if (getEndDate() == null) { return Duration.NEVER; } Date now = Settings.getNow(); if (now.after(getEndDate())) { return Duration.DONE; } long time = getEndDate().getTime() - now.getTime(); if (time <= 1000) { //less than 1 second return new Duration("..."); } else if (time < (60 * 1000)) { //less than 1 minute return new Duration(time, false, false, false, true); } else { return new Duration(time, true, true, true, false); } } @Override public Integer getTypeID() { return getBlueprintTypeID(); } public final boolean isCompletedSuccessful() { return getStatus() == IndustryJobStatus.DELIVERED; } public final boolean isDone() { return getStatus() == IndustryJobStatus.DELIVERED || getStatus() == IndustryJobStatus.CANCELLED || getStatus() == IndustryJobStatus.REVERTED || getStatus() == IndustryJobStatus.ARCHIVED //Status is unknown -> default to done > true ; } public final boolean isNotDeliveredToAssets() { return !isDone() //if not done -> not delivered to assets -> true && (owner.getAssetLastUpdate() == null //if null -> never updated -> not delivered to assets -> true || getCompletedDate() == null //if null -> not completed -> not delivered to assets -> true || owner.getAssetLastUpdate().before(getCompletedDate()) //if assets last updated before completed date -> not delivered to assets -> true ); } public final boolean isRemovedFromAssets() { return owner.getAssetLastUpdate() != null //if null -> never updated -> not removed from assets -> false && getStartDate() != null //if null -> not started -> not removed from assets -> false && owner.getAssetLastUpdate().after(getStartDate()); //if assets last updated after started date -> removed from assets -> true } public final boolean isManufacturing() { return getActivity() == IndustryActivity.ACTIVITY_MANUFACTURING || getActivity() == IndustryActivity.ACTIVITY_REACTIONS; } public final boolean isCopying() { return getActivity() == IndustryActivity.ACTIVITY_COPYING; } public final boolean isInvention() { return getActivity() == IndustryActivity.ACTIVITY_REVERSE_INVENTION; } public boolean isOwned() { return owned; } public void setOwned(boolean owned) { this.owned = owned; } public IndustryActivity getActivity() { return activity; } public boolean isExpired() { return getEndDate().before(Settings.getNow()); } @Override public IndustryJobStatus getStatus() { //Update READY (may have changed after loading profile) if (isExpired() && super.getStatus() == IndustryJobStatus.ACTIVE) { setStatus(IndustryJobStatus.READY); } return super.getStatus(); } public String getStatusFormatted() { return getStatusName(getStatus(), isExpired()); } public static String getStatusName(IndustryJobStatus status) { return getStatusName(status, false); } public static String getStatusName(IndustryJobStatus status, boolean expired) { switch (status) { case ACTIVE: //Active if (expired) { return DataModelIndustryJob.get().statusDone(); } else { return DataModelIndustryJob.get().statusActive(); } case PAUSED: return DataModelIndustryJob.get().statusPaused(); case READY: return DataModelIndustryJob.get().statusDone(); case DELIVERED: return DataModelIndustryJob.get().statusDelivered(); case CANCELLED: return DataModelIndustryJob.get().statusCancelled(); case REVERTED: return DataModelIndustryJob.get().statusReverted(); case ARCHIVED: return DataModelIndustryJob.get().statusArchived(); default: return DataModelIndustryJob.get().statusUnknown(); } } @Override public void setDynamicPrice(double price) { this.price = price; } @Override public Double getDynamicPrice() { return price; } public double getOutputValue() { return outputValue; } public String getName() { return name; } public void setOutputPrice(double outputPrice) { if (isManufacturing()) { this.outputValue = outputPrice * getRuns() * getProductQuantity(); } else if (isCopying() && getLicensedRuns() != null) { this.outputValue = outputPrice * getRuns() * getLicensedRuns(); } else { this.outputValue = 0; } } public int getOutputCount() { return outputCount; } public Item getOutputItem() { return output; } public double getOutputVolume() { if (isCopying()) { return output.getVolumePackaged() * getRuns(); // Volume of the output blueprints (bp runs should not be counted) } else { return output.getVolumePackaged() * outputCount; } } public String getInstaller() { return installer; } public void setInstaller(String installer) { this.installer = installer; } public String getCompletedCharacter() { return completedCharacter; } public void setCompletedCharacter(String completedCharacter) { this.completedCharacter = completedCharacter; } @Override public Set getOwners() { return owners; } @Override public long getLocationID() { if (ApiIdConverter.isLocationOK(getStationID())) { return getStationID(); } if (ApiIdConverter.isLocationOK(getBlueprintLocationID())) { return getBlueprintLocationID(); } if (ApiIdConverter.isLocationOK(getOutputLocationID())) { return getOutputLocationID(); } return getStationID(); } @Override public MyLocation getLocation() { return location; } @Override public void setLocation(MyLocation location) { this.location = location; } public OwnerType getOwner() { return owner; } public String getOwnerName() { return owner.getOwnerName(); } public long getOwnerID() { return owner.getOwnerID(); } public int getProductQuantity() { return item.getProductQuantity(); } @Override public boolean archive() { boolean update = esi; //Update if in esi if (esi && (getStatus() == IndustryJobStatus.READY || getStatus() == IndustryJobStatus.ACTIVE)) { setStatus(IndustryJobStatus.ARCHIVED); } this.esi = false; return update; } @Override public boolean isESI() { return esi; } @Override public void setESI(boolean esi) { this.esi = esi; } @Override public Item getItem() { return item; } @Override public long getItemCount() { return 1; //Just one blueprint here } @Override public int hashCode() { int hash = 5; hash = 37 * hash + Objects.hashCode(this.getJobID()); hash = 37 * hash + (int) (this.owner.getOwnerID() ^ (this.owner.getOwnerID() >>> 32)); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final MyIndustryJob other = (MyIndustryJob) obj; if (!Objects.equals(this.getJobID(), other.getJobID())) { return false; } return this.owner.getOwnerID() == other.owner.getOwnerID(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MyJournal.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import java.util.Date; import java.util.HashSet; import java.util.Objects; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.raw.RawJournal; import net.nikr.eve.jeveasset.data.api.raw.RawJournalRefType; import net.nikr.eve.jeveasset.data.settings.tag.TagID; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.data.settings.types.OwnersType; import net.nikr.eve.jeveasset.data.settings.types.TagsType; import net.nikr.eve.jeveasset.gui.tabs.journal.JournalTab; import net.nikr.eve.jeveasset.io.shared.RawConverter; public class MyJournal extends RawJournal implements Comparable, OwnersType, TagsType { private static final String CORP = "(Corporation)"; private final OwnerType owner; private final Set owners = new HashSet<>(); private String firstPartyName = ""; private String secondPartyName = ""; private Date added; private String context = null; private Tags tags; public MyJournal(RawJournal rawJournal, OwnerType owner) { super(rawJournal); this.owner = owner; owners.add(owner.getOwnerID()); owners.add(RawConverter.toLong(getFirstPartyID())); owners.add(RawConverter.toLong(getSecondPartyID())); } public int getAccountKeyFormatted() { return getAccountKey() - 999; } public String getOwnerName() { return owner.getOwnerName(); } public String getRefTypeFormatted() { RawJournalRefType refType = getRefType(); if (refType != null) { return capitalizeAll(refType.name().replace("_CORP_", CORP).replace('_', ' ')); } else { return ""; } } public String getFirstPartyName() { return firstPartyName; } public void setFirstPartyName(String firstPartyName) { this.firstPartyName = firstPartyName; } public String getSecondPartyName() { return secondPartyName; } public void setSecondPartyName(String secondPartyName) { this.secondPartyName = secondPartyName; } private String capitalize(String s) { if (s.length() == 0) { return s; } if (s.equals(CORP)) { return s; } return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); } @Override public Set getOwners() { return owners; } public Date getAdded() { return added; } public void setAdded(Date added) { this.added = added; } public String getContext() { return context; } public void setContext(String context) { this.context = context; } private String capitalizeAll(String in) { String[] words = in.split("\\s"); StringBuilder builder = new StringBuilder(); for (String word : words) { if (builder.length() > 0) { builder.append(' '); } builder.append(capitalize(word)); } return builder.toString(); } @Override public Tags getTags() { return tags; } private double getAmountNotNull() { Double amount = getAmount(); if (amount != null) { return amount; } else { return 0.0; } } @Override public TagID getTagID() { return new TagID(JournalTab.NAME, getRefID(), getAmountNotNull()); } @Override public void setTags(Tags tags) { this.tags = tags; } @Override public int compareTo(MyJournal o) { int compared = o.getDate().compareTo(this.getDate()); if (compared != 0) { return compared; } else { return Double.compare(o.getAmount(), this.getAmount()); } } @Override public int hashCode() { int hash = 7; hash = 83 * hash + Objects.hashCode(this.getAmount()); hash = 83 * hash + Objects.hashCode(this.getRefID()); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final RawJournal other = (RawJournal) obj; if (!Objects.equals(this.getAmount(), other.getAmount())) { return false; } if (!Objects.equals(this.getRefID(), other.getRefID())) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MyLoyaltyPoints.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.raw.RawLoyaltyPoints; import net.nikr.eve.jeveasset.data.settings.types.CorporationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.table.containers.TextIcon; import net.nikr.eve.jeveasset.io.online.EveImageGetter.ImageSize; public class MyLoyaltyPoints extends RawLoyaltyPoints implements Comparable, CorporationType { public static ImageSize IMAGE_SIZE = ImageSize.SIZE_32; private final OwnerType owner; private String corporationName = ""; private TextIcon textIcon = null; public MyLoyaltyPoints(RawLoyaltyPoints rawLoyaltyPoints, OwnerType owner) { super(rawLoyaltyPoints); this.owner = owner; } public String getOwnerName() { return owner.getOwnerName(); } @Override public String getCorporationName() { return corporationName; } public void setCorporationName(String corporationName) { this.corporationName = corporationName; } public TextIcon getTextIcon() { if (textIcon == null) { textIcon = new TextIcon(Images.getIcon(this), corporationName); } return textIcon; } @Override public int compareTo(MyLoyaltyPoints o) { int comp = this.getOwnerName().compareTo(o.getOwnerName()); if (comp != 0) { return comp; } return this.getCorporationName().compareTo(o.getCorporationName()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MyMarketOrder.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.Objects; import java.util.Set; import javax.management.timer.Timer; import javax.swing.JButton; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.PriceData; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.types.BlueprintType; import net.nikr.eve.jeveasset.data.settings.types.EditableLocationType; import net.nikr.eve.jeveasset.data.settings.types.EditablePriceType; import net.nikr.eve.jeveasset.data.settings.types.EsiType; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.data.settings.types.LastTransactionType; import net.nikr.eve.jeveasset.data.settings.types.MarketDetailType; import net.nikr.eve.jeveasset.data.settings.types.OwnersType; import net.nikr.eve.jeveasset.gui.shared.components.JButtonComparable; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.gui.tabs.orders.Outbid; import net.nikr.eve.jeveasset.i18n.TabsOrders; public class MyMarketOrder extends RawMarketOrder implements Comparable, EditableLocationType, ItemType, BlueprintType, EditablePriceType, OwnersType, LastTransactionType, MarketDetailType, EsiType { private final Item item; private final OwnerType owner; private final Set owners; private MyLocation location; private double price; private PriceData priceData = new PriceData(); private double transactionPrice; private double transactionProfitDifference; private Percent transactionProfitPercent; private String issuedByName = ""; private Double brokersFee; private Outbid outbid; private boolean outbidOwned = false; private boolean esi = true; private boolean owned; //soft init private JButton jButton; public MyMarketOrder(final RawMarketOrder rawMarketOrder, final Item item, final OwnerType owner) { super(rawMarketOrder); this.item = item; this.owner = owner; this.owners = Collections.singleton(owner.getOwnerID()); this.owned = !rawMarketOrder.isCorp(); } @Override public boolean archive() { boolean update = esi; //Update if in esi if (esi && getState() == MarketOrderState.OPEN) { //Only do once, as the user can set the state to open setState(MarketOrderState.UNKNOWN); } esi = false; return update; } @Override public int compareTo(final MyMarketOrder o) { return Long.compare(o.getOrderID(), this.getOrderID()); } @Override public boolean isESI() { return esi; } @Override public void setESI(boolean esi) { this.esi = esi; } public Date getExpires() { long expires = (this.getIssued().getTime() + ((this.getDuration()) * Timer.ONE_DAY)); return new Date(expires); } public final boolean isExpired() { return getExpires().before(new Date()); } public final boolean isNearExpired() { Calendar cal = Calendar.getInstance(); cal.add(Calendar.DATE, Settings.get().getMarketOrdersSettings().getExpireWarnDays()); return getExpires().before(cal.getTime()); } public final boolean isNearFilled() { //How much do we want to worry about precision vs cost of converting to doubles for possibly //thousands of orders in history, if we want more accuracy cast to doubles first and change //comparison to Double.compare //Multiply by 100 since we are dealing with percents as integers. //This will be slightly inaccurate since int are essentially floored if they have a remainder. return ( (getVolumeRemain() * 100) / getVolumeTotal() <= Settings.get().getMarketOrdersSettings().getRemainingWarnPercent()); } public boolean isActive() { return getState() == MarketOrderState.OPEN && !isExpired(); } public boolean isOwned() { return owned; } public void setOwned(boolean owned) { this.owned = owned; } @Override public boolean isBPC() { return false; //Market Orders are always BPO } @Override public boolean isBPO() { return item.isBlueprint(); } @Override public int getRuns() { return -1; //BPO - Can not sell BPC } @Override public int getMaterialEfficiency() { return 0; //Zero - Can not sell researched blueprints } @Override public int getTimeEfficiency() { return 0; //Zero - Can not sell researched blueprints } @Override public void setDynamicPrice(double price) { this.price = price; } @Override public Double getDynamicPrice() { return price; } @Override public double getTransactionPrice() { return transactionPrice; } @Override public double getTransactionProfitDifference() { return transactionProfitDifference; } @Override public Percent getTransactionProfitPercent() { return transactionProfitPercent; } @Override public void setTransactionPrice(double transactionPrice) { this.transactionPrice = transactionPrice; } @Override public void setTransactionProfit(double transactionProfitDifference) { this.transactionProfitDifference = transactionProfitDifference; } @Override public void setTransactionProfitPercent(Percent transactionProfitPercent) { this.transactionProfitPercent = transactionProfitPercent; } public double getMarketMargin() { if (getDynamicPrice() > 0 && getPrice() > 0) { if (isBuyOrder()) { return (getDynamicPrice() - getPrice()) / getDynamicPrice(); } else { return (getPrice() - getDynamicPrice()) / getPrice(); } } else { return 0; } } public double getMarketProfit() { if (isBuyOrder()) { return getDynamicPrice() - getPrice(); } else { return getPrice() - getDynamicPrice(); } } public Date getCreatedOrIssued() { if (!getChanges().isEmpty()) { return getChanges().iterator().next().getDate(); } else { return getIssued(); } } @Override public Item getItem() { return item; } @Override public long getItemCount() { return getVolumeRemain(); } @Override public MyLocation getLocation() { return location; } @Override public Set getOwners() { return owners; } @Override public void setLocation(MyLocation location) { this.location = location; } public String getIssuedByName() { return issuedByName; } public void setIssuedByName(String issuedByName) { this.issuedByName = issuedByName; } public OwnerType getOwner() { return owner; } public String getOwnerName() { return owner.getOwnerName(); } public long getOwnerID() { return owner.getOwnerID(); } public String getStateFormatted() { if ((isExpired() && getState() == MarketOrderState.UNKNOWN) //expired (status may be out-of-date) || getState() == MarketOrderState.EXPIRED) { if (this.getVolumeRemain() == 0) { return TabsOrders.get().statusFulfilled(); } else if (Objects.equals(this.getVolumeRemain(), this.getVolumeTotal())) { return TabsOrders.get().statusExpired(); } else { return TabsOrders.get().statusPartiallyFulfilled(); } } else { return getStateName(getState()); } } public static String getStateName(MarketOrderState state) { switch (state) { case OPEN: //open/active return TabsOrders.get().statusActive(); case CLOSED: //closed return TabsOrders.get().statusClosed(); case EXPIRED: //expired (or fulfilled) return TabsOrders.get().statusExpired(); case CANCELLED: //cancelled return TabsOrders.get().statusCancelled(); case PENDING: //pending return TabsOrders.get().statusPending(); case CHARACTER_DELETED: //character deleted return TabsOrders.get().statusCharacterDeleted(); case UNKNOWN: //Unknown or Auto Closed return TabsOrders.get().statusUnknown(); default: return TabsOrders.get().statusUnknown(); } } public boolean isCorporation() { return owner.isCorporation(); } public Double getBrokersFee() { return brokersFee; } public Double getBrokersFeeNotNull() { if (brokersFee != null) { return brokersFee; } else { return 0.0; } } public void setBrokersFee(Double brokerFee) { this.brokersFee = brokerFee; } public boolean isOutbid() { if (outbid == null) { return false; } return outbid.getCount() > 0; } public boolean isOutbidOwned() { return outbidOwned; } public void setOutbidOwned(boolean outbidOwned) { this.outbidOwned = outbidOwned; } public boolean haveOutbid() { return outbid != null; } public Double getOutbidPrice() { if (outbid == null) { return null; } return outbid.getPrice(); } public Long getOutbidCount() { if (outbid == null) { return null; } return outbid.getCount(); } public Double getOutbidDelta() { if (outbid == null) { return null; } if (isBuyOrder()) { return getPrice() - outbid.getPrice(); } else { return outbid.getPrice() - getPrice(); } } public void setOutbid(Outbid outbid) { this.outbid = outbid; } public double getPriceReprocessed() { return item.getPriceReprocessed(); } public void setPriceData(PriceData priceData) { this.priceData = priceData; } public double getPriceBuyMax() { return priceData.getBuyMax(); } public double getPriceSellMin() { return priceData.getSellMin(); } @Override public JButton getButton() { if (jButton == null) { jButton = new JButtonComparable(TabsOrders.get().eveUiOpen()); } return jButton; } @Override public int hashCode() { int hash = 7; hash = 89 * hash + Objects.hashCode(this.getOrderID()); //OrderID is globaly unique return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final MyMarketOrder other = (MyMarketOrder) obj; return Objects.equals(this.getOrderID(), other.getOrderID()); //OrderID is globaly unique } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MyMining.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import java.util.Objects; import net.nikr.eve.jeveasset.data.api.raw.RawMining; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.types.EditableLocationType; import net.nikr.eve.jeveasset.data.settings.types.EditablePriceType; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.InfoItem; import net.nikr.eve.jeveasset.gui.shared.table.containers.DateOnly; public class MyMining extends RawMining implements Comparable, InfoItem, ItemType, EditablePriceType, EditableLocationType { private final DateOnly dateOnly; private final Item item; private MyLocation location; private double price; private String characterName; public MyMining(RawMining mining, Item item, MyLocation location) { super(mining); this.dateOnly = new DateOnly(getDate()); this.item = item; this.location = location; } public String getCharacterName() { return characterName; } public void setCharacterName(String characterName) { this.characterName = characterName; } @Override public double getValue() { return price * getCount(); } public DateOnly getDateOnly() { return dateOnly; } public double getPriceReprocessed() { return item.getPriceReprocessed(); } @Override public double getValueReprocessed() { return item.getPriceReprocessed() * getCount(); } public double getPriceReprocessedMax() { return item.getPriceReprocessedMax(); } public double getValueReprocessedMax() { return item.getPriceReprocessedMax() * getCount(); } private float getVolume() { return item.getVolumePackaged(); } @Override public double getVolumeTotal() { return item.getVolumePackaged() * getCount(); } public double getValuePerVolumeOre() { if (getVolume() > 0 && getDynamicPrice() > 0) { return getDynamicPrice() / getVolume(); } else { return 0; } } public double getValuePerVolumeReprocessed() { if (getVolume() > 0 && getPriceReprocessed()> 0) { return getPriceReprocessed() / getVolume(); } else { return 0; } } public double getValuePerVolumeReprocessedMax() { if (getVolume() > 0 && getPriceReprocessedMax()> 0) { return getPriceReprocessedMax() / getVolume(); } else { return 0; } } @Override public void setDynamicPrice(double price) { this.price = price; } @Override public boolean isBPC() { return false; } @Override public Double getDynamicPrice() { return price; } @Override public void setLocation(MyLocation location) { this.location = location; } @Override public Item getItem() { return item; } @Override public long getItemCount() { return getCount(); } @Override public MyLocation getLocation() { return location; } @Override public int compareTo(MyMining o) { return o.getDate().compareTo(this.getDate()); } @Override public int hashCode() { int hash = 3; hash = 17 * hash + Objects.hashCode(this.getDate()); hash = 17 * hash + Objects.hashCode(this.getLocationID()); hash = 17 * hash + Objects.hashCode(this.getTypeID()); hash = 17 * hash + Objects.hashCode(this.getCharacterID()); hash = 17 * hash + Objects.hashCode(this.isForCorporation()); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final MyMining other = (MyMining) obj; if (!Objects.equals(this.getDate(), other.getDate())) { return false; } if (!Objects.equals(this.getLocationID(), other.getLocationID())) { return false; } if (!Objects.equals(this.getTypeID(), other.getTypeID())) { return false; } if (!Objects.equals(this.getCharacterID(), other.getCharacterID())) { return false; } return Objects.equals(this.isForCorporation(), other.isForCorporation()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MyNpcStanding.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.raw.RawNpcStanding; import net.nikr.eve.jeveasset.data.sde.Agent; import net.nikr.eve.jeveasset.data.sde.NpcCorporation; import net.nikr.eve.jeveasset.data.settings.types.CorporationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.table.containers.Security; import net.nikr.eve.jeveasset.gui.shared.table.containers.TextIcon; import net.nikr.eve.jeveasset.io.online.EveImageGetter; import net.nikr.eve.jeveasset.io.online.EveImageGetter.ImageSize; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class MyNpcStanding extends RawNpcStanding implements Comparable, CorporationType { public static ImageSize IMAGE_SIZE = ImageSize.SIZE_32; private final OwnerType owner; private final int factionID; private final int corporationID; private final int agentID; private final Agent agent; private final boolean connections; private final boolean criminalConnections; private String factionName; private String corporationName; private TextIcon ownerTextIcon = null;; private TextIcon factionTextIcon = null; private TextIcon corporationTextIcon = null; private TextIcon agentTextIcon = null; private int connectionsLevel; private int diplomacyLevel; private int criminalConnectionsLevel; public MyNpcStanding(RawNpcStanding rawNpcStanding, OwnerType owner) { super(rawNpcStanding); this.owner = owner; agentID = getFromType() == FromType.AGENT ? getFromID() : 0; agent = ApiIdConverter.getAgent(agentID); NpcCorporation npcCorporation; if (getFromType() == FromType.AGENT) { if (!agent.isEmpty()) { corporationID = agent.getCorporationID(); npcCorporation = ApiIdConverter.getNpcCorporation(corporationID); factionID = npcCorporation.getFactionID(); } else { npcCorporation = ApiIdConverter.getNpcCorporation(getCorporationID()); corporationID = npcCorporation.getCorporationID(); factionID = npcCorporation.getFactionID(); } } else if (getFromType() == FromType.NPC_CORP) { corporationID = getFromID(); npcCorporation = ApiIdConverter.getNpcCorporation(corporationID); factionID = npcCorporation.getFactionID(); } else { //FromType.FACTION corporationID = 0; factionID = getFromID(); npcCorporation = ApiIdConverter.getNpcCorporation(factionID); } if (npcCorporation != null) { connections = npcCorporation.isConnections(); criminalConnections = npcCorporation.isCriminalConnections(); } else { connections = false; criminalConnections = false; } } public String getOwnerName() { return owner.getOwnerName(); } public int getFactionID() { return factionID; } @Override public Integer getCorporationID() { return corporationID; } @Override public String getCorporationName() { return corporationName; } public int getAgentID() { return agentID; } public Agent getAgent() { return agent; } public String getAgentName() { return agent.getAgent(); } public TextIcon getOwnerTextIcon() { if (ownerTextIcon == null ) { if (owner.isCharacter()) { ownerTextIcon = new TextIcon(Images.getIcon((int)owner.getOwnerID(), EveImageGetter.ImageCategory.CHARACTERS), owner.getOwnerName()); } else { ownerTextIcon = new TextIcon(Images.getIcon((int)owner.getOwnerID(), EveImageGetter.ImageCategory.CORPORATIONS), owner.getOwnerName()); } } return ownerTextIcon; } public TextIcon getFactionTextIcon() { if (factionTextIcon == null && factionID > 0) { factionTextIcon = new TextIcon(Images.getIcon(factionID, EveImageGetter.ImageCategory.CORPORATIONS), factionName); } return factionTextIcon; } public TextIcon getCorporationTextIcon() { if (corporationTextIcon == null && corporationID > 0 && (getFromType() == FromType.AGENT || getFromType() == FromType.NPC_CORP)) { corporationTextIcon = new TextIcon(Images.getIcon(corporationID, EveImageGetter.ImageCategory.CORPORATIONS), corporationName); } return corporationTextIcon; } public TextIcon getAgentTextIcon() { if (agentTextIcon == null && getFromType() == FromType.AGENT) { agentTextIcon = new TextIcon(Images.getIcon(this), getAgentName()); } return agentTextIcon; } public void setFactionName(String factionName) { this.factionName = factionName; } public void setCorporationName(String corporationName) { this.corporationName = corporationName; } public void updateSkills() { for (MySkill mySkill : owner.getSkills()) { if (mySkill.getTypeID() == 3359) { //Connections connectionsLevel = mySkill.getActiveSkillLevel(); } if (mySkill.getTypeID() == 3357) { //Connections diplomacyLevel = mySkill.getActiveSkillLevel(); } if (mySkill.getTypeID() == 3361) { //Connections criminalConnectionsLevel = mySkill.getActiveSkillLevel(); } } } public Float getStandingEffective() { Float standing = getStanding(); if (standing >= 0) { if (connections && connectionsLevel > 0) { standing = calc(standing, connectionsLevel); } if (criminalConnections && criminalConnectionsLevel > 0) { standing = calc(standing, criminalConnectionsLevel); } } else { standing = calc(standing, diplomacyLevel); } return standing; } public Float getStandingMaximum() { return calc(getStanding(), 5); } private Float calc(Float standing, int modifier) { return standing + (10 - standing) * 0.04F * modifier; } public String getLocation() { if (!agent.isEmpty()) { return agent.getLocation().getLocation(); } else { return null; } } public Security getSecurityObject() { if (!agent.isEmpty()) { return agent.getLocation().getSecurityObject(); } else { return null; } } public String getSystem() { if (!agent.isEmpty()) { return agent.getLocation().getSystem(); } else { return null; } } public String getConstellation() { if (!agent.isEmpty()) { return agent.getLocation().getConstellation(); } else { return null; } } public String getRegion() { if (!agent.isEmpty()) { return agent.getLocation().getRegion(); } else { return null; } } @Override public int compareTo(MyNpcStanding o) { int compare = MyNpcStanding.FROM_TYPE_COMPARATOR.compare(this.getFromType(), o.getFromType()); if (compare != 0) { return compare; } return Float.compare(o.getStanding(), this.getStanding()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MyShip.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import java.util.Objects; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.CharacterLocationResponse; import net.troja.eve.esi.model.CharacterShipResponse; public class MyShip implements Comparable, LocationType { //Static values (set by constructor) private final Long itemID; private final Integer typeID; private final MyLocation location; private final String name; private final String typeName; private final String eveName; public MyShip(final CharacterShipResponse shipType, final CharacterLocationResponse response) { this(shipType.getShipItemId(), SafeConverter.toInteger(shipType.getShipTypeId()), RawConverter.toLocationID(response)); } public MyShip(final Long itemID, final Integer typeID, final Long locationID) { this.itemID = itemID; this.typeID = typeID; this.location = ApiIdConverter.getLocation(locationID); this.typeName = ApiIdConverter.getItemUpdate(typeID).getTypeName(); if (Settings.get().getEveNames().get(itemID) != null) { this.eveName = Settings.get().getEveNames().get(itemID); this.name = this.eveName + " (" + this.typeName + ")"; } else { this.eveName = ""; this.name = this.typeName; } } public Long getItemID() { return itemID; } @Override public MyLocation getLocation() { return location; } public long getLocationID() { return location.getLocationID(); } public String getName() { return name; } public String getEveName() { return eveName; } public int getTypeID() { return typeID; } public final String getTypeName() { return typeName; } @Override public String toString() { return this.getName(); } @Override public int compareTo(final MyShip o) { return this.getName().compareToIgnoreCase(o.getName()); } @Override public int hashCode() { int hash = 5; hash = 97 * hash + Objects.hashCode(this.itemID); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final MyShip other = (MyShip) obj; if (!Objects.equals(this.itemID, other.itemID)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MySkill.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import java.util.Objects; import net.nikr.eve.jeveasset.data.api.raw.RawSkill; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.settings.types.ItemType; public class MySkill extends RawSkill implements Comparable, ItemType { private final Item item; private final String owner; public MySkill(RawSkill skill, Item item, String owner) { super(skill); this.item = item; this.owner = owner; } public String getName() { return item.getTypeName(); } @Override public Item getItem() { return item; } @Override public long getItemCount() { return 1; } public String getOwnerName() { return owner; } @Override public int compareTo(MySkill o) { int compared = this.getOwnerName().compareTo(o.getOwnerName()); if (compared != 0) { return compared; } return this.getName().compareTo(o.getName()); } @Override public int hashCode() { int hash = 3; hash = 59 * hash + Objects.hashCode(this.item); hash = 59 * hash + Objects.hashCode(this.owner); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final MySkill other = (MySkill) obj; if (!Objects.equals(this.owner, other.owner)) { return false; } return Objects.equals(this.item, other.item); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/my/MyTransaction.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.my; import java.util.Date; import java.util.HashSet; import java.util.Objects; import java.util.Set; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.raw.RawTransaction; import net.nikr.eve.jeveasset.data.settings.tag.TagID; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.data.settings.types.EditableLocationType; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.data.settings.types.LastTransactionType; import net.nikr.eve.jeveasset.data.settings.types.OwnersType; import net.nikr.eve.jeveasset.data.settings.types.TagsType; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTab; import net.nikr.eve.jeveasset.i18n.TabsTransaction; public class MyTransaction extends RawTransaction implements EditableLocationType, ItemType, Comparable, OwnersType, LastTransactionType, TagsType { private final Item item; private final OwnerType owner; private final Set owners = new HashSet<>(); private MyLocation location; private String clientName; private double transactionPrice; private double transactionProfit; private Percent transactionProfitPercent; private Double tax; private Date added; private Tags tags; public MyTransaction(final RawTransaction rawTransaction, final Item item, final OwnerType owner) { super(rawTransaction); this.item = item; this.owner = owner; owners.add(getClientID()); owners.add(owner.getOwnerID()); } public int getAccountKeyFormatted() { return getAccountKey() - 999; } public String getTransactionTypeFormatted() { if (isSell()) { return TabsTransaction.get().sell(); } else { return TabsTransaction.get().buy(); } } public String getTransactionForFormatted() { if (isPersonal()) { return TabsTransaction.get().personal(); } else { return TabsTransaction.get().corporation(); } } @Override public MyLocation getLocation() { return location; } @Override public Set getOwners() { return owners; } @Override public void setLocation(MyLocation location) { this.location = location; } @Override public Item getItem() { return item; } @Override public long getItemCount() { return getQuantity(); } public String getOwnerName() { return owner.getOwnerName(); } public long getOwnerID() { return owner.getOwnerID(); } public String getClientName() { return clientName; } public void setClientName(String clientName) { this.clientName = clientName; } public double getValue() { if (isSell()) { return (getQuantity() * getPrice()) + getTaxNotNull(); //Adding tax, tax is a negative number } else { return getQuantity() * -getPrice(); } } public boolean isAfterAssets() { Date date = owner.getAssetLastUpdate(); if (date != null) { return getDate().after(date); } else { return false; } } public boolean isSell() { return !isBuy(); } public boolean isCorporation() { return !isPersonal(); } public Double getTax() { return tax; } public double getTaxNotNull() { if (tax != null) { return tax; } else { return 0.0; } } public void setTax(Double tax) { this.tax = tax; } public Date getAdded() { return added; } public void setAdded(Date added) { this.added = added; } @Override public Tags getTags() { return tags; } @Override public TagID getTagID() { return new TagID(TransactionTab.NAME, getTransactionID(), getPrice()); } @Override public void setTags(Tags tags) { this.tags = tags; } @Override public double getTransactionPrice() { return transactionPrice; } @Override public double getTransactionProfitDifference() { return transactionProfit; } @Override public Percent getTransactionProfitPercent() { return transactionProfitPercent; } @Override public void setTransactionPrice(double transactionPrice) { this.transactionPrice = transactionPrice; } @Override public void setTransactionProfit(double transactionProfit) { this.transactionProfit = transactionProfit; } @Override public void setTransactionProfitPercent(Percent transactionProfitPercent) { this.transactionProfitPercent = transactionProfitPercent; } @Override public int compareTo(final MyTransaction o) { int compared = o.getDate().compareTo(this.getDate()); if (compared != 0) { return compared; } else { return Double.compare(o.getPrice(), this.getPrice()); } } @Override public int hashCode() { int hash = 7; hash = 67 * hash + Objects.hashCode(this.getTransactionID()); hash = 67 * hash + Objects.hashCode(this.getPrice()); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final RawTransaction other = (RawTransaction) obj; if (!Objects.equals(this.getTransactionID(), other.getTransactionID())) { return false; } if (!Objects.equals(this.getPrice(), other.getPrice())) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawAccountBalance.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.CorporationWalletsResponse; public class RawAccountBalance { private Double balance; private Integer accountKey; /** * New */ private RawAccountBalance() { } public static RawAccountBalance create() { return new RawAccountBalance(); } /** * Raw * * @param balance */ protected RawAccountBalance(RawAccountBalance balance) { this.balance = balance.balance; this.accountKey = balance.accountKey; } /** * ESI Character * * @param balance * @param accountKey */ public RawAccountBalance(Double balance, Integer accountKey) { this.balance = balance; this.accountKey = accountKey; } /** * ESI Corporation * * @param response */ public RawAccountBalance(CorporationWalletsResponse response) { this.balance = response.getBalance(); this.accountKey = SafeConverter.toInteger(response.getDivision()) + 999; } public Double getBalance() { return balance; } public void setBalance(Double balance) { this.balance = balance; } public Integer getAccountKey() { return accountKey; } public void setAccountKey(Integer accountKey) { this.accountKey = accountKey; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawAsset.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import java.util.Objects; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob.IndustryActivity; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.sde.ItemFlag; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.CharacterAssetsResponse; import net.troja.eve.esi.model.CharacterLocationResponse; import net.troja.eve.esi.model.PlanetPin; import net.troja.eve.esi.model.CharacterPlanetsResponse; import net.troja.eve.esi.model.CharacterShipResponse; import net.troja.eve.esi.model.CorporationAssetsResponse; import net.troja.eve.esi.model.PinContent; public class RawAsset { private static final ItemFlag MANUFACTURING_FLAG = new ItemFlag(0, IndustryActivity.ACTIVITY_MANUFACTURING.toString(), IndustryActivity.ACTIVITY_MANUFACTURING.toString()); private static final ItemFlag REACTIONS_FLAG = new ItemFlag(0, IndustryActivity.ACTIVITY_REACTIONS.toString(), IndustryActivity.ACTIVITY_REACTIONS.toString()); private static final ItemFlag COPYING_FLAG = new ItemFlag(0, IndustryActivity.ACTIVITY_COPYING.toString(), IndustryActivity.ACTIVITY_COPYING.toString()); private static final ItemFlag INDUSTRY_JOB_FLAG = new ItemFlag(0, General.get().industryJobFlag(), General.get().industryJobFlag()); private static final ItemFlag MARKET_ORDER_BUY_FLAG = new ItemFlag(0, General.get().marketOrderBuyFlag(), General.get().marketOrderBuyFlag()); private static final ItemFlag MARKET_ORDER_SELL_FLAG = new ItemFlag(0, General.get().marketOrderSellFlag(), General.get().marketOrderSellFlag()); private static final ItemFlag CONTRACT_INCLUDED_FLAG = new ItemFlag(0, General.get().contractIncluded(), General.get().contractIncluded()); private static final ItemFlag CONTRACT_EXCLUDED_FLAG = new ItemFlag(0, General.get().contractExcluded(), General.get().contractExcluded()); public static final ItemFlag JUMP_CLONE_FLAG = new ItemFlag(0, General.get().jumpClone(), General.get().jumpClone()); public static final ItemFlag ACTIVE_CLONE_FLAG = new ItemFlag(0, General.get().activeClone(), General.get().activeClone()); public static final ItemFlag IMPLANT_FLAG = ApiIdConverter.getFlag(89); //Implant; private Boolean isSingleton = null; private Long itemId = null; private ItemFlag itemFlag = null; private String locationFlag = null; private Long locationId = null; private Integer quantity = null; private Integer typeId = null; /** * New */ private RawAsset() { } public static RawAsset create() { return new RawAsset(); } /** * IndustryJob * * @param industryJob * @param output */ public RawAsset(MyIndustryJob industryJob, boolean output) { if (output && industryJob.isManufacturing()) { isSingleton = false; itemId = RawConverter.toLong(industryJob.getJobID()); //This item doesn't exist yet, need a new itemID switch (industryJob.getActivity()) { //Can not be null case ACTIVITY_MANUFACTURING: //Manufacturing itemFlag = MANUFACTURING_FLAG; break; case ACTIVITY_REACTIONS: //Reactions itemFlag = REACTIONS_FLAG; break; default: itemFlag = ApiIdConverter.getFlag(0); //Should never happen, but, better safe than sorry... } locationId = industryJob.getLocationID(); quantity = industryJob.getOutputCount(); typeId = industryJob.getProductTypeID(); } else if (output && industryJob.isCopying()) { isSingleton = true; itemId = RawConverter.toLong(industryJob.getJobID()); //This item doesn't exist yet, need a new itemID itemFlag = COPYING_FLAG; locationId = industryJob.getLocationID(); quantity = -2; //BPC typeId = industryJob.getBlueprintTypeID(); } else { isSingleton = true; itemId = industryJob.getBlueprintID(); //blueprint itemID itemFlag = INDUSTRY_JOB_FLAG; locationId = industryJob.getLocationID(); if (industryJob.isBPO()) { quantity = -1; } else { quantity = -2; } typeId = industryJob.getBlueprintTypeID(); } } /** * MarketOrder * * @param marketOrder */ public RawAsset(MyMarketOrder marketOrder) { isSingleton = false; itemId = marketOrder.getOrderID(); if (marketOrder.isBuyOrder()) { //Buy itemFlag = MARKET_ORDER_BUY_FLAG; } else { //Sell itemFlag = MARKET_ORDER_SELL_FLAG; } locationId = marketOrder.getLocationID(); quantity = marketOrder.getVolumeRemain(); typeId = marketOrder.getTypeID(); } /** * ContractItem * * @param contractItem */ public RawAsset(MyContractItem contractItem) { isSingleton = contractItem.isSingleton(); if (contractItem.getItemID() != null) { itemId = contractItem.getItemID(); } else { itemId = contractItem.getRecordID(); } if (contractItem.isIncluded()) { //Sell itemFlag = CONTRACT_INCLUDED_FLAG; } else { //Buy itemFlag = CONTRACT_EXCLUDED_FLAG; } if (contractItem.getContract().getStartLocationID() != null) { locationId = contractItem.getContract().getStartLocationID(); } else { locationId = 0L; } quantity = RawConverter.toAssetQuantity(contractItem.getQuantity(), contractItem.getRawQuantity()); typeId = contractItem.getTypeID(); } /** * Raw * * @param asset */ protected RawAsset(RawAsset asset) { isSingleton = asset.isSingleton; itemId = asset.itemId; itemFlag = asset.itemFlag; locationFlag = asset.locationFlag; locationId = asset.locationId; quantity = asset.quantity; typeId = asset.typeId; } /** * ESI Character * * @param asset */ public RawAsset(CharacterAssetsResponse asset) { if (asset.getQuantity() != null && asset.getQuantity() < 0 && asset.getQuantity() == -2) { //rawQuantity: Quantity should tell us if it's a BPC or BPO isSingleton = true; } else { isSingleton = asset.getIsSingleton(); } itemId = asset.getItemId(); itemFlag = RawConverter.toFlag(asset.getLocationFlag()); locationFlag = asset.getLocationFlagString(); locationId = asset.getLocationId(); if (asset.getQuantity() == 1) { if (asset.getIsBlueprintCopy() != null && asset.getIsBlueprintCopy()) { quantity = -2; } else { quantity = -1; } } else { quantity = SafeConverter.toInteger(asset.getQuantity()); } typeId = SafeConverter.toInteger(asset.getTypeId()); } /** * ESI Corporation * * @param asset */ public RawAsset(CorporationAssetsResponse asset) { if (asset.getQuantity() != null && asset.getQuantity() < 0 && asset.getQuantity() == -2) { //rawQuantity: Quantity should tell us if it's a BPC or BPO isSingleton = true; } else { isSingleton = asset.getIsSingleton(); } itemId = asset.getItemId(); itemFlag = RawConverter.toFlag(asset.getLocationFlag()); locationFlag = asset.getLocationFlagString(); locationId = asset.getLocationId(); if (asset.getQuantity() == 1) { if (asset.getIsBlueprintCopy() != null && asset.getIsBlueprintCopy()) { quantity = -2; } else { quantity = -1; } } else { quantity = SafeConverter.toInteger(asset.getQuantity()); } typeId = SafeConverter.toInteger(asset.getTypeId()); } /** * ESI Plugged in Implant * * @param clone * @param impantTypeID */ public RawAsset(RawClone clone, Integer impantTypeID) { isSingleton = true; //Unpacked long combinedId = Long.parseLong(clone.getJumpCloneID() + "" + impantTypeID); itemId = combinedId; itemFlag = IMPLANT_FLAG; locationId = clone.getLocationID(); quantity = 1; //Plugged in AKA always 1 typeId = impantTypeID; } /** * ESI Jump Clone * * @param clone */ public RawAsset(RawClone clone) { isSingleton = true; //Unpacked itemId = clone.getJumpCloneID(); if (clone.isActive()) { itemFlag = ACTIVE_CLONE_FLAG; } else { itemFlag = JUMP_CLONE_FLAG; } //Implant locationId = clone.getLocationID(); quantity = 1; //Plugged in AKA always 1 typeId = 0; } /** * ESI Ship * * @param shipType * @param shipLocation */ public RawAsset(CharacterShipResponse shipType, CharacterLocationResponse shipLocation) { isSingleton = true; //Unpacked itemId = shipType.getShipItemId(); itemFlag = ApiIdConverter.getFlag(0); //None locationId = RawConverter.toLocationID(shipLocation); quantity = 1; //Unpacked AKA always 1 typeId = SafeConverter.toInteger(shipType.getShipTypeId()); } /** * ESI Planetary Interaction Asset * * @param planet * @param pin * @param content */ public RawAsset(CharacterPlanetsResponse planet, PlanetPin pin, PinContent content) { isSingleton = false; //Packed itemId = Long.valueOf(pin.getPinId() + "" + content.getTypeId()); //Semi unique itemFlag = ApiIdConverter.getFlag(0); //None locationId = planet.getPlanetId(); //Planet quantity = content.getAmount().intValue(); //Not perfect, but, will have to do typeId = SafeConverter.toInteger(content.getTypeId()); } /** * ESI Planetary Interaction Facility * * @param planet * @param pin */ public RawAsset(CharacterPlanetsResponse planet, PlanetPin pin) { isSingleton = false; //Packed itemId = pin.getPinId(); //Semi unique itemFlag = ApiIdConverter.getFlag(0); //None locationId = (long) planet.getPlanetId(); //Planet quantity = 1; typeId = SafeConverter.toInteger(pin.getTypeId()); } /** * Singleton: Unpackaged. * * @return true if unpackaged - false if packaged */ public final Boolean isSingleton() { return isSingleton; } public void setSingleton(Boolean isSingleton) { this.isSingleton = isSingleton; } public Long getItemID() { return itemId; } public final void setItemID(Long itemId) { this.itemId = itemId; } public ItemFlag getItemFlag() { return itemFlag; } public final void setItemFlag(ItemFlag itemFlag) { this.itemFlag = itemFlag; } public String getLocationFlagString() { return locationFlag; } public void setLocationFlagString(String locationFlagString) { this.locationFlag = locationFlagString; } public long getLocationID() { return locationId; } public final void setLocationID(Long locationId) { this.locationId = locationId; } public final Integer getQuantity() { return quantity; } public void setQuantity(Integer quantity) { this.quantity = quantity; } public Integer getTypeID() { return typeId; } public void setTypeID(Integer typeId) { this.typeId = typeId; } @Override public int hashCode() { int hash = 7; hash = 37 * hash + Objects.hashCode(this.itemId); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final RawAsset other = (RawAsset) obj; if (!Objects.equals(this.itemId, other.itemId)) { return false; } return Objects.equals(this.typeId, other.typeId); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawBlueprint.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import net.nikr.eve.jeveasset.data.sde.ItemFlag; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.CharacterBlueprintsResponse; import net.troja.eve.esi.model.CorporationBlueprintsResponse; public class RawBlueprint { private Long itemId = null; private ItemFlag itemFlag; private String locationFlag = null; private Long locationId = null; private Integer materialEfficiency = null; private Integer quantity = null; private Integer runs = null; private Integer timeEfficiency = null; private Integer typeId = null; /** * New */ private RawBlueprint() { } public static RawBlueprint create() { return new RawBlueprint(); } /** * Raw (Never used) * * @param blueprint */ private RawBlueprint(RawBlueprint blueprint) { itemId = blueprint.itemId; itemFlag = blueprint.itemFlag; locationFlag = blueprint.locationFlag; locationId = blueprint.locationId; materialEfficiency = blueprint.materialEfficiency; quantity = blueprint.quantity; runs = blueprint.runs; timeEfficiency = blueprint.timeEfficiency; typeId = blueprint.typeId; } /** * ESI Character * * @param blueprint */ public RawBlueprint(CharacterBlueprintsResponse blueprint) { itemId = blueprint.getItemId(); itemFlag = RawConverter.toFlag(blueprint.getLocationFlag()); locationFlag = blueprint.getLocationFlagString(); locationId = blueprint.getLocationId(); materialEfficiency = SafeConverter.toInteger(blueprint.getMaterialEfficiency()); quantity = SafeConverter.toInteger(blueprint.getQuantity()); runs = SafeConverter.toInteger(blueprint.getRuns()); timeEfficiency = SafeConverter.toInteger(blueprint.getTimeEfficiency()); typeId = SafeConverter.toInteger(blueprint.getTypeId()); } /** * ESI Corporation * * @param blueprint */ public RawBlueprint(CorporationBlueprintsResponse blueprint) { itemId = blueprint.getItemId(); itemFlag = RawConverter.toFlag(blueprint.getLocationFlag()); locationFlag = blueprint.getLocationFlagString(); locationId = blueprint.getLocationId(); materialEfficiency = SafeConverter.toInteger(blueprint.getMaterialEfficiency()); quantity = SafeConverter.toInteger(blueprint.getQuantity()); runs = SafeConverter.toInteger(blueprint.getRuns()); timeEfficiency = SafeConverter.toInteger(blueprint.getTimeEfficiency()); typeId = SafeConverter.toInteger(blueprint.getTypeId()); } public Long getItemID() { return itemId; } public void setItemID(Long itemId) { this.itemId = itemId; } public void setItemFlag(ItemFlag itemFlag) { this.itemFlag = itemFlag; } public int getFlagID() { return itemFlag.getFlagID(); } public String getFlagName() { return itemFlag.getFlagName(); } public String getLocationFlagString() { return locationFlag; } public void setLocationFlagString(String locationFlagString) { this.locationFlag = locationFlagString; } public Long getLocationID() { return locationId; } public void setLocationID(Long locationId) { this.locationId = locationId; } public Integer getMaterialEfficiency() { return materialEfficiency; } public void setMaterialEfficiency(Integer materialEfficiency) { this.materialEfficiency = materialEfficiency; } public Integer getQuantity() { return quantity; } public void setQuantity(Integer quantity) { this.quantity = quantity; } public Integer getRuns() { return runs; } public void setRuns(Integer runs) { this.runs = runs; } public Integer getTimeEfficiency() { return timeEfficiency; } public void setTimeEfficiency(Integer timeEfficiency) { this.timeEfficiency = timeEfficiency; } public Integer getTypeID() { return typeId; } public void setTypeID(Integer typeId) { this.typeId = typeId; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawClone.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import java.util.ArrayList; import java.util.List; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.JumpClone; public class RawClone { private List implants = new ArrayList<>(); private Long jumpCloneId; private Long locationId; private String name; private boolean active; public static RawClone create() { return new RawClone(); } private RawClone() { } public RawClone(RawClone rawClone) { this.implants = new ArrayList<>(rawClone.implants); this.jumpCloneId = rawClone.jumpCloneId; this.locationId = rawClone.locationId; this.name = rawClone.name; this.active = rawClone.active; } /** * Jump Clone * @param clone */ public RawClone(JumpClone clone) { this.implants = SafeConverter.toInteger(clone.getImplants()); this.jumpCloneId = clone.getJumpCloneId(); this.locationId = clone.getLocationId(); this.name = clone.getName(); this.active = false; } /** * Active Clone * @param implants * @param jumpCloneId * @param locationId */ public RawClone(List implants, Long jumpCloneId, Long locationId) { this.implants = SafeConverter.toInteger(implants); this.jumpCloneId = jumpCloneId; this.locationId = locationId; this.name = null; this.active = true; } public List getImplants() { return implants; } public void setImplants(List implants) { this.implants = implants; } public Long getJumpCloneID() { return jumpCloneId; } public void setJumpCloneID(Long jumpCloneId) { this.jumpCloneId = jumpCloneId; } public Long getLocationID() { return locationId; } public void setLocationID(Long locationId) { this.locationId = locationId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isActive() { return active; } public void setActive(boolean active) { this.active = active; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawContract.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import java.util.Date; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.CharacterContractsResponse; import net.troja.eve.esi.model.CorporationContractsResponse; public class RawContract { public enum ContractAvailability { PUBLIC("public"), PERSONAL("personal"), CORPORATION("corporation"), ALLIANCE("alliance"); private final String value; ContractAvailability(String value) { this.value = value; } public String getValue() { return value; } } public enum ContractStatus { OUTSTANDING("outstanding"), IN_PROGRESS("in_progress"), FINISHED_ISSUER("finished_issuer"), FINISHED_CONTRACTOR("finished_contractor"), FINISHED("finished"), CANCELLED("cancelled"), REJECTED("rejected"), FAILED("failed"), DELETED("deleted"), REVERSED("reversed"), ARCHIVED("archived"); private final String value; ContractStatus(String value) { this.value = value; } public String getValue() { return value; } } public enum ContractType { UNKNOWN("unknown"), ITEM_EXCHANGE("item_exchange"), AUCTION("auction"), COURIER("courier"), LOAN("loan"); private final String value; ContractType(String value) { this.value = value; } public String getValue() { return value; } } private Integer acceptorId = null; private Integer assigneeId = null; private String availability = null; private ContractAvailability availabilityEnum = null; private Double buyout = null; private Double collateral = null; private Integer contractId = null; private Date dateAccepted = null; private Date dateCompleted = null; private Date dateExpired = null; private Date dateIssued = null; private Integer daysToComplete = null; private Long endLocationId = null; private Boolean forCorporation = null; private Integer issuerCorporationId = null; private Integer issuerId = null; private Double price = null; private Double reward = null; private Long startLocationId = null; private String status = null; private ContractStatus statusEnum = null; private String title = null; private String type = null; private ContractType typeEnum = null; private Double volume = null; /** * New */ private RawContract() { } public static RawContract create() { return new RawContract(); } /** * Raw * * @param contract */ protected RawContract(RawContract contract) { acceptorId = contract.acceptorId; assigneeId = contract.assigneeId; availability = contract.availability; availabilityEnum = contract.availabilityEnum; buyout = contract.buyout; collateral = contract.collateral; contractId = contract.contractId; dateAccepted = contract.dateAccepted; dateCompleted = contract.dateCompleted; dateExpired = contract.dateExpired; dateIssued = contract.dateIssued; daysToComplete = contract.daysToComplete; endLocationId = contract.endLocationId; forCorporation = contract.forCorporation; issuerCorporationId = contract.issuerCorporationId; issuerId = contract.issuerId; price = contract.price; reward = contract.reward; startLocationId = contract.startLocationId; status = contract.status; statusEnum = contract.statusEnum; title = contract.title; type = contract.type; typeEnum = contract.typeEnum; volume = contract.volume; } /** * ESI Character * * @param contract */ public RawContract(CharacterContractsResponse contract) { acceptorId = SafeConverter.toInteger(contract.getAcceptorId()); assigneeId = SafeConverter.toInteger(contract.getAssigneeId()); availability = contract.getAvailabilityString(); availabilityEnum = RawConverter.toContractAvailability(contract.getAvailability()); buyout = contract.getBuyout(); collateral = contract.getCollateral(); contractId = SafeConverter.toInteger(contract.getContractId()); dateAccepted = RawConverter.toDate(contract.getDateAccepted()); dateCompleted = RawConverter.toDate(contract.getDateCompleted()); dateExpired = RawConverter.toDate(contract.getDateExpired()); dateIssued = RawConverter.toDate(contract.getDateIssued()); daysToComplete = SafeConverter.toInteger(contract.getDaysToComplete()); endLocationId = contract.getEndLocationId(); forCorporation = contract.getForCorporation(); issuerCorporationId = SafeConverter.toInteger(contract.getIssuerCorporationId()); issuerId = SafeConverter.toInteger(contract.getIssuerId()); price = contract.getPrice(); reward = contract.getReward(); startLocationId = contract.getStartLocationId(); status = contract.getStatusString(); statusEnum = RawConverter.toContractStatus(contract.getStatus()); title = contract.getTitle(); type = contract.getTypeString(); typeEnum = RawConverter.toContractType(contract.getType()); volume = contract.getVolume(); } /** * ESI Corporation * * @param contract */ public RawContract(CorporationContractsResponse contract) { acceptorId = SafeConverter.toInteger(contract.getAcceptorId()); assigneeId = SafeConverter.toInteger(contract.getAssigneeId()); availability = contract.getAvailabilityString(); availabilityEnum = RawConverter.toContractAvailability(contract.getAvailability()); buyout = contract.getBuyout(); collateral = contract.getCollateral(); contractId = SafeConverter.toInteger(contract.getContractId()); dateAccepted = RawConverter.toDate(contract.getDateAccepted()); dateCompleted = RawConverter.toDate(contract.getDateCompleted()); dateExpired = RawConverter.toDate(contract.getDateExpired()); dateIssued = RawConverter.toDate(contract.getDateIssued()); daysToComplete = SafeConverter.toInteger(contract.getDaysToComplete()); endLocationId = contract.getEndLocationId(); forCorporation = contract.getForCorporation(); issuerCorporationId = SafeConverter.toInteger(contract.getIssuerCorporationId()); issuerId = SafeConverter.toInteger(contract.getIssuerId()); price = contract.getPrice(); reward = contract.getReward(); startLocationId = contract.getStartLocationId(); status = contract.getStatusString(); statusEnum = RawConverter.toContractStatus(contract.getStatus()); title = contract.getTitle(); type = contract.getTypeString(); typeEnum = RawConverter.toContractType(contract.getType()); volume = contract.getVolume(); } public final long getAcceptorID() { return acceptorId; } public void setAcceptorID(Integer acceptorId) { this.acceptorId = acceptorId; } public final long getAssigneeID() { return assigneeId; } public void setAssigneeID(Integer assigneeId) { this.assigneeId = assigneeId; } public ContractAvailability getAvailability() { return availabilityEnum; } public void setAvailability(ContractAvailability availability) { this.availabilityEnum = availability; } public String getAvailabilityString() { return availability; } public void setAvailabilityString(String availabilityString) { this.availability = availabilityString; } public Double getBuyout() { return buyout; } public void setBuyout(Double buyout) { this.buyout = buyout; } public Double getCollateral() { return collateral; } public void setCollateral(Double collateral) { this.collateral = collateral; } public Integer getContractID() { return contractId; } public void setContractID(Integer contractId) { this.contractId = contractId; } public Date getDateAccepted() { return dateAccepted; } public void setDateAccepted(Date dateAccepted) { this.dateAccepted = dateAccepted; } public Date getDateCompleted() { return dateCompleted; } public void setDateCompleted(Date dateCompleted) { this.dateCompleted = dateCompleted; } public Date getDateExpired() { return dateExpired; } public void setDateExpired(Date dateExpired) { this.dateExpired = dateExpired; } public Date getDateIssued() { return dateIssued; } public void setDateIssued(Date dateIssued) { this.dateIssued = dateIssued; } public Integer getDaysToComplete() { return daysToComplete; } public void setDaysToComplete(Integer daysToComplete) { this.daysToComplete = daysToComplete; } public Long getEndLocationID() { return endLocationId; } public void setEndLocationID(Long endLocationId) { this.endLocationId = endLocationId; } public Boolean isForCorp() { return forCorporation; } public void setForCorporation(Boolean forCorporation) { this.forCorporation = forCorporation; } public final long getIssuerCorpID() { return issuerCorporationId; } public void setIssuerCorporationID(Integer issuerCorporationId) { this.issuerCorporationId = issuerCorporationId; } public final long getIssuerID() { return issuerId; } public void setIssuerID(Integer issuerId) { this.issuerId = issuerId; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } public Double getReward() { return reward; } public void setReward(Double reward) { this.reward = reward; } public Long getStartLocationID() { return startLocationId; } public void setStartLocationID(Long startLocationId) { this.startLocationId = startLocationId; } public ContractStatus getStatus() { return statusEnum; } public void setStatus(ContractStatus status) { this.statusEnum = status; } public String getStatusString() { return status; } public void setStatusString(String statusString) { this.status = statusString; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public ContractType getType() { return typeEnum; } public void setType(ContractType type) { this.typeEnum = type; } public String getTypeString() { return type; } public void setTypeString(String typeString) { this.type = typeString; } public Double getVolume() { return volume; } public void setVolume(Double volume) { this.volume = volume; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawContractItem.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import net.nikr.eve.jeveasset.data.api.my.MyBlueprint; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.ContractItemsResponse; import net.troja.eve.esi.model.PublicContractsItemsResponse; public class RawContractItem { private Boolean isIncluded = null; private Boolean isSingleton = null; private Integer quantity = null; private Integer rawQuantity = null; private Long recordId = null; private Integer typeId = null; private Long itemId = null; private Integer runs = null; private Integer materialEfficiency = null; private Integer timeEfficiency = null; /** * New */ private RawContractItem() { } public static RawContractItem create() { return new RawContractItem(); } /** * Raw * * @param contractItem */ protected RawContractItem(RawContractItem contractItem) { isIncluded = contractItem.isIncluded; isSingleton = contractItem.isSingleton; quantity = contractItem.quantity; rawQuantity = contractItem.rawQuantity; recordId = contractItem.recordId; typeId = contractItem.typeId; itemId = contractItem.itemId; runs = contractItem.runs; materialEfficiency = contractItem.materialEfficiency; timeEfficiency = contractItem.timeEfficiency; } /** * ESI Character/Corporation * * @param contractItem */ public RawContractItem(ContractItemsResponse contractItem) { isIncluded = contractItem.getIsIncluded(); isSingleton = contractItem.getIsSingleton(); quantity = SafeConverter.toInteger(contractItem.getQuantity()); rawQuantity = SafeConverter.toInteger(contractItem.getRawQuantity()); recordId = contractItem.getRecordId(); typeId = SafeConverter.toInteger(contractItem.getTypeId()); } /** * ESI Public * * @param contractItem */ public RawContractItem(PublicContractsItemsResponse contractItem) { isIncluded = contractItem.getIsIncluded(); isSingleton = false; quantity = SafeConverter.toInteger(contractItem.getQuantity()); if (RawConverter.toBoolean(contractItem.getIsBlueprintCopy())) { rawQuantity = -2; } else { rawQuantity = SafeConverter.toInteger(contractItem.getQuantity()); } recordId = contractItem.getRecordId(); typeId = SafeConverter.toInteger(contractItem.getTypeId()); itemId = contractItem.getItemId(); runs = SafeConverter.toInteger(contractItem.getRuns()); materialEfficiency = SafeConverter.toInteger(contractItem.getMaterialEfficiency()); timeEfficiency = SafeConverter.toInteger(contractItem.getTimeEfficiency()); } public MyBlueprint getBlueprint() { if (runs != null || materialEfficiency != null || timeEfficiency != null) { return new MyBlueprint(this); } else { return null; } } public Boolean isIncluded() { return isIncluded; } public final void setIncluded(Boolean isIncluded) { this.isIncluded = isIncluded; } public Boolean isSingleton() { return isSingleton; } public final void setSingleton(Boolean isSingleton) { this.isSingleton = isSingleton; } public Integer getQuantity() { return quantity; } public final void setQuantity(Integer quantity) { this.quantity = quantity; } public Integer getRawQuantity() { return rawQuantity; } public final void setRawQuantity(Integer rawQuantity) { this.rawQuantity = rawQuantity; } public Long getRecordID() { return recordId; } public final void setRecordID(Long recordId) { this.recordId = recordId; } public Integer getTypeID() { return typeId; } public final void setTypeID(Integer typeId) { this.typeId = typeId; } public Long getItemID() { return itemId; } public void setItemID(Long itemId) { this.itemId = itemId; } public Integer getLicensedRuns() { return runs; } public void setLicensedRuns(Integer runs) { this.runs = runs; } public Integer getME() { return materialEfficiency; } public void setME(Integer materialEfficiency) { this.materialEfficiency = materialEfficiency; } public Integer getTE() { return timeEfficiency; } public void setTE(Integer timeEfficiency) { this.timeEfficiency = timeEfficiency; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawExtraction.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import java.util.Date; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.CorporationMiningExtractionsResponse; public class RawExtraction { private Date chunkArrivalTime; private Date extractionStartTime; private Integer moonId; private Date naturalDecayTime; private Long structureId; private RawExtraction() { } public static RawExtraction create() { return new RawExtraction(); } public RawExtraction(RawExtraction extraction) { this.chunkArrivalTime = extraction.chunkArrivalTime; this.extractionStartTime = extraction.extractionStartTime; this.moonId = extraction.moonId; this.naturalDecayTime = extraction.naturalDecayTime; this.structureId = extraction.structureId; } public RawExtraction(CorporationMiningExtractionsResponse response) { this.chunkArrivalTime = RawConverter.toDate(response.getChunkArrivalTime()); this.extractionStartTime = RawConverter.toDate(response.getExtractionStartTime()); this.moonId = SafeConverter.toInteger(response.getMoonId()); this.naturalDecayTime = RawConverter.toDate(response.getNaturalDecayTime()); this.structureId = response.getStructureId(); } public Date getChunkArrivalTime() { return chunkArrivalTime; } public void setChunkArrivalTime(Date chunkArrivalTime) { this.chunkArrivalTime = chunkArrivalTime; } public Date getExtractionStartTime() { return extractionStartTime; } public void setExtractionStartTime(Date extractionStartTime) { this.extractionStartTime = extractionStartTime; } public Integer getMoonID() { return moonId; } public void setMoonID(Integer moonId) { this.moonId = moonId; } public Date getNaturalDecayTime() { return naturalDecayTime; } public void setNaturalDecayTime(Date naturalDecayTime) { this.naturalDecayTime = naturalDecayTime; } public Long getStructureID() { return structureId; } public void setStructureID(Long structureId) { this.structureId = structureId; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawIndustryJob.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import java.util.Date; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.CharacterIndustryJobsResponse; import net.troja.eve.esi.model.CorporationIndustryJobsResponse; public class RawIndustryJob { public enum IndustryJobStatus { ACTIVE("active"), CANCELLED("cancelled"), DELIVERED("delivered"), PAUSED("paused"), READY("ready"), REVERTED("reverted"), ARCHIVED("archived"); private final String value; IndustryJobStatus(String value) { this.value = value; } public String getValue() { return value; } } private Integer activityId = null; private Long blueprintId = null; private Long blueprintLocationId = null; private Integer blueprintTypeId = null; private Integer completedCharacterId = null; private Date completedDate = null; private Double cost = null; private Integer duration = null; private Date endDate = null; private Long facilityId = null; private Integer installerId = null; private Integer jobId = null; private Integer licensedRuns = null; private Long outputLocationId = null; private Date pauseDate = null; private Float probability = null; private Integer productTypeId = null; private Integer runs = null; private Date startDate = null; private Long stationId = null; private String status = null; private IndustryJobStatus statusEnum = null; private Integer successfulRuns = null; /** * New */ private RawIndustryJob() { } public static RawIndustryJob create() { return new RawIndustryJob(); } /** * Raw * * @param industryJob */ protected RawIndustryJob(RawIndustryJob industryJob) { activityId = industryJob.activityId; blueprintId = industryJob.blueprintId; blueprintLocationId = industryJob.blueprintLocationId; blueprintTypeId = industryJob.blueprintTypeId; completedCharacterId = industryJob.completedCharacterId; completedDate = industryJob.completedDate; cost = industryJob.cost; duration = industryJob.duration; endDate = industryJob.endDate; facilityId = industryJob.facilityId; installerId = industryJob.installerId; jobId = industryJob.jobId; licensedRuns = industryJob.licensedRuns; outputLocationId = industryJob.outputLocationId; pauseDate = industryJob.pauseDate; probability = industryJob.probability; productTypeId = industryJob.productTypeId; runs = industryJob.runs; startDate = industryJob.startDate; stationId = industryJob.stationId; status = industryJob.status; statusEnum = industryJob.statusEnum; successfulRuns = industryJob.successfulRuns; } /** * ESI Character * * @param industryJob */ public RawIndustryJob(CharacterIndustryJobsResponse industryJob) { activityId = SafeConverter.toInteger(industryJob.getActivityId()); blueprintId = industryJob.getBlueprintId(); blueprintLocationId = industryJob.getBlueprintLocationId(); blueprintTypeId = SafeConverter.toInteger(industryJob.getBlueprintTypeId()); completedCharacterId = SafeConverter.toInteger(industryJob.getCompletedCharacterId()); completedDate = RawConverter.toDate(industryJob.getCompletedDate()); cost = industryJob.getCost(); duration = SafeConverter.toInteger(industryJob.getDuration()); endDate = RawConverter.toDate(industryJob.getEndDate()); facilityId = industryJob.getFacilityId(); installerId = SafeConverter.toInteger(industryJob.getInstallerId()); jobId = SafeConverter.toInteger(industryJob.getJobId()); licensedRuns = SafeConverter.toInteger(industryJob.getLicensedRuns()); outputLocationId = industryJob.getOutputLocationId(); pauseDate = RawConverter.toDate(industryJob.getPauseDate()); probability = SafeConverter.toFloat(industryJob.getProbability()); productTypeId = SafeConverter.toInteger(industryJob.getProductTypeId()); runs = SafeConverter.toInteger(industryJob.getRuns()); startDate = RawConverter.toDate(industryJob.getStartDate()); stationId = industryJob.getStationId(); status = industryJob.getStatusString(); statusEnum = RawConverter.toIndustryJobStatus(industryJob.getStatus()); successfulRuns = SafeConverter.toInteger(industryJob.getSuccessfulRuns()); } /** * ESI Corporation * * @param industryJob */ public RawIndustryJob(CorporationIndustryJobsResponse industryJob) { activityId = SafeConverter.toInteger(industryJob.getActivityId()); blueprintId = industryJob.getBlueprintId(); blueprintLocationId = industryJob.getBlueprintLocationId(); blueprintTypeId = SafeConverter.toInteger(industryJob.getBlueprintTypeId()); completedCharacterId = SafeConverter.toInteger(industryJob.getCompletedCharacterId()); completedDate = RawConverter.toDate(industryJob.getCompletedDate()); cost = industryJob.getCost(); duration = SafeConverter.toInteger(industryJob.getDuration()); endDate = RawConverter.toDate(industryJob.getEndDate()); facilityId = industryJob.getFacilityId(); installerId = SafeConverter.toInteger(industryJob.getInstallerId()); jobId = SafeConverter.toInteger(industryJob.getJobId()); licensedRuns = SafeConverter.toInteger(industryJob.getLicensedRuns()); outputLocationId = industryJob.getOutputLocationId(); pauseDate = RawConverter.toDate(industryJob.getPauseDate()); probability = SafeConverter.toFloat(industryJob.getProbability()); productTypeId = SafeConverter.toInteger(industryJob.getProductTypeId()); runs = SafeConverter.toInteger(industryJob.getRuns()); startDate = RawConverter.toDate(industryJob.getStartDate()); stationId = industryJob.getLocationId(); status = industryJob.getStatusString(); statusEnum = RawConverter.toIndustryJobStatus(industryJob.getStatus()); successfulRuns = SafeConverter.toInteger(industryJob.getSuccessfulRuns()); } public final Integer getActivityID() { return activityId; } public void setActivityID(Integer activityId) { this.activityId = activityId; } public Long getBlueprintID() { return blueprintId; } public void setBlueprintID(Long blueprintId) { this.blueprintId = blueprintId; } public Long getBlueprintLocationID() { return blueprintLocationId; } public void setBlueprintLocationID(Long blueprintLocationId) { this.blueprintLocationId = blueprintLocationId; } public Integer getBlueprintTypeID() { return blueprintTypeId; } public void setBlueprintTypeID(Integer blueprintTypeId) { this.blueprintTypeId = blueprintTypeId; } public Integer getCompletedCharacterID() { return completedCharacterId; } public void setCompletedCharacterID(Integer completedCharacterId) { this.completedCharacterId = completedCharacterId; } public Date getCompletedDate() { return completedDate; } public void setCompletedDate(Date completedDate) { this.completedDate = completedDate; } public Double getCost() { return cost; } public void setCost(Double cost) { this.cost = cost; } public Integer getDuration() { return duration; } public void setDuration(Integer duration) { this.duration = duration; } public final Date getEndDate() { return endDate; } public void setEndDate(Date endDate) { this.endDate = endDate; } public Long getFacilityID() { return facilityId; } public void setFacilityID(Long facilityId) { this.facilityId = facilityId; } public final long getInstallerID() { return installerId; } public void setInstallerID(Integer installerId) { this.installerId = installerId; } public Integer getJobID() { return jobId; } public void setJobID(Integer jobId) { this.jobId = jobId; } public final Integer getLicensedRuns() { return licensedRuns; } public void setLicensedRuns(Integer licensedRuns) { this.licensedRuns = licensedRuns; } public Long getOutputLocationID() { return outputLocationId; } public void setOutputLocationID(Long outputLocationId) { this.outputLocationId = outputLocationId; } public Date getPauseDate() { return pauseDate; } public void setPauseDate(Date pauseDate) { this.pauseDate = pauseDate; } public Float getProbability() { return probability; } public void setProbability(Float probability) { this.probability = probability; } public Integer getProductTypeID() { return productTypeId; } public void setProductTypeID(Integer productTypeId) { this.productTypeId = productTypeId; } public final int getRuns() { return runs; } public void setRuns(Integer runs) { this.runs = runs; } public Date getStartDate() { return startDate; } public void setStartDate(Date startDate) { this.startDate = startDate; } public Long getStationID() { return stationId; } public void setStationID(Long stationId) { this.stationId = stationId; } public IndustryJobStatus getStatus() { return statusEnum; } public void setStatus(IndustryJobStatus status) { this.statusEnum = status; } public String getStatusString() { return status; } public void setStatusString(String statusString) { this.status = statusString; } public Integer getSuccessfulRuns() { return successfulRuns; } public void setSuccessfulRuns(Integer successfulRuns) { this.successfulRuns = successfulRuns; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawJournal.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import java.util.Date; import net.nikr.eve.jeveasset.i18n.TabsJournal; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.CharacterWalletJournalResponse; import net.troja.eve.esi.model.CorporationWalletJournalResponse; public class RawJournal { public enum ArgName { STATION_NAME, NPC_NAME, DESTROYED_SHIP_TYPE_ID, PLAYER_NAME, JOB_ID, CONTRACT_ID, TRANSACTION_ID, CORPORATION_NAME, ALLIANCE_NAME, PLANET_NAME, } public enum ArgID { STATION_ID, NPC_ID, PLAYER_ID, SYSTEM_ID, CORPORATION_ID, ALLIANCE_ID, PLANET_ID, } public enum ContextType { STRUCTURE_ID("structure_id") { @Override protected String getI18N() { return TabsJournal.get().contextStructureID(); } }, STATION_ID("station_id") { @Override protected String getI18N() { return TabsJournal.get().contextStationID(); } }, MARKET_TRANSACTION_ID("market_transaction_id") { @Override protected String getI18N() { return TabsJournal.get().contextTransactionID(); } }, CHARACTER_ID("character_id") { @Override protected String getI18N() { return TabsJournal.get().contextCharacterID(); } }, CORPORATION_ID("corporation_id") { @Override protected String getI18N() { return TabsJournal.get().contextCorporationID(); } }, ALLIANCE_ID("alliance_id") { @Override protected String getI18N() { return TabsJournal.get().contextAllianceID(); } }, EVE_SYSTEM("eve_system") { @Override protected String getI18N() { return TabsJournal.get().contextEveID(); } }, INDUSTRY_JOB_ID("industry_job_id") { @Override protected String getI18N() { return TabsJournal.get().contextIndustryJobID(); } }, CONTRACT_ID("contract_id") { @Override protected String getI18N() { return TabsJournal.get().contextContractID(); } }, PLANET_ID("planet_id") { @Override protected String getI18N() { return TabsJournal.get().contextPlanetID(); } }, SYSTEM_ID("system_id") { @Override protected String getI18N() { return TabsJournal.get().contextSystemID(); } }, TYPE_ID("type_id") { @Override protected String getI18N() { return TabsJournal.get().contextTypeID(); } }; private final String value; ContextType(String value) { this.value = value; } public String getValue() { return value; } @Override public String toString() { return getI18N(); } protected abstract String getI18N(); } private Double amount = null; private Double balance = null; private Long contextId; private String contextIdType; private ContextType contextIdTypeEnum; private Date date = null; private String description; private Integer firstPartyId = null; private String reason = null; private Long id = null; private String refType = null; private RawJournalRefType refTypeEnum = null; private Integer secondPartyId = null; private Double tax = null; private Integer taxReceiverId = null; private Integer accountKey = null; /** * New */ private RawJournal() { } public static RawJournal create() { return new RawJournal(); } /** * Raw * * @param journal */ protected RawJournal(RawJournal journal) { amount = journal.amount; balance = journal.balance; date = journal.date; description = journal.description; contextId = journal.contextId; contextIdType = journal.contextIdType; contextIdTypeEnum = journal.contextIdTypeEnum; firstPartyId = journal.firstPartyId; reason = journal.reason; id = journal.id; refType = journal.refType; refTypeEnum = journal.refTypeEnum; secondPartyId = journal.secondPartyId; tax = journal.tax; taxReceiverId = journal.taxReceiverId; accountKey = journal.accountKey; } /** * ESI Character * * @param journal * @param accountKey */ public RawJournal(CharacterWalletJournalResponse journal, Integer accountKey) { amount = journal.getAmount(); balance = journal.getBalance(); contextId = journal.getContextId(); contextIdType = journal.getContextIdTypeString(); contextIdTypeEnum = RawConverter.toJournalContextType(journal.getContextIdType()); date = RawConverter.toDate(journal.getDate()); description = journal.getDescription(); firstPartyId = SafeConverter.toInteger(journal.getFirstPartyId()); reason = journal.getReason(); id = journal.getId(); refType = journal.getRefTypeString(); refTypeEnum = RawConverter.toJournalRefType(journal.getRefType()); secondPartyId = SafeConverter.toInteger(journal.getSecondPartyId()); tax = journal.getTax(); taxReceiverId = SafeConverter.toInteger(journal.getTaxReceiverId()); this.accountKey = accountKey; } /** * ESI Corporation * * @param journal * @param accountKey */ public RawJournal(CorporationWalletJournalResponse journal, Integer accountKey) { amount = journal.getAmount(); balance = journal.getBalance(); contextId = journal.getContextId(); contextIdType = journal.getContextIdTypeString(); contextIdTypeEnum = RawConverter.toJournalContextType(journal.getContextIdType()); date = RawConverter.toDate(journal.getDate()); description = journal.getDescription(); firstPartyId = SafeConverter.toInteger(journal.getFirstPartyId()); reason = journal.getReason(); id = journal.getId(); refType = journal.getRefTypeString(); refTypeEnum = RawConverter.toJournalRefType(journal.getRefType()); secondPartyId = SafeConverter.toInteger(journal.getSecondPartyId()); tax = journal.getTax(); taxReceiverId = SafeConverter.toInteger(journal.getTaxReceiverId()); this.accountKey = accountKey; } public Double getAmount() { return amount; } public void setAmount(Double amount) { this.amount = amount; } public Double getBalance() { return balance; } public void setBalance(Double balance) { this.balance = balance; } public Long getContextID() { return contextId; } public void setContextID(Long contextId) { this.contextId = contextId; } public ContextType getContextType() { return contextIdTypeEnum; } public String getContextTypeName() { if (contextIdTypeEnum == null) { return ""; } else { return contextIdTypeEnum.toString(); } } public void setContextType(ContextType contextType) { this.contextIdTypeEnum = contextType; } public String getContextTypeString() { return contextIdType; } public void setContextTypeString(String contextIdTypeString) { this.contextIdType = contextIdTypeString; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public final Integer getFirstPartyID() { return firstPartyId; } public void setFirstPartyID(Integer firstPartyId) { this.firstPartyId = firstPartyId; } public String getReason() { return reason; } public void setReason(String reason) { this.reason = reason; } public Long getRefID() { return id; } public void setRefID(Long refId) { this.id = refId; } public RawJournalRefType getRefType() { return refTypeEnum; } public void setRefType(RawJournalRefType refType) { this.refTypeEnum = refType; } public String getRefTypeString() { return refType; } public void setRefTypeString(String refTypeString) { this.refType = refTypeString; } public final Integer getSecondPartyID() { return secondPartyId; } public void setSecondPartyID(Integer secondPartyId) { this.secondPartyId = secondPartyId; } public Double getTaxAmount() { return tax; } public void setTax(Double tax) { this.tax = tax; } public Integer getTaxReceiverID() { return taxReceiverId; } public void setTaxReceiverID(Integer taxRecieverId) { this.taxReceiverId = taxRecieverId; } public Integer getAccountKey() { return accountKey; } public void setAccountKey(Integer accountKey) { this.accountKey = accountKey; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawJournalRefType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; public enum RawJournalRefType { UNDEFINED(0, "Undefined"), PLAYER_TRADING(1, "Player Trading", RawJournal.ArgName.STATION_NAME, RawJournal.ArgID.STATION_ID), MARKET_TRANSACTION(2, "Market Transaction", RawJournal.ArgName.TRANSACTION_ID, null), GM_CASH_TRANSFER(3, "GM Cash Transfer"), ATM_WITHDRAW(4, "ATM Withdraw"), ATM_DEPOSIT(5, "ATM Deposit"), BACKWARD_COMPATIBLE(6, "Backward Compatible"), MISSION_REWARD(7, "Mission Reward", RawJournal.ArgName.PLAYER_NAME, RawJournal.ArgID.PLAYER_ID), CLONE_ACTIVATION(8, "Clone Activation"), INHERITANCE(9, "Inheritance"), PLAYER_DONATION(10, "Player Donation"), CORPORATION_PAYMENT(11, "Corporation Payment"), DOCKING_FEE(12, "Docking Fee"), OFFICE_RENTAL_FEE(13, "Office Rental Fee"), FACTORY_SLOT_RENTAL_FEE(14, "Factory Slot Rental Fee"), REPAIR_BILL(15, "Repair Bill"), BOUNTY(16, "Bounty"), BOUNTY_PRIZE(17, "Bounty Prize", RawJournal.ArgName.NPC_NAME, RawJournal.ArgID.NPC_ID), AGENTS_TEMPORARY(18, "Agents_temporary"), INSURANCE(19, "Insurance", RawJournal.ArgName.DESTROYED_SHIP_TYPE_ID, null), MISSION_EXPIRATION(20, "Mission Expiration"), MISSION_COMPLETION(21, "Mission Completion"), SHARES(22, "Shares"), COURIER_MISSION_ESCROW(23, "Courier Mission Escrow"), MISSION_COST(24, "Mission Cost"), AGENT_MISCELLANEOUS(25, "Agent Miscellaneous"), LP_STORE(26, "LP Store"), AGENT_LOCATION_SERVICES(27, "Agent Location Services"), AGENT_DONATION(28, "Agent Donation"), AGENT_SECURITY_SERVICES(29, "Agent Security Services"), AGENT_MISSION_COLLATERAL_PAID(30, "Agent Mission Collateral Paid"), AGENT_MISSION_COLLATERAL_REFUNDED(31, "Agent Mission Collateral Refunded"), AGENTS_PREWARD(32, "Agents_preward"), AGENT_MISSION_REWARD(33, "Agent Mission Reward", RawJournal.ArgName.PLAYER_NAME, RawJournal.ArgID.PLAYER_ID), AGENT_MISSION_TIME_BONUS_REWARD(34, "Agent Mission Time Bonus Reward", RawJournal.ArgName.PLAYER_NAME, RawJournal.ArgID.PLAYER_ID), CSPA(35, "CSPA", RawJournal.ArgName.PLAYER_NAME, RawJournal.ArgID.PLAYER_ID), CSPAOFFLINEREFUND(36, "CSPAOfflineRefund"), CORPORATION_ACCOUNT_WITHDRAWAL(37, "Corporation Account Withdrawal", RawJournal.ArgName.PLAYER_NAME, RawJournal.ArgID.PLAYER_ID), CORPORATION_DIVIDEND_PAYMENT(38, "Corporation Dividend Payment"), CORPORATION_REGISTRATION_FEE(39, "Corporation Registration Fee"), CORPORATION_LOGO_CHANGE_COST(40, "Corporation Logo Change Cost", RawJournal.ArgName.CORPORATION_NAME, RawJournal.ArgID.CORPORATION_ID), RELEASE_OF_IMPOUNDED_PROPERTY(41, "Release Of Impounded Property"), MARKET_ESCROW(42, "Market Escrow"), AGENT_SERVICES_RENDERED(43, "Agent Services Rendered"), MARKET_FINE_PAID(44, "Market Fine Paid"), CORPORATION_LIQUIDATION(45, "Corporation Liquidation"), BROKERS_FEE(46, "Brokers Fee"), CORPORATION_BULK_PAYMENT(47, "Corporation Bulk Payment"), ALLIANCE_REGISTRATION_FEE(48, "Alliance Registration Fee"), WAR_FEE(49, "War Fee"), ALLIANCE_MAINTAINANCE_FEE(50, "Alliance Maintainance Fee", RawJournal.ArgName.ALLIANCE_NAME, RawJournal.ArgID.ALLIANCE_ID), CONTRABAND_FINE(51, "Contraband Fine"), CLONE_TRANSFER(52, "Clone Transfer"), ACCELERATION_GATE_FEE(53, "Acceleration Gate Fee"), TRANSACTION_TAX(54, "Transaction Tax"), JUMP_CLONE_INSTALLATION_FEE(55, "Jump Clone Installation Fee"), MANUFACTURING(56, "Manufacturing", RawJournal.ArgName.JOB_ID, null), RESEARCHING_TECHNOLOGY(57, "Researching Technology"), RESEARCHING_TIME_PRODUCTIVITY(58, "Researching Time Productivity"), RESEARCHING_MATERIAL_PRODUCTIVITY(59, "Researching Material Productivity"), COPYING(60, "Copying"), DUPLICATING(61, "Duplicating"), REVERSE_ENGINEERING(62, "Reverse Engineering"), CONTRACT_AUCTION_BID(63, "Contract Auction Bid", RawJournal.ArgName.CONTRACT_ID, null), CONTRACT_AUCTION_BID_REFUND(64, "Contract Auction Bid Refund", RawJournal.ArgName.CONTRACT_ID, null), CONTRACT_COLLATERAL(65, "Contract Collateral", RawJournal.ArgName.CONTRACT_ID, null), CONTRACT_REWARD_REFUND(66, "Contract Reward Refund", RawJournal.ArgName.CONTRACT_ID, null), CONTRACT_AUCTION_SOLD(67, "Contract Auction Sold", RawJournal.ArgName.CONTRACT_ID, null), CONTRACT_REWARD(68, "Contract Reward", RawJournal.ArgName.CONTRACT_ID, null), CONTRACT_COLLATERAL_REFUND(69, "Contract Collateral Refund", RawJournal.ArgName.CONTRACT_ID, null), CONTRACT_COLLATERAL_PAYOUT(70, "Contract Collateral Payout", RawJournal.ArgName.CONTRACT_ID, null), CONTRACT_PRICE(71, "Contract Price", RawJournal.ArgName.CONTRACT_ID, null), CONTRACT_BROKERS_FEE(72, "Contract Brokers Fee", RawJournal.ArgName.CONTRACT_ID, null), CONTRACT_SALES_TAX(73, "Contract Sales Tax", RawJournal.ArgName.CONTRACT_ID, null), CONTRACT_DEPOSIT(74, "Contract Deposit", RawJournal.ArgName.CONTRACT_ID, null), CONTRACT_DEPOSIT_SALES_TAX(75, "Contract Deposit Sales Tax", RawJournal.ArgName.CONTRACT_ID, null), SECURE_EVE_TIME_CODE_EXCHANGE(76, "Secure EVE Time Code Exchange"), CONTRACT_AUCTION_BID_CORP(77, "Contract Auction Bid (corp)"), CONTRACT_COLLATERAL_DEPOSITED_CORP(78, "Contract Collateral Deposited (corp)"), CONTRACT_PRICE_PAYMENT_CORP(79, "Contract Price Payment (corp)"), CONTRACT_BROKERS_FEE_CORP(80, "Contract Brokers Fee (corp)"), CONTRACT_DEPOSIT_CORP(81, "Contract Deposit (corp)"), CONTRACT_DEPOSIT_REFUND(82, "Contract Deposit Refund"), CONTRACT_REWARD_DEPOSITED(83, "Contract Reward Deposited"), CONTRACT_REWARD_DEPOSITED_CORP(84, "Contract Reward Deposited (corp)"), BOUNTY_PRIZES(85, "Bounty Prizes", null, RawJournal.ArgID.SYSTEM_ID), ADVERTISEMENT_LISTING_FEE(86, "Advertisement Listing Fee"), MEDAL_CREATION(87, "Medal Creation", RawJournal.ArgName.PLAYER_NAME, RawJournal.ArgID.PLAYER_ID), MEDAL_ISSUED(88, "Medal Issued", RawJournal.ArgName.PLAYER_NAME, RawJournal.ArgID.PLAYER_ID), BETTING(89, "Betting"), DNA_MODIFICATION_FEE(90, "DNA Modification Fee"), SOVEREIGNITY_BILL(91, "Sovereignity bill"), BOUNTY_PRIZE_CORPORATION_TAX(92, "Bounty Prize Corporation Tax"), AGENT_MISSION_REWARD_CORPORATION_TAX(93, "Agent Mission Reward Corporation Tax"), AGENT_MISSION_TIME_BONUS_REWARD_CORPORATION_TAX(94, "Agent Mission Time Bonus Reward Corporation Tax"), UPKEEP_ADJUSTMENT_FEE(95, "Upkeep adjustment fee"), PLANETARY_IMPORT_TAX(96, "Planetary Import Tax", RawJournal.ArgName.PLANET_NAME, RawJournal.ArgID.PLANET_ID), PLANETARY_EXPORT_TAX(97, "Planetary Export Tax", RawJournal.ArgName.PLANET_NAME, RawJournal.ArgID.PLANET_ID), PLANETARY_CONSTRUCTION(98, "Planetary Construction"), CORPORATE_REWARD_PAYOUT(99, "Corporate Reward Payout"), // MINIGAME_BETTING(100, "Minigame Betting"), BOUNTY_SURCHARGE(101, "Bounty Surcharge"), CONTRACT_REVERSAL(102, "Contract Reversal"), CORPORATE_REWARD_TAX(103, "Corporate Reward Tax"), STORE_PURCHASE(106, "Store Purchase"), STORE_PURCHASE_REFUND(107, "Store Purchase Refund"), PLEX_SOLD_FOR_AURUM(108, "PLEX sold for Aurum"), LOTTERY_GIVE_AWAY(109, "Lottery Give Away"), AURUM_TOKEN_EXCHANGED_FOR_AUR(111, "Aurum Token exchanged for Aur"), DATACORE_FEE(112, "Datacore Fee"), WAR_FEE_SURRENDER(113, "War fee surrender"), WAR_ALLY_CONTRACT(114, "War ally contract"), BOUNTY_REIMBURSEMENT(115, "Bounty Reimbursement"), KILL_RIGHT(116, "Kill Right Fee"), SECURITY_PROCESSING_FEE(117, "Security Processing Fee"), ESCROW_FOR_INDUSTRY_TEAM_AUCTION(118, "Escrow for Industry Team Auction"), REIMBURSEMENT_OF_ESCROW(119, "Reimbursement of escrow"), INDUSTRY_JOB_TAX(120, "Industry Job Tax", null, RawJournal.ArgID.STATION_ID), INFRASTRUCTURE_HUB_MAINTENANCE(122, "Infrastructure Hub maintenance"), ASSET_SAFETY_RECOVERY_TAX(123, "Asset Safety recovery Tax"), OPPORTUNITY_REWARD(124, "Opportunity reward"), PROJECT_DISCOVERY_REWARD(125, "Project Discovery reward"), PROJECT_DISCOVERY_TAX(126, "Project Discovery Tax"), REPROCESSING_TAX(127, "Reprocessing Tax"), JUMP_CLONE_ACTIVATION_FEE(128, "Jump Clone Activation Fee"), OPERATION_BONUS(129, "Operation Bonus"), RESOURCE_WARS_SITE_COMPLETION(131, "Resource Wars Site Completion"), DUEL_WAGER_ESCROW(132, "Duel Wager Escrow"), DUEL_WAGER_PAYMENT(133, "Duel Wager Payment"), DUEL_WAGER_REFUND(134, "Duel Wager Refund"), REACTIONS(135, "Reactions"), EXTERNAL_TRADE_FREEZE(136, "External Trade Freeze"), EXTERNAL_TRADE_THAW(137, "External Trade Thaw"), EXTERNAL_TRADE_DELIVERY(138, "External Trade Delivery"), SEASON_CHALLENGE_REWARD(139, "Season Challenge Reward"), STRUCTURE_GATE_JUMP(140, "Structure Gate Jump"), SKILL_PURCHASE(141, "Skill Purchase"), ITEM_TRADER_PAYMENT(142, "Item Trader Payment"), FLUX_TICKET_SALE(143, "Flux Ticket Sale"), //hypernet ref group FLUX_PAYOUT(144, "Flux Payout"), //hypernet ref group FLUX_TAX(145, "Flux Tax"), //hypernet ref group FLUX_TICKET_REPAYMENT(146, "Flux Ticket Repayment"), //hypernet ref group REDEEMED_ISK_TOKEN(147, "Redeemed Isk Token"), DAILY_CHALLENGE_REWARD(148, "Daily Challenge Reward"), MARKET_PROVIDER_TAX(149, "Market Provider Tax"), ESS_ESCROW_TRANSFER(155, "ESS Escrow Transfer"), MILESTONE_REWARD_PAYMENT(156, "Milestone Reward Payment"), UNDER_CONSTRUCTION(166, "Under Construction"), ALLIGNMENT_BASED_GATE_TOLL (168, "Allignment Based Gate Toll"), PROJECT_PAYOUTS (170, "Project Payouts"), INSURGENCY_CORRUPTION_CONTRIBUTION_REWARD (172, "Insurgency Corruption Contribution Reward"), INSURGENCY_SUPPRESSION_CONTRIBUTION_REWARD (173, "Insurgency Suppression Contribution Reward"), DAILY_GOAL_PAYOUTS (174, "Daily Goal Payouts"), DAILY_GOAL_PAYOUTS_TAX (175, "Daily Goal Payouts Tax"), COSMETIC_MARKET_COMPONENT_ITEM_PURCHASE (178, "Cosmetic Market Component Item Purchase"), COSMETIC_MARKET_SKIN_SALE_BROKER_FEE (179, "Cosmetic Market Skin Sale Broker Fee"), COSMETIC_MARKET_SKIN_PURCHASE (180, "Cosmetic Market Skin Purchase"), COSMETIC_MARKET_SKIN_SALE (181, "Cosmetic Market Skin Sale"), COSMETIC_MARKET_SKIN_SALE_TAX (182, "Cosmetic Market Skin Sale Tax"), COSMETIC_MARKET_SKIN_TRANSACTION (183, "Cosmetic Market Skin Sale Transaction"), SKYHOOK_CLAIM_FEE(184, "Skyhook Claim Fee"), AIR_CAREER_PROGRAM_REWARD(185, "Air Ccareer Program Reward"), FREELANCE_JOBS_DURATION_FEE(186, "Freelance Jobs Duration Fee"), FREELANCE_JOBS_BROADCASTING_FEE(187, "Freelance Jobs Broadcasting Fee"), FREELANCE_JOBS_REWARD_ESCROW(188, "Freelance Jobs Reward Escrow"), FREELANCE_JOBS_REWARD(189, "Freelance Jobs Reward"), FREELANCE_JOBS_ESCROW_REFUND(190, "Freelance Jobs Escrow Refund"), FREELANCE_JOBS_REWARD_CORPORATION_TAX(191, "Freelance Jobs Reward Corporation Tax"), GM_PLEX_FEE_REFUND(192, "GM PLEX Fee Refund"), MODIFY_ISK(10001, "Modify ISK"), PRIMARY_MARKETPLACE_PURCHASE(10002, "Primary Marketplace Purchase"), BATTLE_REWARD(10003, "Battle Reward"), NEW_CHARACTER_STARTING_FUNDS(10004, "New Character Starting Funds"), CORPORATION_ACCOUNT_WITHDRAWAL_2(10005, "Corporation Account Withdrawal"), CORPORATION_ACCOUNT_DEPOSIT(10006, "Corporation Account Deposit"), BATTLE_WP_WIN_REWARD(10007, "Battle WP Win Reward"), BATTLE_WP_LOSS_REWARD(10008, "Battle WP Loss Reward"), BATTLE_WIN_REWARD(10009, "Battle Win Reward"), BATTLE_LOSS_REWARD(10010, "Battle Loss Reward"), RESET_ISK_FOR_CHARACTER_RESET(10011, "Reset ISK for Character Reset"), DISTRICT_CONTRACT_DEPOSIT(10012, "District Contract Deposit"), DISTRICT_CONTRACT_DEPOSIT_REFUND(10013, "District Contract Deposit Refund"), DISTRICT_CONTRACT_COLLATERAL(10014, "District Contract Collateral"), DISTRICT_CONTRACT_COLLATERAL_REFUND(10015, "District Contract Collateral Refund"), DISTRICT_CONTRACT_REWARD(10016, "District Contract Reward"), DISTRICT_CLONE_TRANSPORTATION(10017, "District Clone Transportation"), DISTRICT_CLONE_TRANSPORTATION_REFUND(10018, "District Clone Transportation Refund"), DISTRICT_INFRASTRUCTURE(10019, "District Infrastructure"), DISTRICT_CLONE_SALES(10020, "District Clone Sales"), DISTRICT_CLONE_PURCHASE(10021, "District Clone Purchase"), BIOMASS_REWARD(10022, "Biomass Reward"), ISK_SWAP_REWARD(10023, "ISK Swap Reward"), MODIFY_UPLEX(11001, "Modify AUR"), RESPEC_PAYMENT(11002, "Respec payment"), ENTITLEMENT(11003, "Entitlement"), RESET_REIMBURSEMENT(11004, "Reset Reimbursement"), RESET_AUR_FOR_CHARACTER_RESET(11005, "Reset AUR for Character Reset"), DAILY_MISSION_CP(12001, "Daily mission CP"), WARBARGE_CP(12002, "Warbarge CP"), DONATE_CP(12003, "Donate CP"), USE_CP_FOR_CLONE_PACKS(12004, "Use CP for clone packs"), USE_CP_FOR_MOVING_CLONES(12005, "Use CP for moving clones"), USE_CP_FOR_SELLING_CLONES(12006, "Use CP for selling clones"), USE_CP_FOR_CHANGING_REINFORCEMENT(12007, "Use CP for changing reinforcement"), USE_CP_FOR_CHANGING_SURFACE_INFRASTRUCTURE(12008, "Use CP for changing surface infrastructure"), DAILY_MISSION_DK(13001, "Daily mission DK"), PLANETARY_CONQUEST_DK(13002, "Planetary conquest DK"), USE_DK_FOR_PURCHASING_ITEMS(13003, "Use DK for purchasing items"), USE_DK_FOR_REROLLING_MARKET(13004, "Use DK for rerolling market"), SELLING_CLONES_DK(13005, "Selling Clones DK"), ; private final int id; private final String value; private final RawJournal.ArgName argName; private final RawJournal.ArgID argID; private RawJournalRefType(int id, String value) { this.id = id; this.value = value; this.argName = null; this.argID = null; } private RawJournalRefType(int id, String value, RawJournal.ArgName argName, RawJournal.ArgID argID) { this.id = id; this.value = value; this.argName = argName; this.argID = argID; } public int getID() { return id; } public RawJournal.ArgName getArgName() { return argName; } public RawJournal.ArgID getArgID() { return argID; } @Override public String toString() { return value; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawLoyaltyPoints.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.CharacterLoyaltyPointsResponse; public class RawLoyaltyPoints { private Integer corporationId; private Integer loyaltyPoints; public static RawLoyaltyPoints create() { return new RawLoyaltyPoints(); } private RawLoyaltyPoints() { } public RawLoyaltyPoints(CharacterLoyaltyPointsResponse response) { corporationId = SafeConverter.toInteger(response.getCorporationId()); loyaltyPoints = SafeConverter.toInteger(response.getLoyaltyPoints()); } public RawLoyaltyPoints(RawLoyaltyPoints response) { corporationId = response.getCorporationID(); loyaltyPoints = response.getLoyaltyPoints(); } public Integer getCorporationID() { return corporationId; } public void setCorporationID(Integer corporationId) { this.corporationId = corporationId; } public Integer getLoyaltyPoints() { return loyaltyPoints; } public void setLoyaltyPoints(Integer loyaltyPoints) { this.loyaltyPoints = loyaltyPoints; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawMarketOrder.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import java.util.Date; import java.util.Objects; import java.util.Set; import java.util.TreeSet; import net.nikr.eve.jeveasset.i18n.TabsOrders; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.CharacterOrdersHistoryResponse; import net.troja.eve.esi.model.CharacterOrdersResponse; import net.troja.eve.esi.model.CorporationOrdersHistoryResponse; import net.troja.eve.esi.model.CorporationOrdersResponse; public class RawMarketOrder { public enum MarketOrderRange { _1("1", TabsOrders.get().rangeJump()), _10("10"), _2("2"), _20("20"), _3("3"), _30("30"), _4("4"), _40("40"), _5("5"), REGION("region", TabsOrders.get().rangeRegion()), SOLARSYSTEM("solarsystem", TabsOrders.get().rangeSolarSystem()), STATION("station", TabsOrders.get().rangeStation()); private static final MarketOrderRange[] SORTED = { REGION, SOLARSYSTEM, STATION, _1, _2, _3, _4, _5, _10, _20, _30, _40 }; private final String value; private final String text; MarketOrderRange(String value) { this(value, TabsOrders.get().rangeJumps(value)); } MarketOrderRange(String value, String text) { this.value = value; this.text = text; } public static MarketOrderRange[] valuesSorted() { return SORTED; } public String getValue() { return value; } @Override public String toString() { return text; } } public enum MarketOrderState { CANCELLED("cancelled"), CHARACTER_DELETED("character_deleted"), CLOSED("closed"), EXPIRED("expired"), OPEN("open"), PENDING("pending"), UNKNOWN("Unknown"); private final String value; MarketOrderState(String value) { this.value = value; } public String getValue() { return value; } } private Integer walletDivision = null; private Integer duration = null; private Double escrow = null; private Boolean isBuyOrder = null; private Boolean isCorp = null; private Date issued = null; private final Set changes = new TreeSet<>(); private Integer issuedBy = null; private Long locationId = null; private Integer minVolume = null; private Long orderId = null; private Double price = null; private String range = null; private MarketOrderRange rangeEnum = null; private Integer regionId = null; private String state = null; private MarketOrderState stateEnum = null; private Integer typeId = null; private Integer volumeRemain = null; private Integer volumeTotal = null; private Date changed; private boolean updateChanged = false; /** * New */ private RawMarketOrder() { } public static RawMarketOrder create() { return new RawMarketOrder(); } /** * Raw * * @param marketOrder */ protected RawMarketOrder(RawMarketOrder marketOrder) { walletDivision = marketOrder.walletDivision; duration = marketOrder.duration; escrow = marketOrder.escrow; isBuyOrder = marketOrder.isBuyOrder; isCorp = marketOrder.isCorp; issued = marketOrder.issued; changes.addAll(marketOrder.changes); issuedBy = marketOrder.issuedBy; locationId = marketOrder.locationId; minVolume = marketOrder.minVolume; orderId = marketOrder.orderId; price = marketOrder.price; range = marketOrder.range; rangeEnum = marketOrder.rangeEnum; regionId = marketOrder.regionId; state = marketOrder.state; stateEnum = marketOrder.stateEnum; typeId = marketOrder.typeId; volumeRemain = marketOrder.volumeRemain; volumeTotal = marketOrder.volumeTotal; } /** * ESI Character * * @param marketOrder */ public RawMarketOrder(CharacterOrdersResponse marketOrder) { walletDivision = 1; duration = SafeConverter.toInteger(marketOrder.getDuration()); escrow = RawConverter.toDouble(marketOrder.getEscrow(), 0); isBuyOrder = RawConverter.toBoolean(marketOrder.getIsBuyOrder()); isCorp = marketOrder.getIsCorporation(); issued = RawConverter.toDate(marketOrder.getIssued()); issuedBy = null; locationId = marketOrder.getLocationId(); minVolume = RawConverter.toInteger(marketOrder.getMinVolume(), 0); orderId = marketOrder.getOrderId(); price = marketOrder.getPrice(); range = marketOrder.getRangeString(); rangeEnum = RawConverter.toMarketOrderRange(marketOrder.getRange()); regionId = SafeConverter.toInteger(marketOrder.getRegionId()); state = MarketOrderState.OPEN.getValue(); stateEnum = MarketOrderState.OPEN; typeId = SafeConverter.toInteger(marketOrder.getTypeId()); volumeRemain = SafeConverter.toInteger(marketOrder.getVolumeRemain()); volumeTotal = SafeConverter.toInteger(marketOrder.getVolumeTotal()); changes.add(new Change(this)); } /** * ESI Character History * * @param marketOrder */ public RawMarketOrder(CharacterOrdersHistoryResponse marketOrder) { walletDivision = 1; duration = SafeConverter.toInteger(marketOrder.getDuration()); escrow = RawConverter.toDouble(marketOrder.getEscrow(), 0); isBuyOrder = RawConverter.toBoolean(marketOrder.getIsBuyOrder()); isCorp = marketOrder.getIsCorporation(); issued = RawConverter.toDate(marketOrder.getIssued()); issuedBy = null; locationId = marketOrder.getLocationId(); minVolume = RawConverter.toInteger(marketOrder.getMinVolume(), 0); orderId = marketOrder.getOrderId(); price = marketOrder.getPrice(); range = marketOrder.getRangeString(); rangeEnum = RawConverter.toMarketOrderRange(marketOrder.getRange()); regionId = SafeConverter.toInteger(marketOrder.getRegionId()); state = marketOrder.getStateString(); stateEnum = RawConverter.toMarketOrderState(marketOrder.getState()); typeId = SafeConverter.toInteger(marketOrder.getTypeId()); volumeRemain = SafeConverter.toInteger(marketOrder.getVolumeRemain()); volumeTotal = SafeConverter.toInteger(marketOrder.getVolumeTotal()); changes.add(new Change(this)); } /** * ESI Corporation * * @param marketOrder */ public RawMarketOrder(CorporationOrdersResponse marketOrder) { walletDivision = SafeConverter.toInteger(marketOrder.getWalletDivision()); duration = SafeConverter.toInteger(marketOrder.getDuration()); escrow = RawConverter.toDouble(marketOrder.getEscrow(), 0); isBuyOrder = RawConverter.toBoolean(marketOrder.getIsBuyOrder()); isCorp = true; issued = RawConverter.toDate(marketOrder.getIssued()); issuedBy = SafeConverter.toInteger(marketOrder.getIssuedBy()); locationId = marketOrder.getLocationId(); minVolume = RawConverter.toInteger(marketOrder.getMinVolume(), 0); orderId = marketOrder.getOrderId(); price = marketOrder.getPrice(); range = marketOrder.getRangeString(); rangeEnum = RawConverter.toMarketOrderRange(marketOrder.getRange()); regionId = SafeConverter.toInteger(marketOrder.getRegionId()); state = MarketOrderState.OPEN.getValue(); stateEnum = MarketOrderState.OPEN; typeId = SafeConverter.toInteger(marketOrder.getTypeId()); volumeRemain = SafeConverter.toInteger(marketOrder.getVolumeRemain()); volumeTotal = SafeConverter.toInteger(marketOrder.getVolumeTotal()); changes.add(new Change(this)); } /** * ESI Corporation History * * @param marketOrder */ public RawMarketOrder(CorporationOrdersHistoryResponse marketOrder) { walletDivision = SafeConverter.toInteger(marketOrder.getWalletDivision()); duration = SafeConverter.toInteger(marketOrder.getDuration()); escrow = RawConverter.toDouble(marketOrder.getEscrow(), 0); isBuyOrder = RawConverter.toBoolean(marketOrder.getIsBuyOrder()); isCorp = true; issued = RawConverter.toDate(marketOrder.getIssued()); issuedBy = SafeConverter.toInteger(marketOrder.getIssuedBy()); locationId = marketOrder.getLocationId(); minVolume = RawConverter.toInteger(marketOrder.getMinVolume(), 0); orderId = marketOrder.getOrderId(); price = marketOrder.getPrice(); range = marketOrder.getRangeString(); rangeEnum = RawConverter.toMarketOrderRange(marketOrder.getRange()); regionId = SafeConverter.toInteger(marketOrder.getRegionId()); state = marketOrder.getStateString(); stateEnum = RawConverter.toMarketOrderState(marketOrder.getState()); typeId = SafeConverter.toInteger(marketOrder.getTypeId()); volumeRemain = SafeConverter.toInteger(marketOrder.getVolumeRemain()); volumeTotal = SafeConverter.toInteger(marketOrder.getVolumeTotal()); changes.add(new Change(this)); } public Integer getWalletDivision() { return walletDivision; } public void setWalletDivision(Integer walletDivision) { this.walletDivision = walletDivision; } public Integer getDuration() { return duration; } public void setDuration(Integer duration) { this.duration = duration; } public Double getEscrow() { return escrow; } public void setEscrow(Double escrow) { this.escrow = escrow; } public Boolean isBuyOrder() { return isBuyOrder; } public void setBuyOrder(Boolean isBuyOrder) { this.isBuyOrder = isBuyOrder; } public Boolean isCorp() { return isCorp; } public void setCorp(Boolean isCorp) { this.isCorp = isCorp; } public Date getIssued() { return issued; } public void setIssued(Date issued) { this.issued = issued; } public int getEdits() { if (changes.isEmpty() || changes.size() == 1) { //0 or 1 = 0; return 0; } else { return changes.size() - 1; // > 1 } } public Date getChanged() { return changed; } public void setChanged(Date changed) { this.changed = changed; updateChanged = false; } public boolean isUpdateChanged() { return updateChanged; } public Set getChanges() { return changes; } public void addChangesLegacy(Date date) { if (date != null) { changes.add(new Change(date, null, null)); } } public void addChanges(Set change) { if (change != null) { Change current = new Change(this); updateChanged = !change.contains(current); changes.add(current); //Add current changes.addAll(change); //Add old } } public boolean addChanges(RawPublicMarketOrder response) { if (response != null) { //Set new data setPrice(response.getPrice()); setVolumeRemain(response.getVolumeRemain()); setIssued(response.getIssued()); //Add change return changes.add(new Change(response)); } return false; } public Integer getIssuedBy() { return issuedBy; } public void setIssuedBy(Integer issuedBy) { this.issuedBy = issuedBy; } public long getLocationID() { return locationId; } public void setLocationID(Long locationId) { this.locationId = locationId; } public Integer getMinVolume() { return minVolume; } public void setMinVolume(Integer minVolume) { this.minVolume = minVolume; } public Long getOrderID() { return orderId; } public void setOrderID(Long orderId) { this.orderId = orderId; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } public final MarketOrderRange getRange() { return rangeEnum; } public void setRange(MarketOrderRange range) { this.rangeEnum = range; } public String getRangeString() { return range; } public void setRangeString(String rangeString) { this.range = rangeString; } public Integer getRegionID() { return regionId; } public void setRegionID(Integer regionId) { this.regionId = regionId; } public final MarketOrderState getState() { return stateEnum; } public void setState(MarketOrderState state) { this.stateEnum = state; } public String getStateString() { return state; } public void setStateString(String stateString) { this.state = stateString; } public Integer getTypeID() { return typeId; } public void setTypeID(Integer typeId) { this.typeId = typeId; } public final Integer getVolumeRemain() { return volumeRemain; } public void setVolumeRemain(Integer volumeRemain) { this.volumeRemain = volumeRemain; } public final Integer getVolumeTotal() { return volumeTotal; } public void setVolumeTotal(Integer volumeTotal) { this.volumeTotal = volumeTotal; } public static class Change implements Comparable { private final Date date; private final Double price; private final Integer volumeRemaining; public Change(RawPublicMarketOrder response) { this(response.getIssued(), response.getPrice(), response.getVolumeRemain()); } public Change(RawMarketOrder response) { this(response.getIssued(), response.getPrice(), response.getVolumeRemain()); } public Change(Date date, Double price, Integer volumeRemaining) { this.date = date; this.price = price; this.volumeRemaining = volumeRemaining; } public Date getDate() { return date; } public Double getPrice() { return price; } public Integer getVolumeRemaining() { return volumeRemaining; } @Override public int hashCode() { int hash = 7; hash = 53 * hash + Objects.hashCode(this.date); hash = 53 * hash + Objects.hashCode(this.price); hash = 53 * hash + Objects.hashCode(this.volumeRemaining); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Change other = (Change) obj; if (!Objects.equals(this.date, other.date)) { return false; } if (!Objects.equals(this.price, other.price)) { return false; } if (!Objects.equals(this.volumeRemaining, other.volumeRemaining)) { return false; } return true; } @Override public int compareTo(Change change) { return date.compareTo(change.date); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawMining.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import java.util.Date; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.CharacterMiningResponse; import net.troja.eve.esi.model.CorporationMiningObserverResponse; import net.troja.eve.esi.model.CorporationMiningObserversResponse; public class RawMining { private Date date; private Long count; private Long locationID; private Integer typeID; private long characterID; private Long corporationID = null; private String corporationName; private boolean forCorporation; private RawMining() { } public static RawMining create() { return new RawMining(); } public RawMining(RawMining mining) { this.date = mining.date; this.count = mining.count; this.locationID = mining.locationID; this.typeID = mining.typeID; this.characterID = mining.characterID; this.corporationID = mining.corporationID; this.corporationName = mining.corporationName; this.forCorporation = mining.forCorporation; } /** * ESI Character * * @param mining * @param owner */ public RawMining(CharacterMiningResponse mining, OwnerType owner) { this.date = RawConverter.toDate(mining.getDate()); this.count = mining.getQuantity(); this.locationID = mining.getSolarSystemId(); this.typeID = SafeConverter.toInteger(mining.getTypeId()); this.characterID = owner.getOwnerID(); this.corporationID = null; this.corporationName = owner.getCorporationName(); this.forCorporation = false; } /** * ESI Corporation * * @param observers * @param mining * @param owner */ public RawMining(CorporationMiningObserversResponse observers, CorporationMiningObserverResponse mining, OwnerType owner) { this.date = RawConverter.toDate(mining.getLastUpdated()); this.count = mining.getQuantity(); this.locationID = observers.getObserverId(); this.typeID = SafeConverter.toInteger(mining.getTypeId()); this.characterID = mining.getCharacterId(); this.corporationName = null; this.corporationID = mining.getRecordedCorporationId(); this.forCorporation = true; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public long getCount() { return count; } public void setCount(Long count) { this.count = count; } public long getLocationID() { return locationID; } public void setLocationID(Long locationID) { this.locationID = locationID; } public Integer getTypeID() { return typeID; } public void setTypeID(Integer typeID) { this.typeID = typeID; } public long getCharacterID() { return characterID; } public void setCharacterID(long characterID) { this.characterID = characterID; } public Long getCorporationID() { return corporationID; } public void setCorporationID(Long corporationID) { this.corporationID = corporationID; } public boolean isForCorporation() { return forCorporation; } public void setForCorporation(boolean forCorporation) { this.forCorporation = forCorporation; } public String getCorporationName() { return corporationName; } public void setCorporationName(String corporationName) { this.corporationName = corporationName; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawNpcStanding.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import java.util.Comparator; import net.nikr.eve.jeveasset.i18n.TabsNpcStanding; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.StandingsResponse; public class RawNpcStanding { public static final TypeComparator FROM_TYPE_COMPARATOR = new TypeComparator(); public enum FromType { FACTION("faction"){ @Override String getI18N() { return TabsNpcStanding.get().typeFaction(); } }, NPC_CORP("npc_corp"){ @Override String getI18N() { return TabsNpcStanding.get().typeCorporation(); } }, AGENT("agent"){ @Override String getI18N() { return TabsNpcStanding.get().typeAgent(); } }; private final String value; FromType(String value) { this.value = value; } public String getValue() { return value; } abstract String getI18N(); @Override public String toString() { return getI18N(); } } private String fromType; private FromType fromTypeEnum; private Integer fromId; private Float standing; public static RawNpcStanding create() { return new RawNpcStanding(); } private RawNpcStanding() { } /** * ESI Character/Corporation * @param response */ public RawNpcStanding(StandingsResponse response) { fromType = response.getFromTypeString(); fromTypeEnum = RawConverter.toNpcStandingFromType(response.getFromType()); fromId = SafeConverter.toInteger(response.getFromId()); standing = SafeConverter.toFloat(response.getStanding()); } public RawNpcStanding(RawNpcStanding response) { fromType = response.getFromTypeString(); fromTypeEnum = response.getFromType(); fromId = response.getFromID(); standing = response.getStanding(); } public String getFromTypeString() { return fromType; } public void setFromTypeString(String fromType) { this.fromType = fromType; } public FromType getFromType() { return fromTypeEnum; } public void setFromType(FromType fromTypeEnum) { this.fromTypeEnum = fromTypeEnum; } public Integer getFromID() { return fromId; } public void setFromID(Integer fromId) { this.fromId = fromId; } public Float getStanding() { return standing; } public void setStanding(Float standing) { this.standing = standing; } public static class TypeComparator implements Comparator { @Override public int compare(FromType o1, FromType o2) { return Integer.compare(o1.ordinal(), o2.ordinal()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawPublicMarketOrder.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import java.util.Date; import java.util.Objects; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.MarketOrderRange; import net.nikr.eve.jeveasset.gui.tabs.orders.MarketLog; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.MarketRegionOrdersResponse; import net.troja.eve.esi.model.MarketStructureResponse; public class RawPublicMarketOrder { private final Integer duration; private final Integer minVolume; private final Boolean isBuyOrder; private final Double price; private final Integer systemId; private final Integer typeId; private final String range; private final MarketOrderRange rangeEnum; private final Integer volumeTotal; private final Date issued; private final Long orderId; private final Integer volumeRemain; private final Long locationId; public RawPublicMarketOrder(MarketRegionOrdersResponse marketOrder) { this.duration = SafeConverter.toInteger(marketOrder.getDuration()); this.minVolume = SafeConverter.toInteger(marketOrder.getMinVolume()); this.isBuyOrder = marketOrder.getIsBuyOrder(); this.price = marketOrder.getPrice(); this.systemId = SafeConverter.toInteger(marketOrder.getSystemId()); this.typeId = SafeConverter.toInteger(marketOrder.getTypeId()); this.range = marketOrder.getRangeString(); this.rangeEnum = RawConverter.toMarketOrderRange(marketOrder.getRange()); this.volumeTotal = SafeConverter.toInteger(marketOrder.getVolumeTotal()); this.issued = RawConverter.toDate(marketOrder.getIssued()); this.orderId = marketOrder.getOrderId(); this.volumeRemain = SafeConverter.toInteger(marketOrder.getVolumeRemain()); this.locationId = marketOrder.getLocationId(); } public RawPublicMarketOrder(MarketStructureResponse marketOrder, final Long systemId) { this.duration = SafeConverter.toInteger(marketOrder.getDuration()); this.minVolume = SafeConverter.toInteger(marketOrder.getMinVolume()); this.isBuyOrder = marketOrder.getIsBuyOrder(); this.price = marketOrder.getPrice(); this.systemId = SafeConverter.toInteger(systemId); this.typeId = SafeConverter.toInteger(marketOrder.getTypeId()); this.range = marketOrder.getRangeString(); this.rangeEnum = RawConverter.toMarketOrderRange(marketOrder.getRange()); this.volumeTotal = SafeConverter.toInteger(marketOrder.getVolumeTotal()); this.issued = RawConverter.toDate(marketOrder.getIssued()); this.orderId = marketOrder.getOrderId(); this.volumeRemain = SafeConverter.toInteger(marketOrder.getVolumeRemain()); this.locationId = marketOrder.getLocationId(); } public RawPublicMarketOrder(MarketLog marketLog) { this.duration = marketLog.getDuration(); this.minVolume = marketLog.getMinVolume(); this.isBuyOrder = marketLog.getBid(); this.price = marketLog.getPrice(); this.systemId = SafeConverter.toInteger(marketLog.getSolarSystemID()); this.typeId = marketLog.getTypeID(); this.range = null; this.rangeEnum = RawConverter.toMarketOrderRange(marketLog.getRange(), null, null); this.volumeTotal = marketLog.getVolEntered(); this.issued = marketLog.getIssueDate(); this.orderId = marketLog.getOrderID(); this.volumeRemain = RawConverter.toInteger(marketLog.getVolRemaining()); this.locationId = marketLog.getStationID(); } public Integer getDuration() { return duration; } public Integer getMinVolume() { return minVolume; } public Boolean isBuyOrder() { return isBuyOrder; } public Double getPrice() { return price; } public Integer getSystemID() { return systemId; } public Integer getTypeID() { return typeId; } public MarketOrderRange getRange() { return rangeEnum; } public String getRangeString() { return range; } public Integer getVolumeTotal() { return volumeTotal; } public Date getIssued() { return issued; } public Long getOrderID() { return orderId; } public Integer getVolumeRemain() { return volumeRemain; } public Long getLocationID() { return locationId; } @Override public int hashCode() { int hash = 7; hash = 37 * hash + Objects.hashCode(this.orderId); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final RawPublicMarketOrder other = (RawPublicMarketOrder) obj; if (!Objects.equals(this.orderId, other.orderId)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawSkill.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.Skill; public class RawSkill { private Integer activeSkillLevel; private Integer skillId; private Long skillpointsInSkill; private Integer trainedSkillLevel; /** * New */ private RawSkill() { } public static RawSkill create() { return new RawSkill(); } public RawSkill(RawSkill skill) { this.activeSkillLevel = skill.getActiveSkillLevel(); this.skillId = skill.getTypeID(); this.skillpointsInSkill = skill.getSkillpoints(); this.trainedSkillLevel = skill.getTrainedSkillLevel(); } public RawSkill(Skill skill) { this.activeSkillLevel = SafeConverter.toInteger(skill.getActiveSkillLevel()); this.skillId = SafeConverter.toInteger(skill.getSkillId()); this.skillpointsInSkill = skill.getSkillpointsInSkill(); this.trainedSkillLevel = SafeConverter.toInteger(skill.getTrainedSkillLevel()); } public Integer getActiveSkillLevel() { return activeSkillLevel; } public Integer getTypeID() { return skillId; } public Long getSkillpoints() { return skillpointsInSkill; } public Integer getTrainedSkillLevel() { return trainedSkillLevel; } public void setActiveSkillLevel(Integer activeSkillLevel) { this.activeSkillLevel = activeSkillLevel; } public void setTypeID(Integer typeID) { this.skillId = typeID; } public void setSkillpoints(Long skillpoints) { this.skillpointsInSkill = skillpoints; } public void setTrainedSkillLevel(Integer trainedSkillLevel) { this.trainedSkillLevel = trainedSkillLevel; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/api/raw/RawTransaction.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.api.raw; import java.util.Date; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.CharacterWalletTransactionsResponse; import net.troja.eve.esi.model.CorporationWalletTransactionsResponse; public class RawTransaction { private Integer clientId = null; private Date date = null; private Boolean isBuy = null; private Boolean isPersonal = null; private Long journalRefId = null; private Long locationId = null; private Integer quantity = null; private Long transactionId = null; private Integer typeId = null; private Double unitPrice = null; private Integer accountKey = null; /** * New */ private RawTransaction() { } public static RawTransaction create() { return new RawTransaction(); } /** * Raw * * @param transaction */ protected RawTransaction(RawTransaction transaction) { clientId = transaction.clientId; date = transaction.date; isBuy = transaction.isBuy; isPersonal = transaction.isPersonal; journalRefId = transaction.journalRefId; locationId = transaction.locationId; quantity = transaction.quantity; transactionId = transaction.transactionId; typeId = transaction.typeId; unitPrice = transaction.unitPrice; accountKey = transaction.accountKey; } /** * ESI Character * * @param transaction * @param accountKey */ public RawTransaction(CharacterWalletTransactionsResponse transaction, Integer accountKey) { clientId = SafeConverter.toInteger(transaction.getClientId()); date = RawConverter.toDate(transaction.getDate()); isBuy = transaction.getIsBuy(); isPersonal = transaction.getIsPersonal(); journalRefId = transaction.getJournalRefId(); locationId = transaction.getLocationId(); quantity = SafeConverter.toInteger(transaction.getQuantity()); transactionId = transaction.getTransactionId(); typeId = SafeConverter.toInteger(transaction.getTypeId()); unitPrice = transaction.getUnitPrice(); this.accountKey = accountKey; } /** * ESI Corporation * * @param transaction * @param accountKey */ public RawTransaction(CorporationWalletTransactionsResponse transaction, Integer accountKey) { clientId = SafeConverter.toInteger(transaction.getClientId()); date = RawConverter.toDate(transaction.getDate()); isBuy = transaction.getIsBuy(); isPersonal = false; journalRefId = transaction.getJournalRefId(); locationId = transaction.getLocationId(); quantity = SafeConverter.toInteger(transaction.getQuantity()); transactionId = transaction.getTransactionId(); typeId = SafeConverter.toInteger(transaction.getTypeId()); unitPrice = transaction.getUnitPrice(); this.accountKey = accountKey; } public final long getClientID() { return clientId; } public void setClientID(Integer clientId) { this.clientId = clientId; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public Boolean isBuy() { return isBuy; } public void setBuy(Boolean isBuy) { this.isBuy = isBuy; } public Boolean isPersonal() { return isPersonal; } public void setPersonal(Boolean isPersonal) { this.isPersonal = isPersonal; } public Long getJournalRefID() { return journalRefId; } public void setJournalRefID(Long journalRefId) { this.journalRefId = journalRefId; } public long getLocationID() { return locationId; } public void setLocationID(Long locationId) { this.locationId = locationId; } public Integer getQuantity() { return quantity; } public void setQuantity(Integer quantity) { this.quantity = quantity; } public Long getTransactionID() { return transactionId; } public void setTransactionID(Long transactionId) { this.transactionId = transactionId; } public Integer getTypeID() { return typeId; } public void setTypeID(Integer typeId) { this.typeId = typeId; } public Double getPrice() { return unitPrice; } public void setUnitPrice(Double unitPrice) { this.unitPrice = unitPrice; } public Integer getAccountKey() { return accountKey; } public void setAccountKey(Integer accountKey) { this.accountKey = accountKey; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/profile/Profile.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.profile; import java.io.File; import java.util.ArrayList; import java.util.List; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.io.local.profile.ProfileDatabase; import net.nikr.eve.jeveasset.io.local.ProfileReader; import net.nikr.eve.jeveasset.io.local.profile.ProfileDatabase.Table; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Profile implements Comparable { private static final Logger LOG = LoggerFactory.getLogger(Profile.class); private static final String XML = "xml"; private static final String XML_BAC = "bac"; private static final String XML_BACKUP = "xmlbackup"; private static final String SQLITE = "db"; private static final String SQLITE_BACKUP = "zip"; public static enum ProfileType { XML, SQLITE } private String name; private boolean defaultProfile; private boolean activeProfile; private ProfileType type; private final StockpileIDs stockpileIDs; private final List esiOwners = new ArrayList<>(); public Profile() { this("Default", true, true, ProfileType.SQLITE); } public Profile(final String name, final boolean defaultProfile, final boolean activeProfile, final ProfileType type) { this.name = name; this.defaultProfile = defaultProfile; this.activeProfile = activeProfile; this.stockpileIDs = new StockpileIDs(name); this.type = type; } public boolean load() { clear(); //Clear the profile before loading stockpileIDs.load(); //Load stockpileIDs if (type == ProfileType.XML) { return ProfileReader.load(this); //Assets (Must be loaded before the price data) } else if (type == ProfileType.SQLITE) { return ProfileDatabase.load(this); } else { return false; } } public void saveTable(Table table) { if (type == ProfileType.XML) { save(); //Full save } else { ProfileDatabase.save(this, table); } } public void save() { boolean save = ProfileDatabase.save(this); if (save && type == ProfileType.XML) { type = ProfileType.SQLITE; //Migrated to SQLite File file = new File(getXmlFilename()); File backup = new File(getBackupXmlFilename()); file.renameTo(backup); } } public boolean isDefaultProfile() { return defaultProfile; } public boolean isActiveProfile() { return activeProfile; } public void setActiveProfile(final boolean activeProfile) { this.activeProfile = activeProfile; } public StockpileIDs getStockpileIDs() { return stockpileIDs; } public List getEsiOwners() { return esiOwners; } public void clear() { esiOwners.clear(); } public String getXmlFilename() { return getFilenameExtension(XML); } public String getBackupXmlFilename() { return getFilenameExtension(XML_BACKUP); } public String getSQLiteFilename() { return getFilenameExtension(SQLITE); } public String getBackupSQLiteFilename() { String filename = getName() + "_" + Program.PROGRAM_VERSION + "_dbbackup"; filename = filename.replace(" ", "_"); //Remove spaces filename = filename + "." + SQLITE_BACKUP; //Add extension if (defaultProfile) { filename = "#" + filename; //Mark active profile } filename = FileUtil.getPathProfile(filename); return filename; } private File getBackupFile() { switch (type) { case XML: return new File(getFilenameExtension(XML_BAC)); case SQLITE: return null; default: return null; } } private File getFile() { switch (type) { case XML: return new File(getFilenameExtension(XML)); case SQLITE: return new File(getFilenameExtension(SQLITE)); default: return null; } } private String getFilenameExtension(String extension) { String filename = getName(); filename = filename.replace(" ", "_"); //Remove spaces filename = filename + "." + extension; //Add extension if (defaultProfile) { filename = "#" + filename; //Mark active profile } filename = FileUtil.getPathProfile(filename); return filename; } public String getName() { return name; } public void setDefaultProfile(final boolean defaultProfile) { if (this.defaultProfile != defaultProfile) { File from = getFile(); File backFrom = getBackupFile(); this.defaultProfile = defaultProfile; File to = getFile(); File backTo = getBackupFile(); if (from != null && to != null && !from.equals(to) && !from.renameTo(to)) { LOG.warn("Failed to rename profile: {}", getName()); } if (backFrom != null && backTo != null && !backFrom.equals(backTo) && !backFrom.renameTo(backTo)) { LOG.warn("Failed to rename profile backup: {}", getName()); } } } public void setName(final String name) { File from = getFile(); File backFrom = getBackupFile(); this.name = name; File to = getFile(); File backTo = getBackupFile(); if (from != null && to != null && !from.equals(to) && !from.renameTo(to)) { LOG.warn("Failed to rename profile: {}", getName()); } if (backFrom != null && backTo != null && !backFrom.equals(backTo) && !backFrom.renameTo(backTo)) { LOG.warn("Failed to rename profile backup: {}", getName()); } stockpileIDs.renameTable(name); } public void delete() { File file = getFile(); if (file != null && !file.delete()) { LOG.warn("Failed to delete profile: {}", getName()); } File backupFile = getBackupFile(); if (backupFile != null && !backupFile.delete()) { LOG.warn("Failed to delete profile backup: {}", getName()); } stockpileIDs.removeTable(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Profile other = (Profile) obj; if (this.name == null && other.name == null) { return true; //Both null } else if (this.name == null || other.name == null) { return false; //One null } else { return this.name.equalsIgnoreCase(other.name); } } @Override public int hashCode() { int hash = 3; hash = 97 * hash + (this.name != null ? this.name.toLowerCase().hashCode() : 0); return hash; } @Override public String toString() { String temp = name; if (defaultProfile) { temp = temp + " (default)"; } //if (activeProfile) temp = temp+" (active)"; return temp; } @Override public int compareTo(final Profile o) { return this.getName().compareToIgnoreCase(o.getName()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/profile/ProfileData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.profile; import ca.odell.glazedlists.EventList; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.SplashUpdater; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyAccountBalance; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyBlueprint; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyExtraction; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.api.my.MySkill; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.api.raw.RawAsset; import net.nikr.eve.jeveasset.data.api.raw.RawBlueprint; import net.nikr.eve.jeveasset.data.api.raw.RawClone; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob.IndustryJobStatus; import net.nikr.eve.jeveasset.data.api.raw.RawJournalRefType; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.Change; import net.nikr.eve.jeveasset.data.sde.IndustryMaterial; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.ReprocessedMaterial; import net.nikr.eve.jeveasset.data.sde.RouteFinder; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.AddedData; import net.nikr.eve.jeveasset.data.settings.MarketPriceData; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.data.settings.types.EditableLocationType; import net.nikr.eve.jeveasset.data.settings.types.EditablePriceType; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.data.settings.types.LastTransactionType; import net.nikr.eve.jeveasset.data.settings.types.LocationsType; import net.nikr.eve.jeveasset.gui.dialogs.settings.SoundsSettingsPanel.SoundOption; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.gui.sounds.SoundPlayer; import net.nikr.eve.jeveasset.gui.tabs.loyalty.TotalLoyaltyPoints; import net.nikr.eve.jeveasset.gui.tabs.orders.OutbidProcesser.OutbidProcesserOutput; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.DataConverter; public class ProfileData { private final ProfileManager profileManager; private final EventList contractItemEventList = EventListManager.create(); private final EventList industryJobsEventList = EventListManager.create(); private final EventList marketOrdersEventList = EventListManager.create(); private final EventList journalEventList = EventListManager.create(); private final EventList transactionsEventList = EventListManager.create(); private final EventList assetsEventList = EventListManager.create(); private final EventList accountBalanceEventList = EventListManager.create(); private final EventList contractEventList = EventListManager.create(); private final EventList skillsEventList = EventListManager.create(); private final EventList loyaltyPointsEventList = EventListManager.create(); private final EventList npcStandingsEventList = EventListManager.create(); private final EventList miningEventList = EventListManager.create(); private final EventList extractionsEventList = EventListManager.create(); private final List contractItemList = new ArrayList<>(); private final List industryJobsList = new ArrayList<>(); private final List marketOrdersList = new ArrayList<>(); private final List journalList = new ArrayList<>(); private final List transactionsList = new ArrayList<>(); private final List assetsList = new ArrayList<>(); private final Map> clonesList = new HashMap<>(); private final List accountBalanceList = new ArrayList<>(); private final List contractList = new ArrayList<>(); private final Map skillPointsTotal = new HashMap<>(); private Map> uniqueAssetsDuplicates = null; //TypeID : int private Map transactionSellPriceData; //TypeID : int private Map transactionBuyPriceData; //TypeID : int private Map transactionBuyTax; //TypeID : int private Map transactionSellTax; //TransactionID : long private Map marketOrdersBrokersFee; //OrderID : long private final List ownerNames = new ArrayList<>(); private final Map owners = new HashMap<>(); private Set staticTypeIDs = null; public ProfileData(ProfileManager profileManager) { this.profileManager = profileManager; RouteFinder.load(); SplashUpdater.setSubProgress(100); } public Set getPriceTypeIDs() { return createPriceTypeIDs(); //always needs to be fresh :) } public EventList getAccountBalanceEventList() { return accountBalanceEventList; } public EventList getAssetsEventList() { return assetsEventList; } public EventList getIndustryJobsEventList() { return industryJobsEventList; } public EventList getMarketOrdersEventList() { return marketOrdersEventList; } public EventList getJournalEventList() { return journalEventList; } public EventList getTransactionsEventList() { return transactionsEventList; } public EventList getContractEventList() { return contractEventList; } public EventList getContractItemEventList() { return contractItemEventList; } public EventList getSkillsEventList() { return skillsEventList; } public EventList getLoyaltyPointsEventList() { return loyaltyPointsEventList; } public EventList getNpcStandingsEventList() { return npcStandingsEventList; } public EventList getMiningEventList() { return miningEventList; } public EventList getExtractionsEventList() { return extractionsEventList; } public List getContractItemList() { return contractItemList; } public List getIndustryJobsList() { return industryJobsList; } public List getMarketOrdersList() { return marketOrdersList; } public List getJournalList() { return journalList; } public List getTransactionsList() { return transactionsList; } public List getAssetsList() { return assetsList; } public List getAccountBalanceList() { return accountBalanceList; } public Map> getClonesList() { return clonesList; } public List getContractList() { return contractList; } public Map getSkillPointsTotal() { return skillPointsTotal; } public List getOwnerNames(boolean all) { synchronized (ownerNames) { //synchronized as ownerNames are modified by updateEventLists List sortedOwners = new ArrayList<>(ownerNames); if (all) { sortedOwners.add(0, General.get().all()); } return sortedOwners; } } public Map getOwners() { synchronized (owners) { //synchronized as owners are modified by updateEventLists return new HashMap<>(owners); } } private Set createPriceTypeIDs() { Set priceTypeIDs = new HashSet<>(); priceTypeIDs.add(40519); //Skill Extractor priceTypeIDs.add(40520); //Large Skill Injector for (OwnerType owner : profileManager.getOwnerTypes()) { //Add Assets to uniqueIds deepAssets(owner.getAssets(), priceTypeIDs); //Add Market Orders to uniqueIds for (MyMarketOrder marketOrder : owner.getMarketOrders()) { Item item = marketOrder.getItem(); if (item.isMarketGroup()) { priceTypeIDs.add(item.getTypeID()); } } //Add Transaction to uniqueIds for (MyTransaction transaction : owner.getTransactions()) { Item item = transaction.getItem(); if (item.isMarketGroup()) { priceTypeIDs.add(item.getTypeID()); } } //Add Industry Job to uniqueIds for (MyIndustryJob industryJob : owner.getIndustryJobs()) { //Blueprint Item blueprint = industryJob.getItem(); if (blueprint.isMarketGroup()) { priceTypeIDs.add(blueprint.getTypeID()); } //Manufacturing Output if (industryJob.isManufacturing() && industryJob.isNotDeliveredToAssets() && industryJob.getProductTypeID() != null) { //Output Item output = ApiIdConverter.getItem(industryJob.getProductTypeID()); if (output.isMarketGroup()) { priceTypeIDs.add(output.getTypeID()); } } } //Add Contract to uniqueIds for (Map.Entry> entry : owner.getContracts().entrySet()) { for (MyContractItem contractItem : entry.getValue()) { Item item = contractItem.getItem(); if (item.isMarketGroup()) { priceTypeIDs.add(item.getTypeID()); } } } //Add Mining to uniqueIds for (MyMining mining : owner.getMining()) { Item item = mining.getItem(); if (item.isMarketGroup()) { priceTypeIDs.add(item.getTypeID()); } } //Add Clone to uniqueIds for (RawClone clone : owner.getClones()) { for (Integer typeID : clone.getImplants()) { Item item = ApiIdConverter.getItem(typeID); if (item.isMarketGroup()) { priceTypeIDs.add(item.getTypeID()); } } } } //Add StockpileItems to uniqueIds for (Stockpile stockpile : Settings.get().getStockpiles()) { for (StockpileItem stockpileItem : stockpile.getItems()) { if (stockpileItem.getItem().isMarketGroup()) { priceTypeIDs.add(stockpileItem.getTypeID()); } } } //Add reprocessed and manufacturing items to the price queue if (staticTypeIDs == null) { staticTypeIDs = new HashSet<>(); for (Item item : StaticData.get().getItems().values()) { for (ReprocessedMaterial reprocessedMaterial : item.getReprocessedMaterial()) { int typeID = reprocessedMaterial.getTypeID(); Item reprocessedItem = ApiIdConverter.getItem(typeID); if (reprocessedItem.isMarketGroup()) { staticTypeIDs.add(typeID); } } for (IndustryMaterial industryMaterial : item.getManufacturingMaterials()) { int typeID = industryMaterial.getTypeID(); Item reprocessedItem = ApiIdConverter.getItem(typeID); if (reprocessedItem.isMarketGroup()) { staticTypeIDs.add(typeID); } } } } priceTypeIDs.addAll(staticTypeIDs); return priceTypeIDs; } private void deepAssets(List assets, Set priceTypeIDs) { for (MyAsset asset : assets) { //Unique Ids if (asset.getItem().isMarketGroup()) { priceTypeIDs.add(asset.getItem().getTypeID()); } deepAssets(asset.getAssets(), priceTypeIDs); } } public void updateMarketOrders(OutbidProcesserOutput output) { Date addedDate = new Date(); Map marketOrdersAdded = AddedData.getMarketOrders().getAll(); synchronized (owners) { //synchronized as owners are modified by updateEventLists for (OwnerType ownerType : owners.values()) { for (MyMarketOrder order : ownerType.getMarketOrders()) { // getMarketOrders() is thread safe order.setOutbid(output.getOutbids().get(order.getOrderID())); boolean updated = order.addChanges(output.getUpdates().get(order.getOrderID())); if (updated) { //If Market Order have been updated order.setChanged(AddedData.getMarketOrders().getPut(marketOrdersAdded, order.getOrderID(), addedDate)); } } } } updateOutbidOwned(marketOrdersList); AddedData.getMarketOrders().commitQueue(); Program.ensureEDT(new Runnable() { @Override public void run() { try { marketOrdersEventList.getReadWriteLock().writeLock().lock(); List cache = new ArrayList<>(marketOrdersEventList); marketOrdersEventList.clear(); marketOrdersEventList.addAll(cache); } finally { marketOrdersEventList.getReadWriteLock().writeLock().unlock(); } } }); } public void updateLocations(Set locationIDs) { if (locationIDs == null || locationIDs.isEmpty()) { return; } //Update Contracts locations try { contractEventList.getReadWriteLock().readLock().lock(); for (MyContract contract : contractEventList) { //Update Locations contract.setStartLocation(ApiIdConverter.getLocation(contract.getStartLocationID())); contract.setEndLocation(ApiIdConverter.getLocation(contract.getEndLocationID())); } } finally { contractEventList.getReadWriteLock().readLock().unlock(); } updateEditableLocation(transactionsEventList, locationIDs); updateEditableLocation(marketOrdersEventList, locationIDs); updateEditableLocation(assetsEventList, locationIDs); updateEditableLocation(industryJobsEventList, locationIDs); updateLocations(contractItemEventList, locationIDs); updateLocations(contractEventList, locationIDs); updateEditableLocation(miningEventList, locationIDs); updateEditableLocation(extractionsEventList, locationIDs); updateLocationList(StaticData.get().getAgents().values(), locationIDs); } public void updateNames(Set itemIDs) { if (itemIDs == null || itemIDs.isEmpty()) { return; } updateNames(assetsEventList, itemIDs); } public void updatePrice(Set typeIDs) { if (typeIDs == null || typeIDs.isEmpty()) { return; } //Update Items dynamic values for (Item item : StaticData.get().getItems().values()) { double before = item.getPriceReprocessed(); double price = ApiIdConverter.getPriceReprocessed(item); item.setPriceReprocessed(price); double beforeMax = item.getPriceReprocessedMax(); double priceMax = ApiIdConverter.getPriceReprocessedMax(item); item.setPriceReprocessedMax(priceMax); double beforeManufacturing = item.getPriceManufacturing(); double priceManufacturing = ApiIdConverter.getPriceManufacturing(item); item.setPriceManufacturing(priceManufacturing); if (before != price || beforeMax != priceMax || beforeManufacturing != priceManufacturing) { typeIDs.add(item.getTypeID()); } } updatePrices(marketOrdersEventList, typeIDs); updatePrices(contractItemEventList, typeIDs); updatePrices(miningEventList, typeIDs); updatePrices(assetsEventList, typeIDs); updateIndustryJobPrices(industryJobsEventList, typeIDs); } public void updateEventLists() { updateEventLists(new Date()); } public synchronized void updateEventLists(Date addedDate) { uniqueAssetsDuplicates = new HashMap<>(); Set uniqueOwnerNames = new HashSet<>(); Map uniqueOwners = new HashMap<>(); //Temp List assets = new ArrayList<>(); List accountBalance = new ArrayList<>(); Map assetsMap = new HashMap<>(); Map accountBalanceMap = new HashMap<>(); Map copyIndustryJobs = new HashMap<>(); Set marketOrders = new HashSet<>(); Set charMarketOrders = new HashSet<>(); Set journals = new HashSet<>(); Set transactions = new HashSet<>(); Set charTransactions = new HashSet<>(); Set industryJobs = new HashSet<>(); Set contractItems = new HashSet<>(); Set contracts = new HashSet<>(); Set skills = new HashSet<>(); Set loyaltyPointses = new HashSet<>(); Map loyaltyPointsTotals = new HashMap<>(); Set npcStandings = new HashSet<>(); Set minings = new HashSet<>(); Set extractions = new HashSet<>(); Map blueprintsMap = new HashMap<>(); Map blueprints = new HashMap<>(); Map skillPointsTotalCache = new HashMap<>(); Map> clones = new HashMap<>(); calcTransactionsPriceData(); for (OwnerType owner : profileManager.getOwnerTypes()) { if (!owner.isShowOwner()) { continue; } uniqueOwnerNames.add(owner.getOwnerName()); uniqueOwners.put(owner.getOwnerID(), owner); } //Add Market Orders/Journal/Transactions/Industry Jobs/Contracts/Contract Items/Blueprints/Assets/Account Balance for (OwnerType owner : profileManager.getOwnerTypes()) { if (!owner.isShowOwner()) { continue; } //Clones clones.put(owner, owner.getClones()); //Market Orders //If owner is corporation overwrite the character orders (to use the "right" owner) if (owner.isCorporation()) { marketOrders.addAll(owner.getMarketOrders()); } else { charMarketOrders.addAll(owner.getMarketOrders()); } //Journal journals.addAll(owner.getJournal()); //Transactions if (owner.isCorporation()) { transactions.addAll(owner.getTransactions()); } else { charTransactions.addAll(owner.getTransactions()); } //Industry Jobs > MyBlueprint industryJobs.addAll(owner.getIndustryJobs()); for (MyIndustryJob myIndustryJob : owner.getIndustryJobs()) { blueprints.put(myIndustryJob.getBlueprintID(), new MyBlueprint(myIndustryJob)); if (myIndustryJob.isCopying()) { blueprints.put(myIndustryJob.getJobID().longValue(), new MyBlueprint(myIndustryJob)); copyIndustryJobs.put(myIndustryJob.getBlueprintID(), myIndustryJob); } } //Contracts & Contract Items for (Map.Entry> entry : owner.getContracts().entrySet()) { MyContract contract = entry.getKey(); if (entry.getValue().isEmpty() && contract.isCourierContract() && ( //XXX - Workaround for alien contracts uniqueOwners.containsKey(contract.getAcceptorID()) || uniqueOwners.containsKey(contract.getAssigneeID()) || uniqueOwners.containsKey(contract.getIssuerID()) || (contract.isForCorp() && uniqueOwners.containsKey(contract.getIssuerCorpID())))) { //Add contracts and ContractItems contracts.add(contract); contractItems.add(new MyContractItem(contract)); } else if (entry.getValue().isEmpty()) { contracts.add(contract); contractItems.add(new MyContractItem(contract)); } else if (!entry.getValue().isEmpty()) { //Add contracts and ContractItems contracts.add(contract); contractItems.addAll(entry.getValue()); } for (MyContractItem contractItem : entry.getValue()) { MyBlueprint blueprint = contractItem.getBlueprint(); Long itemID = contractItem.getItemID(); if (blueprint != null) { if (itemID != null) { blueprints.put(itemID, blueprint); } blueprints.put(contractItem.getRecordID(), blueprint); } } } //Blueprints (Newest) if (!owner.getBlueprints().isEmpty()) { OwnerType ownerType = blueprintsMap.get(owner.getOwnerID()); if (ownerType == null || (owner.getBlueprintsNextUpdate() != null && ownerType.getBalanceNextUpdate() != null && owner.getBlueprintsNextUpdate().after(ownerType.getBalanceNextUpdate()))) { blueprintsMap.put(owner.getOwnerID(), owner); } } //Assets (Newest) if (!owner.getAssets().isEmpty()) { OwnerType ownerType = assetsMap.get(owner.getOwnerID()); if (ownerType == null || (owner.getAssetNextUpdate() != null && ownerType.getAssetNextUpdate() != null && owner.getAssetNextUpdate().after(ownerType.getAssetNextUpdate()))) { assetsMap.put(owner.getOwnerID(), owner); } } //Account Balance (Newest) if (!owner.getAccountBalances().isEmpty()) { OwnerType ownerType = accountBalanceMap.get(owner.getOwnerID()); if (ownerType == null || (owner.getBalanceNextUpdate() != null && ownerType.getBalanceNextUpdate() != null && owner.getBalanceNextUpdate().after(ownerType.getBalanceNextUpdate()))) { accountBalanceMap.put(owner.getOwnerID(), owner); } } //Skills skills.addAll(owner.getSkills()); if (owner.getTotalSkillPoints() != null) { if (owner.getUnallocatedSkillPoints() != null) { skillPointsTotalCache.put(owner.getOwnerName(), owner.getTotalSkillPoints() + owner.getUnallocatedSkillPoints()); } else { skillPointsTotalCache.put(owner.getOwnerName(), owner.getTotalSkillPoints()); } } //Loyalty Points loyaltyPointses.addAll(owner.getLoyaltyPoints()); //NPC Standing npcStandings.addAll(owner.getNpcStanding()); //Mining minings.addAll(owner.getMining()); //Extractions extractions.addAll(owner.getExtractions()); } //Fill accountBalance for (OwnerType owner : accountBalanceMap.values()) { accountBalance.addAll(owner.getAccountBalances()); } //RawBlueprint > MyBlueprint for (OwnerType owner : blueprintsMap.values()) { for (Map.Entry entry : owner.getBlueprints().entrySet()) { blueprints.put(entry.getKey(), new MyBlueprint(entry.getValue())); //Best source - overwrite other sources //Copy Industry Jobs MyIndustryJob industryJob = copyIndustryJobs.get(entry.getKey()); if (industryJob != null) { blueprints.put(industryJob.getJobID().longValue(), new MyBlueprint(industryJob.getLicensedRuns(), entry.getValue().getMaterialEfficiency(), entry.getValue().getTimeEfficiency())); } } } //Prioritize corp market orders over char for (MyMarketOrder marketOrder : charMarketOrders) { if (!marketOrder.isCorp()) { //Remove non-corporation orders marketOrders.remove(marketOrder); } marketOrders.add(marketOrder); } //Prioritize corp transactions over char for (MyTransaction transaction : charTransactions) { if (!transaction.isCorporation()) { //Remove non-corporation orders transactions.remove(transaction); } transactions.add(transaction); } //Update MarketOrders dynamic values Map marketOrdersAdded = AddedData.getMarketOrders().getAll(); for (MyMarketOrder order : marketOrders) { //Last Transaction if (order.isBuyOrder()) { //Buy setLastTransaction(order, order.getTypeID(), order.isBuyOrder(), order.getPrice(), null); } else { //Sell setLastTransaction(order, order.getTypeID() , order.isBuyOrder(), order.getPrice(), null); } order.setIssuedByName(ApiIdConverter.getOwnerName(order.getIssuedBy())); order.setBrokersFee(marketOrdersBrokersFee.get(order.getOrderID())); order.setOutbid(Settings.get().getMarketOrdersOutbid().get(order.getOrderID())); //Update Owned Integer issuedBy = order.getIssuedBy(); if (order.isCorporation() && issuedBy != null) { order.setOwned(uniqueOwners.containsKey((long) issuedBy)); } //Price Data order.setPriceData(ApiIdConverter.getPriceData(order.getTypeID(), false)); //Changed date if (order.isUpdateChanged()) { //Update! order.setChanged(AddedData.getMarketOrders().getPut(marketOrdersAdded, order.getOrderID(), addedDate)); } else { Date changed; if (!marketOrdersAdded.containsKey(order.getOrderID())) { //New (use issued as a best guess) changed = order.getIssued(); } else { //Updating changed = addedDate; } order.setChanged(AddedData.getMarketOrders().getAdd(marketOrdersAdded, order.getOrderID(), changed)); } } updateOutbidOwned(marketOrders); AddedData.getMarketOrders().commitQueue(); //Update IndustryJobs dynamic values for (MyIndustryJob industryJob : industryJobs) { //Update Owners industryJob.setInstaller(ApiIdConverter.getOwnerName(industryJob.getInstallerID())); industryJob.setCompletedCharacter(ApiIdConverter.getOwnerName(industryJob.getCompletedCharacterID())); //Update Owned if (industryJob.getOwner().isCorporation()) { industryJob.setOwned(uniqueOwners.containsKey(industryJob.getInstallerID())); } //Update BPO/BPC status industryJob.setBlueprint(blueprints.get(industryJob.getBlueprintID())); //Price updatePrice(industryJob); //Queue Sound if (industryJob.getStatus() == IndustryJobStatus.ACTIVE) { SoundPlayer.playAt(industryJob.getEndDate(), SoundOption.INDUSTRY_JOB_COMPLETED); } } //Update Contracts dynamic values for (MyContract contract : contracts) { OwnerType issuer = uniqueOwners.get(contract.getIssuerID()); OwnerType acceptor = uniqueOwners.get(contract.getAcceptorID()); if (issuer != null) { contract.setIssuerAfterAssets(issuer.getAssetLastUpdate()); } if (acceptor != null) { contract.setAcceptorAfterAssets(acceptor.getAssetLastUpdate()); } //Update Owned if (contract.isForCorp()) { contract.setOwned(uniqueOwners.containsKey(contract.getIssuerID())); } //Update Locations contract.setStartLocation(ApiIdConverter.getLocation(contract.getStartLocationID())); contract.setEndLocation(ApiIdConverter.getLocation(contract.getEndLocationID())); //Update Owners contract.setAcceptor(ApiIdConverter.getOwnerName(contract.getAcceptorID())); contract.setAssignee(ApiIdConverter.getOwnerName(contract.getAssigneeID())); contract.setIssuerCorp(ApiIdConverter.getOwnerName(contract.getIssuerCorpID())); contract.setIssuer(ApiIdConverter.getOwnerName(contract.getIssuerID())); } //Update Transaction dynamic values Map transactionsAdded = AddedData.getTransactions().getAll(); for (MyTransaction transaction : transactions) { //Client Name transaction.setClientName(ApiIdConverter.getOwnerName(transaction.getClientID())); //Tax if (transaction.isBuy()) { //Buy transaction.setTax(null); //Seller pays the tax } else { //Sell transaction.setTax(transactionSellTax.get(transaction.getTransactionID())); } //Transaction Profit if (transaction.isBuy()) { //Buy setLastTransaction(transaction, transaction.getTypeID(), transaction.isBuy(), transaction.getPrice(), transactionBuyTax.get(transaction.getTypeID())); } else { //Sell double tax = 0; if (transaction.getTax() != null) { tax = transaction.getTax() / transaction.getItemCount(); } setLastTransaction(transaction, transaction.getTypeID(), transaction.isBuy(), transaction.getPrice(), tax); } //Date added transaction.setAdded(AddedData.getTransactions().getAdd(transactionsAdded, transaction.getTransactionID(), addedDate)); //Tags Tags tags = Settings.get().getTags(transaction.getTagID()); transaction.setTags(tags); } AddedData.getTransactions().commitQueue(); //Update Journal dynamic values Map journalsAdded = AddedData.getJournals().getAll(); for (MyJournal journal : journals) { //Names journal.setFirstPartyName(ApiIdConverter.getOwnerName(journal.getFirstPartyID())); journal.setSecondPartyName(ApiIdConverter.getOwnerName(journal.getSecondPartyID())); //Date added journal.setAdded(AddedData.getJournals().getAdd(journalsAdded, journal.getRefID(), addedDate)); //Context journal.setContext(ApiIdConverter.getContext(journal)); //Tags Tags tags = Settings.get().getTags(journal.getTagID()); journal.setTags(tags); } AddedData.getJournals().commitQueue(); //Update Loyalty Points dynamic values for (MyLoyaltyPoints loyaltyPoints : loyaltyPointses) { //Names String corporationName = ApiIdConverter.getOwnerName(loyaltyPoints.getCorporationID()); loyaltyPoints.setCorporationName(corporationName); //Totals if (corporationName != null && !corporationName.isEmpty()) { TotalLoyaltyPoints total = loyaltyPointsTotals.get(corporationName); if (total == null) { total = new TotalLoyaltyPoints(loyaltyPoints); loyaltyPointsTotals.put(corporationName, total); } total.add(loyaltyPoints); } } //Add Totals loyaltyPointses.addAll(loyaltyPointsTotals.values()); //Update Npc Standing dynamic values for (MyNpcStanding npcStanding : npcStandings) { //Names npcStanding.updateSkills(); npcStanding.setCorporationName(ApiIdConverter.getOwnerName(npcStanding.getCorporationID())); npcStanding.setFactionName(ApiIdConverter.getOwnerName(npcStanding.getFactionID())); } //Update Mining dynamic values for (MyMining mining : minings) { mining.setCharacterName(ApiIdConverter.getOwnerName(mining.getCharacterID())); if (mining.getCorporationID() != null && mining.getCorporationName() == null) { mining.setCorporationName(ApiIdConverter.getOwnerName(mining.getCorporationID())); } } //Update Items dynamic values for (Item item : StaticData.get().getItems().values()) { item.setPriceReprocessed(ApiIdConverter.getPriceReprocessed(item)); item.setPriceReprocessedMax(ApiIdConverter.getPriceReprocessedMax(item)); item.setPriceManufacturing(ApiIdConverter.getPriceManufacturing(item)); } Map assetAdded = AddedData.getAssets().getAll(); Program.ensureEDT(new Runnable() { @Override public void run() { //Add Market Orders to Assets addAssets(DataConverter.assetMarketOrder(marketOrders, Settings.get().isIncludeSellOrders(), Settings.get().isIncludeBuyOrders()), assets, blueprints, assetAdded, addedDate); //Add Industry Jobs to Assets addAssets(DataConverter.assetIndustryJob(industryJobs, Settings.get().isIncludeManufacturing(), Settings.get().isIncludeCopying()), assets, blueprints, assetAdded, addedDate); //Add Contract Items to Assets addAssets(DataConverter.assetContracts(contractItems, uniqueOwners, Settings.get().isIncludeSellContracts(), Settings.get().isIncludeBuyContracts()), assets, blueprints, assetAdded, addedDate); //Add Jump Clones and Plugged in Implant to Assets addAssets(DataConverter.assetCloneImplants(clones, Settings.get().isIncludeJumpClones(), Settings.get().isIncludePluggedInImplants()), assets, blueprints, assetAdded, addedDate); //Add Assets to Assets for (OwnerType owner : assetsMap.values()) { addAssets(owner.getAssets(), assets, blueprints, assetAdded, addedDate); } } }); AddedData.getAssets().commitQueue(); //Update Locations List editableLocationTypes = new ArrayList<>(); editableLocationTypes.addAll(assets); editableLocationTypes.addAll(marketOrders); editableLocationTypes.addAll(transactions); editableLocationTypes.addAll(industryJobs); editableLocationTypes.addAll(minings); editableLocationTypes.addAll(extractions); editableLocationTypes.addAll(StaticData.get().getAgents().values()); for (EditableLocationType editableLocationType : editableLocationTypes) { editableLocationType.setLocation(ApiIdConverter.getLocation(editableLocationType.getLocationID())); } //Update Prices List editablePriceTypes = new ArrayList<>(); editablePriceTypes.addAll(marketOrders); editablePriceTypes.addAll(contractItems); editablePriceTypes.addAll(minings); for (EditablePriceType editablePriceType : editablePriceTypes) { updatePrice(editablePriceType); } //Owners - Before EventList update - in case owners are referanced in any ListEventListeners synchronized (ownerNames) { //synchronized as ownerNames are modified (here) by updateEventLists ownerNames.clear(); ownerNames.addAll(uniqueOwnerNames); } Collections.sort(ownerNames, StringComparators.CASE_INSENSITIVE); synchronized (owners) { //synchronized as owners are modified (here) by updateEventLists owners.clear(); owners.putAll(uniqueOwners); } //Update Lists assetsList.clear(); assetsList.addAll(assets); marketOrdersList.clear(); marketOrdersList.addAll(marketOrders); journalList.clear(); journalList.addAll(journals); transactionsList.clear(); transactionsList.addAll(transactions); industryJobsList.clear(); industryJobsList.addAll(industryJobs); contractItemList.clear(); contractItemList.addAll(contractItems); contractList.clear(); contractList.addAll(contracts); accountBalanceList.clear(); accountBalanceList.addAll(accountBalance); skillPointsTotal.clear(); skillPointsTotal.putAll(skillPointsTotalCache); clonesList.clear(); clonesList.putAll(clones); //Update EventLists Program.ensureEDT(new Runnable() { @Override public void run() { try { assetsEventList.getReadWriteLock().writeLock().lock(); assetsEventList.clear(); assetsEventList.addAll(assets); } finally { assetsEventList.getReadWriteLock().writeLock().unlock(); } } }); Program.ensureEDT(new Runnable() { @Override public void run() { try { marketOrdersEventList.getReadWriteLock().writeLock().lock(); marketOrdersEventList.clear(); marketOrdersEventList.addAll(marketOrders); } finally { marketOrdersEventList.getReadWriteLock().writeLock().unlock(); } } }); Program.ensureEDT(new Runnable() { @Override public void run() { try { journalEventList.getReadWriteLock().writeLock().lock(); journalEventList.clear(); journalEventList.addAll(journals); } finally { journalEventList.getReadWriteLock().writeLock().unlock(); } } }); Program.ensureEDT(new Runnable() { @Override public void run() { try { transactionsEventList.getReadWriteLock().writeLock().lock(); transactionsEventList.clear(); transactionsEventList.addAll(transactions); } finally { transactionsEventList.getReadWriteLock().writeLock().unlock(); } } }); Program.ensureEDT(new Runnable() { @Override public void run() { try { industryJobsEventList.getReadWriteLock().writeLock().lock(); industryJobsEventList.clear(); industryJobsEventList.addAll(industryJobs); } finally { industryJobsEventList.getReadWriteLock().writeLock().unlock(); } } }); Program.ensureEDT(new Runnable() { @Override public void run() { try { contractItemEventList.getReadWriteLock().writeLock().lock(); contractItemEventList.clear(); contractItemEventList.addAll(contractItems); } finally { contractItemEventList.getReadWriteLock().writeLock().unlock(); } } }); Program.ensureEDT(new Runnable() { @Override public void run() { try { contractEventList.getReadWriteLock().writeLock().lock(); contractEventList.clear(); contractEventList.addAll(contracts); } finally { contractEventList.getReadWriteLock().writeLock().unlock(); } } }); Program.ensureEDT(new Runnable() { @Override public void run() { try { accountBalanceEventList.getReadWriteLock().writeLock().lock(); accountBalanceEventList.clear(); accountBalanceEventList.addAll(accountBalance); } finally { accountBalanceEventList.getReadWriteLock().writeLock().unlock(); } } }); Program.ensureEDT(new Runnable() { @Override public void run() { try { skillsEventList.getReadWriteLock().writeLock().lock(); skillsEventList.clear(); skillsEventList.addAll(skills); } finally { skillsEventList.getReadWriteLock().writeLock().unlock(); } } }); Program.ensureEDT(new Runnable() { @Override public void run() { try { loyaltyPointsEventList.getReadWriteLock().writeLock().lock(); loyaltyPointsEventList.clear(); loyaltyPointsEventList.addAll(loyaltyPointses); } finally { loyaltyPointsEventList.getReadWriteLock().writeLock().unlock(); } } }); Program.ensureEDT(new Runnable() { @Override public void run() { try { npcStandingsEventList.getReadWriteLock().writeLock().lock(); npcStandingsEventList.clear(); npcStandingsEventList.addAll(npcStandings); } finally { npcStandingsEventList.getReadWriteLock().writeLock().unlock(); } } }); Program.ensureEDT(new Runnable() { @Override public void run() { try { miningEventList.getReadWriteLock().writeLock().lock(); miningEventList.clear(); miningEventList.addAll(minings); } finally { miningEventList.getReadWriteLock().writeLock().unlock(); } } }); Program.ensureEDT(new Runnable() { @Override public void run() { try { extractionsEventList.getReadWriteLock().writeLock().lock(); extractionsEventList.clear(); extractionsEventList.addAll(extractions); } finally { extractionsEventList.getReadWriteLock().writeLock().unlock(); } } }); } public void updateNames(EventList eventList, Set itemIDs) { if (itemIDs == null || itemIDs.isEmpty()) { return; } List found = new ArrayList<>(); try { eventList.getReadWriteLock().readLock().lock(); for (MyAsset asset : eventList) { if (itemIDs.contains(asset.getItemID())) { found.add(asset); //Save for update updateName(asset); //Update Name updateContainerChildren(found, asset.getAssets()); //Update Container } for (MyAsset parent : asset.getParents()) { //Offices if (parent.getTypeID() != 27 && !parent.getItemFlag().equals(RawAsset.IMPLANT_FLAG) && !parent.getItemFlag().equals(RawAsset.JUMP_CLONE_FLAG) && !parent.getItemFlag().equals(RawAsset.ACTIVE_CLONE_FLAG) ) { continue; } if (itemIDs.contains(parent.getItemID())) { updateName(parent); //Update Name updateContainerChildren(found, parent.getAssets()); //Update Container } } } } finally { eventList.getReadWriteLock().readLock().unlock(); } updateList(eventList, found); } public static void updatePrices(EventList eventList, Set typeIDs) { if (typeIDs == null || typeIDs.isEmpty()) { return; } List found = new ArrayList<>(); try { eventList.getReadWriteLock().readLock().lock(); for (T t : eventList) { if (typeIDs.contains(getTypeID(t.isBPC(), t.getItem().getTypeID()))) { found.add(t); //Save for update updatePrice(t); } } } finally { eventList.getReadWriteLock().readLock().unlock(); } updateList(eventList, found); } private void updateOutbidOwned(Collection marketOrders) { Map>> lowestBuy = new HashMap<>(); Map>> lowestSell = new HashMap<>(); for (MyMarketOrder order : marketOrders) { //Find lowest if (order.isActive() && order.haveOutbid() && !order.isOutbid()) { //Lowest Map>> lowest; if (order.isBuyOrder()) { lowest = lowestBuy; } else { lowest = lowestSell; } Map> region = lowest.get(order.getRegionID()); if (region == null) { region = new HashMap<>(); lowest.put(order.getRegionID(), region); } Set orderIDs = region.get(order.getTypeID()); if (orderIDs == null) { orderIDs = new HashSet<>(); region.put(order.getTypeID(), orderIDs); } orderIDs.add(order.getOrderID()); } } for (MyMarketOrder order : marketOrders) { //Set owned if (!order.isActive()) { order.setOutbidOwned(false); continue; } Map>> lowest; if (order.isBuyOrder()) { lowest = lowestBuy; } else { lowest = lowestSell; } Map> region = lowest.get(order.getRegionID()); if (region == null) { order.setOutbidOwned(false); continue; } Set orderIDs = region.get(order.getTypeID()); if (orderIDs == null) { order.setOutbidOwned(false); continue; } order.setOutbidOwned(!orderIDs.contains(order.getOrderID())); //not one of the lowest orders } } private void updateIndustryJobPrices(EventList eventList, Set typeIDs) { if (typeIDs == null || typeIDs.isEmpty()) { return; } List found = new ArrayList<>(); try { eventList.getReadWriteLock().readLock().lock(); for (MyIndustryJob industryJob : eventList) { Integer productTypeID = industryJob.getProductTypeID(); if (typeIDs.contains(getTypeID(industryJob.isBPC(), industryJob.getItem().getTypeID())) || (productTypeID != null && typeIDs.contains(getTypeID(industryJob.isCopying(), productTypeID)))) { found.add(industryJob); //Save for update updatePrice(industryJob); //Update data } } } finally { eventList.getReadWriteLock().readLock().unlock(); } updateList(eventList, found); } private static int getTypeID(boolean bpc, int typeID) { if (bpc) { return -typeID; } else { return typeID; } } public static void updateEditableLocation(EventList eventList, Set locationIDs) { if (locationIDs == null || locationIDs.isEmpty()) { return; } List found = new ArrayList<>(); try { eventList.getReadWriteLock().readLock().lock(); for (T t : eventList) { if (locationIDs.contains(t.getLocationID())) { found.add(t); //Save for update t.setLocation(ApiIdConverter.getLocation(t.getLocationID())); //Update data } } } finally { eventList.getReadWriteLock().readLock().unlock(); } updateList(eventList, found); } public static void updateLocationList(Collection collection, Set locationIDs) { if (locationIDs == null || locationIDs.isEmpty()) { return; } for (T t : collection) { if (locationIDs.contains(t.getLocationID())) { t.setLocation(ApiIdConverter.getLocation(t.getLocationID())); //Update data } } } private void updateLocations(EventList eventList, Set locationIDs) { if (locationIDs == null || locationIDs.isEmpty()) { return; } List found = new ArrayList<>(); try { eventList.getReadWriteLock().readLock().lock(); for (T t : eventList) { for (MyLocation location : t.getLocations()) { if (locationIDs.contains(location.getLocationID())) { found.add(t); //Save for update break; //Item already added } } } } finally { eventList.getReadWriteLock().readLock().unlock(); } updateList(eventList, found); } private static void updateList(EventList eventList, List found) { if (found.isEmpty()) { return; } if (found.size() > 2) { Program.ensureEDT(new Runnable() { @Override public void run() { try { eventList.getReadWriteLock().writeLock().lock(); List cache = new ArrayList<>(eventList); eventList.clear(); eventList.addAll(cache); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } }); } else { Program.ensureEDT(new Runnable() { @Override public void run() { try { eventList.getReadWriteLock().writeLock().lock(); eventList.removeAll(found); eventList.addAll(found); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } }); } } private void calcTransactionsPriceData() { //Create Transaction Price Data transactionBuyTax = new HashMap<>(); transactionSellPriceData = new HashMap<>(); transactionBuyPriceData = new HashMap<>(); transactionSellTax = new HashMap<>(); marketOrdersBrokersFee = new HashMap<>(); Date lastTaxDate = null; Date maxAge = new Date(System.currentTimeMillis() - ((long)Settings.get().getMaximumPurchaseAge() * 24L * 60L * 60L * 1000L)); for (OwnerType owner : profileManager.getOwnerTypes()) { //Journal Map> taxes = new HashMap<>(); Map> fees = new HashMap<>(); for (MyJournal journal : owner.getJournal()) { if (journal.getRefType() == RawJournalRefType.TRANSACTION_TAX) { List list = taxes.get(journal.getDate()); if (list == null) { list = new ArrayList<>(); taxes.put(journal.getDate(), list); } list.add(journal.getAmount()); } if (journal.getRefType() == RawJournalRefType.BROKERS_FEE) { List list = fees.get(journal.getDate()); if (list == null) { list = new ArrayList<>(); fees.put(journal.getDate(), list); } list.add(journal.getAmount()); } } //Transactions Map> transactions = new HashMap<>(); for (MyTransaction transaction : owner.getTransactions()) { if (transaction.isSell()) { List list = transactions.get(transaction.getDate()); if (list == null) { list = new ArrayList<>(); transactions.put(transaction.getDate(), list); } list.add(transaction); } if (transaction.getDate().before(maxAge) && Settings.get().getMaximumPurchaseAge() != 0) { continue; //Date out of range and not unlimited } if (transaction.isSell()) { //Sell createTransactionsPriceData(transactionSellPriceData, transaction); } else { //Buy createTransactionsPriceData(transactionBuyPriceData, transaction); } } //Tax for (Map.Entry> entry : transactions.entrySet()) { List list = taxes.get(entry.getKey()); if (list == null) { continue; } List> matchs = new ArrayList<>(); for (MyTransaction transaction : entry.getValue()) { double expected = transaction.getQuantity() * transaction.getPrice() / 100.0 * 5.0; //5% for (Double tax : list) { double diff = Math.abs(tax + expected); //Tax is negative and expected is possitive: Add them together for diff matchs.add(new Match<>(transaction, tax, diff)); } } Collections.sort(matchs); Set found = new HashSet<>(); for (Match match : matchs) { MyTransaction transaction = match.get(); if (!found.contains(transaction) && found.size() <= list.size()) { found.add(transaction); double tax = match.getAmount(); transactionSellTax.put(transaction.getTransactionID(), tax); if ((lastTaxDate == null || lastTaxDate.before(transaction.getDate()))) { transactionBuyTax.put(transaction.getTypeID(), tax / transaction.getItemCount()); lastTaxDate = transaction.getDate(); } } } } //Market Orders Map> marketOrders = new HashMap<>(); for (MyMarketOrder marketOrder : owner.getMarketOrders()) { for (Change change : marketOrder.getChanges()) { Date date = change.getDate(); List list = marketOrders.get(date); if (list == null) { list = new ArrayList<>(); marketOrders.put(date, list); } list.add(marketOrder); } } //Fees for (Map.Entry> entry : marketOrders.entrySet()) { List list = fees.get(entry.getKey()); if (list == null) { continue; } List> matchs = new ArrayList<>(); for (MyMarketOrder marketOrder : entry.getValue()) { double expected = Math.max(marketOrder.getVolumeTotal() * marketOrder.getPrice() / 100.0 * 5.0, 100); //5% or 100isk for (Double fee : list) { double diff = Math.abs(fee + expected); //Fee is negative and expected is possitive: Add them together for diff matchs.add(new Match<>(marketOrder, fee, diff)); } } Collections.sort(matchs); Set found = new HashSet<>(); for (Match match : matchs) { MyMarketOrder marketOrder = match.get(); if (!found.contains(marketOrder) && found.size() <= list.size()) { found.add(marketOrder); Double fee = marketOrdersBrokersFee.get(marketOrder.getOrderID()); if (fee == null) { fee = 0.0; } fee = fee + match.getAmount(); marketOrdersBrokersFee.put(marketOrder.getOrderID(), fee); } } } } } private void createTransactionsPriceData(Map transactionPriceData, MyTransaction transaction) { int typeID = transaction.getTypeID(); MarketPriceData data = transactionPriceData.get(typeID); if (data == null) { data = new MarketPriceData(); transactionPriceData.put(typeID, data); } data.update(transaction.getPrice(), transaction.getItemCount(), transaction.getDate()); } public Double getTransactionAveragePrice(int typeID) { MarketPriceData buy = transactionBuyPriceData.get(typeID); MarketPriceData sell = transactionSellPriceData.get(typeID); if (buy != null && sell != null) { return MarketPriceData.getAverage(buy, sell); } else if (buy != null) { return buy.getAverage(); } else if (sell != null) { return sell.getAverage(); } else { return null; } } private void setLastTransaction(LastTransactionType item, int typeID, boolean buy, double price, Double tax) { if (tax == null) { tax = 0.0; } MarketPriceData marketPriceData; if (buy) { //Buy marketPriceData = transactionSellPriceData.get(typeID); } else { //Sell marketPriceData = transactionBuyPriceData.get(typeID); } if (marketPriceData != null) { double transactionPrice; switch (Settings.get().getTransactionProfitPrice()) { case AVERAGE: transactionPrice = marketPriceData.getAverage(); break; case LASTEST: transactionPrice = marketPriceData.getLatest(); break; case MAXIMUM: transactionPrice = marketPriceData.getMaximum(); break; case MINIMUM: transactionPrice = marketPriceData.getMinimum(); break; default: transactionPrice = marketPriceData.getLatest(); } if (buy) { //Buy transactionPrice = transactionPrice + tax; item.setTransactionPrice(transactionPrice); item.setTransactionProfit(transactionPrice - price); item.setTransactionProfitPercent(Percent.create(transactionPrice / price)); } else { //Sell price = price + tax; item.setTransactionPrice(transactionPrice); item.setTransactionProfit(price - (transactionPrice)); item.setTransactionProfitPercent(Percent.create(price / (transactionPrice))); } } else { item.setTransactionPrice(0); item.setTransactionProfit(0); item.setTransactionProfitPercent(Percent.create(0)); } } private void addAssets(final List assets, List addTo, Map blueprints, Map assetAdded, Date assetAddedDate) { for (MyAsset asset : assets) { //XXX Ignore 9e18 locations: https://github.com/ccpgames/esi-issues/issues/684 if (asset.getLocationID() > 9000000000000000000L) { continue; } //Handle Asset Structures if (asset.getItem().getCategory().equals(Item.CATEGORY_STRUCTURE)) { for (MyAsset childAsset: asset.getAssets()) { updateStructureAssets(childAsset, asset); } } //Blueprint asset.setBlueprint(blueprints.get(asset.getItemID())); //Tags Tags tags = Settings.get().getTags(asset.getTagID()); asset.setTags(tags); //Date added asset.setAdded(AddedData.getAssets().getAdd(assetAdded, asset.getItemID(), assetAddedDate)); //Price updatePrice(asset); //Market price asset.setMarketPriceData(transactionBuyPriceData.get(asset.getItem().getTypeID())); //User Item Names updateName(asset); if (asset.getItemFlag().equals(RawAsset.IMPLANT_FLAG) || asset.getItemFlag().equals(RawAsset.JUMP_CLONE_FLAG) || asset.getItemFlag().equals(RawAsset.ACTIVE_CLONE_FLAG) ) { for (MyAsset parent : asset.getParents()) { updateName(parent); } } //Container updateContainer(asset); //Price data asset.setPriceData(ApiIdConverter.getPriceData(asset.getItem().getTypeID(), asset.isBPC())); //Type Count int typeID; if (asset.isBPC()) { typeID = -asset.getItem().getTypeID(); } else { typeID = asset.getItem().getTypeID(); } List dup = uniqueAssetsDuplicates.get(typeID); if (dup == null) { dup = new ArrayList<>(); uniqueAssetsDuplicates.put(typeID, dup); } long newCount = asset.getCount(); if (!dup.isEmpty()) { newCount = newCount + dup.get(0).getTypeCount(); } dup.add(asset); for (MyAsset assetLoop : dup) { assetLoop.setTypeCount(newCount); } //Add asset if (asset.getTypeID() != 27) { //Ignore offices addTo.add(asset); } else { //Office asset.setLocation(ApiIdConverter.getLocation(asset.getLocationID())); } //Add sub-assets addAssets(asset.getAssets(), addTo, blueprints, assetAdded, assetAddedDate); } } private static void updatePrice(EditablePriceType editablePriceType) { editablePriceType.setDynamicPrice(ApiIdConverter.getPrice(editablePriceType.getItem().getTypeID(), editablePriceType.isBPC())); } private static void updatePrice(MyIndustryJob industryJob) { industryJob.setDynamicPrice(ApiIdConverter.getPrice(industryJob.getItem().getTypeID(), industryJob.isBPC())); industryJob.setOutputPrice(ApiIdConverter.getPrice(industryJob.getProductTypeID(), industryJob.isCopying())); } private static void updatePrice(MyAsset asset) { //User price if (asset.getItem().isBlueprint() && !asset.isBPO()) { //Blueprint Copy asset.setUserPrice(Settings.get().getUserPrices().get(-asset.getItem().getTypeID())); } else { //All other asset.setUserPrice(Settings.get().getUserPrices().get(asset.getItem().getTypeID())); } //Dynamic Price asset.setDynamicPrice(ApiIdConverter.getPrice(asset.getItem().getTypeID(), asset.isBPC())); } private void updateName(MyAsset asset) { asset.setName(Settings.get().getUserItemNames().get(asset.getItemID()), Settings.get().getEveNames().get(asset.getItemID())); } private void updateContainerChildren(List found, List assets) { for (MyAsset asset : assets) { found.add(asset); updateContainer(asset); updateContainerChildren(found, asset.getAssets()); } } private void updateContainer(MyAsset asset) { asset.updateContainer(); } private void updateStructureAssets(final MyAsset asset, final MyAsset structure) { final Long locationID; if (asset.isCorporation() && !asset.getParents().isEmpty() && asset.getParents().get(asset.getParents().size() - 1).equals(structure) && asset.getTypeID() != 27) { locationID = structure.getLocationID(); } else { asset.getParents().remove(structure); locationID = structure.getItemID(); } asset.setLocationID(locationID); asset.setLocation(ApiIdConverter.getLocation(locationID)); for (MyAsset subAsset : asset.getAssets()) { //Update child assets updateStructureAssets(subAsset, structure); } } private static class Match implements Comparable>{ private final T t; private final double amount; private final double diff; public Match(T t, double amount, double diff) { this.t = t; this.amount = amount; this.diff = diff; } public T get() { return t; } public double getAmount() { return amount; } public Double getDiff() { return diff; } @Override public int hashCode() { int hash = 3; hash = 41 * hash + Objects.hashCode(this.t); hash = 41 * hash + (int) (Double.doubleToLongBits(this.amount) ^ (Double.doubleToLongBits(this.amount) >>> 32)); hash = 41 * hash + (int) (Double.doubleToLongBits(this.diff) ^ (Double.doubleToLongBits(this.diff) >>> 32)); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Match other = (Match) obj; if (Double.doubleToLongBits(this.amount) != Double.doubleToLongBits(other.amount)) { return false; } if (Double.doubleToLongBits(this.diff) != Double.doubleToLongBits(other.diff)) { return false; } if (!Objects.equals(this.t, other.t)) { return false; } return true; } @Override public int compareTo(Match match) { return this.getDiff().compareTo(match.getDiff()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/profile/ProfileManager.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.profile; import java.awt.Component; import java.util.ArrayList; import java.util.List; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.SplashUpdater; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.io.local.ProfileFinder; import net.nikr.eve.jeveasset.io.local.profile.ProfileDatabase; import net.nikr.eve.jeveasset.io.local.profile.ProfileDatabase.Table; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ProfileManager { private static final Logger LOG = LoggerFactory.getLogger(ProfileManager.class); private boolean profileLoadError = false; private Profile activeProfile; private List profiles = new ArrayList<>(); public ProfileManager() { setActiveProfile(new Profile()); profiles.add(activeProfile); } public void searchProfile() { //Find profiles boolean found = ProfileFinder.load(this); if (!found) { //No profiles found, using default saveProfile(); //Saving new default profile } } public List getProfiles() { return profiles; } public boolean containsProfileName(String name) { for (Profile profile : profiles) { if (profile.getName().equalsIgnoreCase(name)) { //Profile names are case insensitive return true; } } return false; } public void setProfiles(final List profiles) { this.profiles = profiles; } public final void setActiveProfile(final Profile activeProfile) { this.activeProfile = activeProfile; ProfileDatabase.setUpdateConnectionUrl(activeProfile); } public StockpileIDs getStockpileIDs() { return activeProfile.getStockpileIDs(); } public Profile getActiveProfile() { return activeProfile; } public void saveProfile() { activeProfile.save(); } public void saveProfileTable(Table table) { activeProfile.saveTable(table); } public List getOwnerTypes() { List owners = new ArrayList<>(); owners.addAll(getEsiOwners()); return owners; } public List getEsiOwners() { return activeProfile.getEsiOwners(); } public void clear() { activeProfile.clear(); } public void loadActiveProfile() { //Load Profile LOG.info("Loading profile: {}", activeProfile.getName()); profileLoadError = !activeProfile.load(); SplashUpdater.setProgress(40); } public void showProfileLoadErrorWarning(Component parentComponent) { if (profileLoadError) { JOptionPane.showMessageDialog(parentComponent, GuiShared.get().errorLoadingProfileMsg(), GuiShared.get().errorLoadingProfileTitle(), JOptionPane.ERROR_MESSAGE); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/profile/StockpileIDs.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.profile; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile; import net.nikr.eve.jeveasset.io.local.profile.ProfileTable.Rows; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class StockpileIDs { private static final Logger LOG = LoggerFactory.getLogger(StockpileIDs.class); private final Set hidden = new HashSet<>(); private String tableName; private boolean newDatabase = false; public StockpileIDs(String tableName) { this(tableName, false); } protected StockpileIDs(String tableName, boolean createTable) { this.tableName = getSafeTableName(tableName); if (createTable && !tableExist()) { createTable(); } } private static String getConnectionUrl() { return "jdbc:sqlite:" + FileUtil.getPathStockpileIDsDatabase(); } protected void setNewDatabase(boolean newDatabase) { this.newDatabase = newDatabase; } public void load() { hidden.clear(); //Clear befor loading if (!tableExist()) { //New database: Empty newDatabase = true; createTable(); } else { //Get data from database newDatabase = false; get(); } } public Set getHidden() { return hidden; } public boolean isHidden(long stockpileID) { return hidden.contains(stockpileID); } public boolean isShown(long stockpileID) { return !isHidden(stockpileID); } public void setHidden(Set data) { if (data == null) { return; } //Hide Set hide = new HashSet<>(data); //To be hidden hide.removeAll(hidden); //Remove already hidden insert(hide); //Hide //Show Set show = new HashSet<>(hidden); //Currently hidden show.removeAll(data); //Remove still hidden delete(show); //Show hidden.clear(); hidden.addAll(data); } public void setShown(Set data) { setShown(data, Settings.get().getStockpiles()); } protected void setShown(Set data, List stockpiles) { if (data == null || data.isEmpty() || !newDatabase) { return; } Set hide = new HashSet<>(); //To be hidden for (Stockpile stockpile : stockpiles) { long id = stockpile.getStockpileID(); if (!data.contains(id)) { //Not shown hide.add(id); //Hide } } setHidden(hide); } public void show(long stockpileID) { boolean removed = hidden.remove(stockpileID); if (removed) { //Show only if not already shown delete(Collections.singleton(stockpileID)); } } public void hide(long stockpileID) { boolean added = hidden.add(stockpileID); if (added) { //Hide only if not already hidden insert(Collections.singleton(stockpileID)); } } private void insert(Set data) { if (data == null || data.isEmpty()) { return; } String sql = "INSERT INTO " + tableName + "(id) VALUES(?)"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, data.size()); connection.setAutoCommit(false); for (Long id : data) { statement.setLong(1, id); rows.addRow(); } connection.commit(); connection.setAutoCommit(true); } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } private void delete(Set data) { if (data == null || data.isEmpty()) { return; } String sql = "DELETE FROM " + tableName + " WHERE id = ?"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, data.size()); connection.setAutoCommit(false); for (Long id : data) { statement.setLong(1, id); rows.addRow(); } connection.commit(); connection.setAutoCommit(true); } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } private void get() { String sql = "SELECT * FROM " + tableName; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { hidden.add(rs.getLong("id")); } } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } private String getSafeTableName(String tableName) { //Start with underscore in case the name starts with a number //Replace space with underscore return "_" + tableName.replace(" ", "_"); } private void createTable() { String sql = "CREATE TABLE IF NOT EXISTS " + tableName + " (\n" + " id integer PRIMARY KEY\n" + ");"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); Statement statement = connection.createStatement()) { statement.execute(sql); } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } public boolean renameTable(String tableName) { tableName = getSafeTableName(tableName); if (this.tableName.equals(tableName)) { return true; //OK (no change needed) } if (tableExist(tableName)) { return false; //FAILURE (table already exist) } String sql = "ALTER TABLE " + this.tableName + " RENAME TO " + tableName + ";"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); Statement statement = connection.createStatement()) { statement.execute(sql); this.tableName = tableName; //OK (change successful) return true; } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); return false; //FAILURE (some other error) } } private boolean tableExist() { return tableExist(tableName); } public static boolean tableExist(String tableName) { String sql = "SELECT name FROM sqlite_master WHERE type='table' AND name='" + tableName + "'"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery(sql)) { while (rs.next()) { return true; } } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } return false; } public void removeTable() { String sql = "DROP TABLE IF EXISTS " + this.tableName + ";"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); Statement statement = connection.createStatement()) { statement.execute(sql); } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/profile/TableData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.profile; import net.nikr.eve.jeveasset.Program; public abstract class TableData { protected final ProfileManager profileManager; protected final ProfileData profileData; public TableData(Program program) { this(program.getProfileManager(), program.getProfileData()); } public TableData(ProfileManager profileManager, ProfileData profileData) { this.profileManager = profileManager; this.profileData = profileData; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/sde/Agent.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.sde; import net.nikr.eve.jeveasset.data.settings.types.CorporationType; import net.nikr.eve.jeveasset.data.settings.types.EditableLocationType; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.RawConverter; public class Agent implements Comparable, EditableLocationType, CorporationType { private final String agent; private final int agentID; //agentID : int private final NpcCorporation npcCorporation; private final int corporationID; //corporationID : int private final Integer level; private final int divisionID; //divisionID : int private final String division; private final int agentTypeID; //corporationID : int private final String agentType; private final long locationID; //corporationID : long private final boolean locator; private final boolean empty; private MyLocation location; public Agent(String agentName, int agentID, int corporationID, int level, int divisionID, int agentTypeID, long locationID, boolean locator) { this.agent = agentName; this.agentID = agentID; this.npcCorporation = ApiIdConverter.getNpcCorporation(corporationID); this.corporationID = corporationID; this.level = level; this.divisionID = divisionID; this.division = RawConverter.toAgentDivision(divisionID); this.agentTypeID = agentTypeID; this.agentType = RawConverter.toAgentType(agentTypeID); this.locationID = locationID; this.locator = locator; this.location = ApiIdConverter.getLocation(locationID); this.empty = false; } public Agent(Integer agentID) { this.agent = "!" + agentID; this.agentID = agentID; this.npcCorporation = ApiIdConverter.getNpcCorporation(0); this.corporationID = 0; this.level = null; this.divisionID = 0; this.division = null; this.agentTypeID = 0; this.agentType = null; this.locationID = 0; this.locator = false; this.location = null; this.empty = true; } public boolean isEmpty() { return empty; } public String getAgent() { return agent; } public int getAgentID() { return agentID; } @Override public String getCorporationName() { return npcCorporation.getCorporation(); } @Override public Integer getCorporationID() { return corporationID; } public String getFaction() { return npcCorporation.getFaction(); } public int getFactionID() { return npcCorporation.getFactionID(); } public Integer getLevel() { return level; } public int getDivisionID() { return divisionID; } public String getDivision() { return division; } public int getAgentTypeID() { return agentTypeID; } public String getAgentType() { return agentType; } @Override public long getLocationID() { return locationID; } public boolean isLocator() { return locator; } @Override public int compareTo(final Agent o) { return Integer.compare(agentID, o.agentID); } @Override public int hashCode() { int hash = 3; hash = 37 * hash + this.agentID; return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Agent other = (Agent) obj; return this.agentID == other.agentID; } @Override public void setLocation(MyLocation location) { this.location = location; } @Override public MyLocation getLocation() { return location; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/sde/IndustryMaterial.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.sde; public class IndustryMaterial { private final int typeID; //TypeID : int private final int quantity; public IndustryMaterial(int typeID, int quantity) { this.typeID = typeID; this.quantity = quantity; } public int getTypeID() { return typeID; } public int getQuantity() { return quantity; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/sde/Item.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.sde; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import net.nikr.eve.jeveasset.data.settings.types.ItemType; public class Item implements Comparable, ItemType { //PI public static final String CATEGORY_PLANETARY_INDUSTRY = "Planetary Industry"; public static final String CATEGORY_PLANETARY_COMMODITIES = "Planetary Commodities"; public static final String CATEGORY_PLANETARY_RESOURCES = "Planetary Resources"; public static final String GROUP_COMMAND_CENTERS = "Command Centers"; public static final String GROUP_EXTRACTOR_CONTROL_UNITS = "Extractor Control Units"; public static final String GROUP_PROCESSORS = "Processors"; public static final String GROUP_SPACEPORTS = "Spaceports"; public static final String GROUP_STORAGE_FACILITIES = "Storage Facilities"; //Containers public static final String GROUP_AUDIT_LOG_SECURE_CONTAINER = "Audit Log Secure Container"; public static final String GROUP_FREIGHT_CONTAINER = "Freight Container"; public static final String GROUP_CARGO_CONTAINER = "Cargo Container"; public static final String GROUP_SECURE_CARGO_CONTAINER = "Secure Cargo Container"; //Blueprint public static final String CATEGORY_BLUEPRINT = "Blueprint"; //Ship private static final String CATEGORY_SHIP = "Ship"; //Asteroid private static final String CATEGORY_ASTEROID = "Asteroid"; //Module public static final String CATEGORY_MODULE = "Module"; //Structure public static final String CATEGORY_STRUCTURE = "Structure"; //Material public static final String CATEGORY_MATERIAL = "Material"; //Deployable public static final String CATEGORY_DEPLOYABLE = "Deployable"; //Commodity public static final String CATEGORY_COMMODITY = "Commodity"; //Biomass public static final String GROUP_BIOMASS = "Biomass"; //Station Services public static final String GROUP_STATION_SERVICES = "Station Services"; //Compressed Gas public static final String GROUP_COMPRESSED_GAS = "Compressed Gas"; //Harvestable Cloud public static final String GROUP_HARVESTABLE_CLOUD = "Harvestable Cloud"; private final int typeID; //TypeID : int private final String name; private final String group; private final String category; private final long basePrice; private final float volume; private final float volumePackaged; private final float capacity; private final int meta; private final String tech; private final boolean marketGroup; private final boolean piMaterial; private final int portion; private final int productTypeID; private final Set blueprintTypeIDs = new HashSet<>(); private final int productQuantity; private final boolean blueprint; private final boolean formula; private final String version; private final List reprocessedMaterials = new ArrayList<>(); private final List manufacturingMaterials = new ArrayList<>(); private final List reactionMaterials = new ArrayList<>(); private final String slot; private final String chargeSize; //Dynamic values private double priceReprocessed; private double priceReprocessedMax; private double priceManufacturing; public Item(int typeID) { this(typeID, emptyType(typeID), "", "", -1, -1, -1, -1, -1, "", false, 0, 0, 1, "", "", null); } public Item(int typeID, String version) { this(typeID, emptyType(typeID), "", "", -1, -1, -1, -1, -1, "", false, 0, 0, 1, "", "", version); } public Item(Item item, long basePrice, String tech, int productTypeID, int productQuantity, Set blueprintTypeIDs, List reprocessedMaterials, List manufacturingMaterials, List reactionMaterials) { this(item.getTypeID(), item.getTypeName(), item.getGroup(), item.getCategory(), basePrice, item.getVolume(), item.getVolumePackaged(), item.getCapacity(), item.getMeta(), tech, item.isMarketGroup(), item.getPortion(), productTypeID, productQuantity, item.getSlot(), item.getChargeSize(), item.getVersion()); this.blueprintTypeIDs.addAll(blueprintTypeIDs); this.reprocessedMaterials.addAll(reprocessedMaterials); this.manufacturingMaterials.addAll(manufacturingMaterials); this.reactionMaterials.addAll(reactionMaterials); } public Item(final int typeID, final String name, final String group, final String category, final long basePrice, final float volume, final float volumePackaged, final float capacity, final int meta, final String tech, final boolean marketGroup, final int portion, final int productTypeID, final int productQuantity, String slot, String chargeSize, String version) { this.typeID = typeID; this.name = name; this.group = group.intern(); this.category = category.intern(); this.basePrice = basePrice; this.volume = volume; this.volumePackaged = volumePackaged; this.capacity = capacity; this.meta = meta; this.tech = tech.intern(); this.marketGroup = marketGroup; this.piMaterial = category.equals(CATEGORY_PLANETARY_COMMODITIES) || category.equals(CATEGORY_PLANETARY_RESOURCES); this.portion = portion; this.productTypeID = productTypeID; this.productQuantity = productQuantity; this.blueprint = this.category.equals(CATEGORY_BLUEPRINT) && group.toLowerCase().contains("blueprint"); this.formula = this.category.equals(CATEGORY_BLUEPRINT) && group.toLowerCase().contains("reaction formulas"); this.version = version; if (slot != null) { this.slot = slot; } else { this.slot = "None"; } if (chargeSize != null) { this.chargeSize = chargeSize; } else { this.chargeSize = "None"; } } public String getVersion() { return version; } public boolean isOre() { return category.equals(CATEGORY_ASTEROID); } public boolean isMined() { return category.equals(CATEGORY_ASTEROID) || group.equals(GROUP_HARVESTABLE_CLOUD) || group.equals(GROUP_COMPRESSED_GAS) ; } public boolean isShip() { return category.equals(CATEGORY_SHIP); } public boolean isContainer() { return group.equals(GROUP_AUDIT_LOG_SECURE_CONTAINER) || group.equals(GROUP_FREIGHT_CONTAINER) || group.equals(GROUP_CARGO_CONTAINER) || group.equals(GROUP_SECURE_CARGO_CONTAINER); } public void addReprocessedMaterial(final ReprocessedMaterial material) { reprocessedMaterials.add(material); } public List getReprocessedMaterial() { return reprocessedMaterials; } public void addManufacturingMaterial(IndustryMaterial industryMaterial) { manufacturingMaterials.add(industryMaterial); } public List getManufacturingMaterials() { return manufacturingMaterials; } public void addReactionMaterial(IndustryMaterial industryMaterial) { reactionMaterials.add(industryMaterial); } public List getReactionMaterials() { return reactionMaterials; } public String getCategory() { return category; } public String getGroup() { return group; } public int getTypeID() { return typeID; } public boolean isMarketGroup() { return marketGroup; } public int getMeta() { return meta; } public String getTech() { return tech; } public String getTypeName() { return name; } public double getPriceBase() { return basePrice; } public double getPriceReprocessed() { return priceReprocessed; } public double getPriceReprocessedMax() { return priceReprocessedMax; } public double getPriceManufacturing() { return priceManufacturing; } public float getVolume() { return volume; } public float getVolumePackaged() { return volumePackaged; } public float getCapacity() { return capacity; } public boolean isPiMaterial() { return piMaterial; } public boolean isBlueprint() { return blueprint; } public boolean isFormula() { return formula; } public int getPortion() { return portion; } public int getProductTypeID() { return productTypeID; } public int getProductQuantity() { return productQuantity; } public String getSlot() { return slot; } public String getChargeSize() { return chargeSize; } public boolean isEmpty() { return emptyType(typeID).equals(name); } private static String emptyType(int typeID) { return "!"+typeID; } @Override public Item getItem() { return this; } @Override public long getItemCount() { return 1; //Just this one item? } public boolean isProduct() { return !blueprintTypeIDs.isEmpty(); } public Set getBlueprintTypeIDs() { return blueprintTypeIDs; } public Integer getBlueprintTypeID() { if (blueprintTypeIDs.isEmpty()) { return 0; } else { return blueprintTypeIDs.iterator().next(); } } public void addBlueprintID(int blueprintID) { this.blueprintTypeIDs.add(blueprintID); } public void setPriceReprocessed(double priceReprocessed) { this.priceReprocessed = priceReprocessed; } public void setPriceReprocessedMax(double priceReprocessedMax) { this.priceReprocessedMax = priceReprocessedMax; } public void setPriceManufacturing(double priceManufacturing) { this.priceManufacturing = priceManufacturing; } @Override public String toString() { return name; } @Override public int compareTo(final Item o) { return this.getTypeName().compareToIgnoreCase(o.getTypeName()); } @Override public int hashCode() { int hash = 5; hash = 53 * hash + this.typeID; return hash; } @Override public boolean equals(java.lang.Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Item other = (Item) obj; if (this.typeID != other.typeID) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/sde/ItemFlag.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.sde; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class ItemFlag implements Comparable { private final int flagID; private final String flagName; private final String flagText; private final String toString; public ItemFlag(final int flagID, final String flagName, final String flagText) { this.flagID = flagID; this.flagName = flagName; this.flagText = flagText; this.toString = ApiIdConverter.getFlagName(this); } public int getFlagID() { return flagID; } public String getFlagName() { return flagName; } public String getFlagText() { return flagText; } @Override public String toString() { return toString; } @Override public int compareTo(final ItemFlag o) { return this.getFlagName().compareToIgnoreCase(o.getFlagName()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/sde/Jump.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.sde; /** * * @author Candle */ public class Jump { private MyLocation from; private MyLocation to; public Jump(final MyLocation from, final MyLocation to) { this.from = from; this.to = to; } public MyLocation getFrom() { return from; } public MyLocation getTo() { return to; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/sde/MyLocation.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.sde; import java.util.HashMap; import java.util.Map; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.table.containers.Security; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.i18n.GuiShared; import uk.me.candle.eve.pricing.options.NamedPriceLocation; public class MyLocation implements Comparable, NamedPriceLocation { private final static Map CACHE = new HashMap<>(); private final long locationID; //LocationID : long private String location; private long stationID; //LocationID : long private String station; private long systemID; //LocationID : long private String system; private long constellationID; //LocationID : long private String constellation; private long regionID; //LocationID : long private String region; private String security; private Security securityObject; private boolean citadel; private boolean empty; private boolean userLocation; public static void reset(long locationID) { MyLocation cached = CACHE.get(locationID); if (cached != null) { cached.updateLocation(new MyLocation(locationID)); } } public static MyLocation create(long locationID) { MyLocation cached = CACHE.get(locationID); if (cached == null) { cached = new MyLocation(locationID); CACHE.put(locationID, cached); } return cached; } public static MyLocation create(long stationID, String station, long systemID, String system, long constellationID, String constellation, long regionID, String region, String security, boolean citadel, boolean userLocation) { final MyLocation newLocation = new MyLocation(stationID, station, systemID, system, constellationID, constellation, regionID, region, security, citadel, userLocation); MyLocation cached = CACHE.get(newLocation.getLocationID()); if (cached == null) { //New cached = newLocation; CACHE.put(newLocation.getLocationID(), newLocation); } else { //Update cached.updateLocation(newLocation); } return cached; } private MyLocation(long locationID) { if (locationID == 2004) { this.location = General.get().assetSafety(); this.station = General.get().assetSafety(); this.system = General.get().assetSafety(); this.constellation = General.get().assetSafety(); this.region = General.get().assetSafety(); this.empty = false; } else { this.location = General.get().emptyLocation(String.valueOf(locationID)); this.station = General.get().emptyLocation(String.valueOf(locationID)); this.system = General.get().emptyLocation(String.valueOf(locationID)); this.constellation = General.get().emptyLocation(String.valueOf(locationID)); this.region = General.get().emptyLocation(String.valueOf(locationID)); this.empty = true; } this.locationID = locationID; this.stationID = 0; this.systemID = 0; this.constellationID = 0; this.regionID = 0; this.security = "0.0"; this.securityObject = Security.create(security); this.citadel = false; this.userLocation = false; } public MyLocation(long stationID, String station, long systemID, String system, long constellationID, String constellation, long regionID, String region, String security) { this(stationID, station, systemID, system, constellationID, constellation, regionID, region, security, false, false); } private MyLocation(long stationID, String station, long systemID, String system, long constellationID, String constellation, long regionID, String region, String security, boolean citadel, boolean userLocation) { this.stationID = stationID; this.station = station; this.systemID = systemID; this.system = system.intern(); this.constellationID = constellationID; this.constellation = constellation.intern(); this.regionID = regionID; this.region = region.intern(); this.security = security.intern(); this.securityObject = Security.create(security); if (isStation() || isPlanet()) { //Station or Planet empty = false; this.locationID = stationID; this.location = station; } else if (isSystem()) { empty = false; this.locationID = systemID; this.location = system.intern(); } else if (isConstellation()) { empty = false; this.locationID = constellationID; this.location = constellation.intern(); } else if (isRegion()) { empty = false; this.locationID = regionID; this.location = region.intern(); } else { empty = true; this.locationID = 0; this.location = ""; } this.citadel = citadel; this.userLocation = userLocation; } private void updateLocation(final MyLocation newLocation) { this.stationID = newLocation.stationID; this.station = newLocation.station; this.systemID = newLocation.systemID; this.system = newLocation.system.intern(); this.constellationID = newLocation.constellationID; this.constellation = newLocation.constellation.intern(); this.regionID = newLocation.regionID; this.region = newLocation.region.intern(); this.security = newLocation.security.intern(); this.securityObject = Security.create(newLocation.security); this.location = newLocation.location.intern(); this.empty = newLocation.empty; this.citadel = newLocation.citadel; this.userLocation = newLocation.userLocation; } @Override public String getLocation() { return location; } @Override public long getLocationID() { return locationID; } public String getStation() { return station; } public long getStationID() { return stationID; } public String getSystem() { return system; } public long getSystemID() { return systemID; } public long getConstellationID() { return constellationID; } public String getConstellation() { return constellation; } public String getRegion() { return region; } @Override public long getRegionID() { return regionID; } public String getSecurity() { return security; } public Security getSecurityObject() { return securityObject; } /** * Return true if this location is a Station * Will return false if this location is a Planet, System, Constellation, Region or Unknown/Empty locations * @return */ public final boolean isStation() { return getStationID() != 0 && getSystemID() != 0 && !isConstellation() && getRegionID() != 0 && (locationID < 40000000 || locationID > 50000000); } /** * Return true if this location is a Planet * Will return false if this location is a Station, System, Constellation, Region or Unknown/Empty locations * @return */ public final boolean isPlanet() { return getStationID() != 0 && getSystemID() != 0 && !isConstellation() && getRegionID() != 0 && locationID >= 40000000 && locationID <= 50000000; } /** * Return true if this location is a System * Will return false if this location is a Station, Planet, Constellation, Region or Unknown/Empty locations * @return */ public final boolean isSystem() { return getStationID() == 0 && getSystemID() != 0 && !isConstellation() && getRegionID() != 0; } /** * Return true if this location is a Constellation * Will return false if this location is a Station, Planet, System, Region or Unknown/Empty locations * @return */ public final boolean isConstellation() { return getStationID() == 0 && getSystemID() == 0 && getConstellationID() != 0 && getRegionID() != 0; } /** * Return true if this location is a Region * Will return false if this location is a Station, Planet, System, Constellation or Unknown/Empty locations * @return */ public final boolean isRegion() { return getStationID() == 0 && getSystemID() == 0 && !isConstellation() && getRegionID() != 0; } public String getFactionWarfareSystemOwner() { if (Settings.get().getFactionWarfareSystemOwners().isEmpty()) { return GuiShared.get().unknownFaction(); } String faction = Settings.get().getFactionWarfareSystemOwners().get(getSystemID()); if (faction != null) { return faction; } else { return GuiShared.get().none(); } } public boolean isEmpty() { return empty; } public boolean isCitadel() { return citadel; } public boolean isUserLocation() { return userLocation; } @Override public String toString() { return location; } @Override public boolean equals(final Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final MyLocation other = (MyLocation) obj; if (this.locationID != other.locationID) { return false; } if (this.systemID != other.systemID) { return false; } return true; } @Override public int hashCode() { int hash = 7; hash = 71 * hash + (int) (this.locationID ^ (this.locationID >>> 32)); hash = 71 * hash + (int) (this.systemID ^ (this.systemID >>> 32)); return hash; } @Override public int compareTo(final MyLocation o) { return getLocation().compareToIgnoreCase(o.getLocation()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/sde/NpcCorporation.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.sde; public class NpcCorporation implements Comparable { private final String faction; private final int factionID; //corporationID : int private final String corporation; private final int corporationID; //corporationID : int private final boolean connections; private final boolean criminalConnections; public NpcCorporation(String faction, int factionID, String corporation, int corporationID, boolean connections, boolean criminalConnections) { this.faction = faction; this.factionID = factionID; this.corporation = corporation; this.corporationID = corporationID; this.connections = connections; this.criminalConnections = criminalConnections; } public NpcCorporation(Integer corporationID) { this.faction = null; this.factionID = 0; this.corporation = null; this.corporationID = corporationID; this.connections = false; this.criminalConnections = false; } public boolean isFaction() { return corporationID == 0; } public String getFaction() { return faction; } public int getFactionID() { return factionID; } public String getCorporation() { return corporation; } public int getCorporationID() { return corporationID; } public boolean isConnections() { return connections; } public boolean isCriminalConnections() { return criminalConnections; } @Override public int compareTo(final NpcCorporation o) { return Integer.compare(corporationID, o.corporationID); } @Override public int hashCode() { int hash = 3; hash = 41 * hash + this.corporationID; return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final NpcCorporation other = (NpcCorporation) obj; return this.corporationID == other.corporationID; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/sde/ReprocessedMaterial.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.sde; public class ReprocessedMaterial { private int typeID; //TypeID : int private int quantity; private int portionSize; public ReprocessedMaterial(final int typeID, final int quantity, final int portionSize) { this.typeID = typeID; this.quantity = quantity; this.portionSize = portionSize; } public int getTypeID() { return typeID; } public int getPortionSize() { return portionSize; } public int getQuantity() { return quantity; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/sde/RouteFinder.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.sde; import java.util.HashMap; import java.util.Map; import java.util.Objects; import net.nikr.eve.jeveasset.SplashUpdater; import net.nikr.eve.jeveasset.data.settings.RouteAvoidSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.tabs.routing.SolarSystem; import uk.me.candle.eve.graph.DisconnectedGraphException; import uk.me.candle.eve.graph.Edge; import uk.me.candle.eve.graph.Graph; import uk.me.candle.eve.graph.distances.Jumps; public class RouteFinder { public static enum RouteFinderFilter { JUMPS() { @Override public RouteAvoidSettings getRouteAvoidSettings() { return Settings.get().getJumpsAvoidSettings(); } }, MARKET_ORDERS() { @Override public RouteAvoidSettings getRouteAvoidSettings() { return null; //Unfiltered } }; private final Map systemCache = new HashMap<>(); private final Graph graph = new Graph<>(new Jumps<>()); private final Map distance = new HashMap<>(); public Graph getGraph() { return graph; } Map getDistance() { return distance; } public Map getSystemCache() { return systemCache; } public void update() { systemCache.clear(); distance.clear(); graph.clear(); generateGraph(systemCache, graph, getRouteAvoidSettings()); } abstract public RouteAvoidSettings getRouteAvoidSettings(); } private static RouteFinder DISTANCE; private RouteFinder() { // build the graph. // filter the solarsystems based on the settings. for (RouteFinderFilter filter : RouteFinderFilter.values()) { filter.update(); } } public static void generateGraph(Map systemCache, Graph graph, RouteAvoidSettings avoidSettings) { int count = 0; for (Jump jump : StaticData.get().getJumps()) { // this way we exclude the locations that are unreachable. count++; SplashUpdater.setSubProgress((int) (count * 100.0 / StaticData.get().getJumps().size())); SolarSystem from = systemCache.get(jump.getFrom().getSystemID()); SolarSystem to = systemCache.get(jump.getTo().getSystemID()); if (from == null) { from = SolarSystem.create(systemCache, jump.getFrom()); } if (to == null) { to = SolarSystem.create(systemCache, jump.getTo()); } if (avoidSettings == null || (jump.getFrom().getSecurityObject().getDouble() >= avoidSettings.getSecMin() && jump.getTo().getSecurityObject().getDouble() >= avoidSettings.getSecMin() && jump.getFrom().getSecurityObject().getDouble() <= avoidSettings.getSecMax() && jump.getTo().getSecurityObject().getDouble() <= avoidSettings.getSecMax() && !avoidSettings.getAvoid().keySet().contains(jump.getFrom().getSystemID()) && !avoidSettings.getAvoid().keySet().contains(jump.getTo().getSystemID()) )) { graph.addEdge(new Edge<>(from, to)); } } } public Integer distanceBetween(RouteFinderFilter filter, Long fromSystemID, Long toSystemID) { if (fromSystemID == null || toSystemID == null) { return null; } if (Objects.equals(fromSystemID, toSystemID)) { return 0; } Route route = new Route(fromSystemID, toSystemID); Integer jumps = filter.getDistance().get(route); if (jumps != null) { if (jumps < 0) { return null; } else { return jumps; } //Saved route } SolarSystem from = filter.getSystemCache().get(fromSystemID); SolarSystem to = filter.getSystemCache().get(toSystemID); if (from == null || to == null) { filter.getDistance().put(route, -2); return null; } try { jumps = filter.getGraph().distanceBetween(from, to); filter.getDistance().put(route, jumps); return jumps; } catch (DisconnectedGraphException ex) { filter.getDistance().put(route, -1); } return null; } public static void load() { get(); } public static synchronized RouteFinder get() { if (DISTANCE == null) { DISTANCE = new RouteFinder(); } return DISTANCE; } private static class Route { private final Long lowSystemID; private final Long highSystemID; public Route(Long fromSystemID, Long toSystemID) { if (fromSystemID < toSystemID) { this.lowSystemID = fromSystemID; this.highSystemID = toSystemID; } else { this.lowSystemID = toSystemID; this.highSystemID = fromSystemID; } } @Override public int hashCode() { int hash = 5; hash = 47 * hash + Objects.hashCode(this.lowSystemID); hash = 47 * hash + Objects.hashCode(this.highSystemID); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Route other = (Route) obj; if (!Objects.equals(this.lowSystemID, other.lowSystemID)) { return false; } if (!Objects.equals(this.highSystemID, other.highSystemID)) { return false; } return true; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/sde/StaticData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.sde; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.locks.ReentrantReadWriteLock; import net.nikr.eve.jeveasset.SplashUpdater; import net.nikr.eve.jeveasset.io.local.AgentsReader; import net.nikr.eve.jeveasset.io.local.FlagsReader; import net.nikr.eve.jeveasset.io.local.ItemsReader; import net.nikr.eve.jeveasset.io.local.JumpsReader; import net.nikr.eve.jeveasset.io.local.LocationsReader; import net.nikr.eve.jeveasset.io.local.NpcCorporationsReader; public class StaticData { private static final ReentrantReadWriteLock LOCATIONS_LOCK = new ReentrantReadWriteLock(); //Data private final Map items = new HashMap<>(); //TypeID : int private final Map flags = new HashMap<>(); //FlagID : int private final Map locations = new HashMap<>(); //LocationID : long private final List jumps = new ArrayList<>(); //LocationID : long private final Map agents = new HashMap<>(); //AgentID : int private final Map npcCorporations = new HashMap<>(); //corporationID : int private static StaticData staticData = null; private StaticData() {} public static StaticData get() { load(); return staticData; } public static synchronized void load() { if (staticData == null) { staticData = new StaticData(); staticData.loadData(); } } private void loadData() { SplashUpdater.setProgress(5); ItemsReader.load(items); //Items SplashUpdater.setProgress(10); try { LOCATIONS_LOCK.writeLock().lock(); LocationsReader.load(locations); //Locations } finally { LOCATIONS_LOCK.writeLock().unlock(); } SplashUpdater.setProgress(15); JumpsReader.load(jumps); //Jumps SplashUpdater.setProgress(20); FlagsReader.load(flags); //Item Flags NpcCorporationsReader.load(npcCorporations); //Must be loaded after locations AgentsReader.load(agents); //Must be loaded after locations SplashUpdater.setProgress(25); } public Map getItemFlags() { return flags; } public Map getItems() { return items; } public List getJumps() { return jumps; } public Map getAgents() { return agents; } public Map getNpcCorporations() { return npcCorporations; } public void addLocation(MyLocation location) { try { LOCATIONS_LOCK.writeLock().lock(); locations.put(location.getLocationID(), location); } finally { LOCATIONS_LOCK.writeLock().unlock(); } } public void removeLocation(long locationID) { try { LOCATIONS_LOCK.writeLock().lock(); locations.remove(locationID); } finally { LOCATIONS_LOCK.writeLock().unlock(); } } public MyLocation getLocation(long locationID) { try { LOCATIONS_LOCK.readLock().lock(); return locations.get(locationID); } finally { LOCATIONS_LOCK.readLock().unlock(); } } public Collection getLocations() { try { LOCATIONS_LOCK.readLock().lock(); return new ArrayList<>(locations.values()); //Copy } finally { LOCATIONS_LOCK.readLock().unlock(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/AddedData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Date; import java.util.HashMap; import java.util.Map; import net.nikr.eve.jeveasset.io.local.AssetAddedReader; import net.nikr.eve.jeveasset.io.local.profile.ProfileTable.Rows; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AddedData { private static final Logger LOG = LoggerFactory.getLogger(AddedData.class); private static enum DataSettings { ASSETS("assetadded") { @Override public void load() { AssetAddedReader.load(); } }, TRANSACTIONS("transactionadded"), JOURNALS("journaladded"), MARKET_ORDERS("marketorderadded"), ; private final AddedData addedData; private final String tableName; private DataSettings(String tableName) { this.tableName = tableName; this.addedData = new AddedData(this); } public String getTableName() { return tableName; } public AddedData getInstance() { return addedData; } public void load() { } } private Map insert = null; private Map update = null; private final DataSettings dataSettings; private String getConnectionURL() { return "jdbc:sqlite:" + FileUtil.getPathAssetAddedDatabase(); } private AddedData(DataSettings dataSettings) { this.dataSettings = dataSettings; } public static AddedData getAssets() { return DataSettings.ASSETS.getInstance(); } public static AddedData getTransactions() { return DataSettings.TRANSACTIONS.getInstance(); } public static AddedData getJournals() { return DataSettings.JOURNALS.getInstance(); } public static AddedData getMarketOrders() { return DataSettings.MARKET_ORDERS.getInstance(); } public static void load() { for (DataSettings dataSettings : DataSettings.values()) { dataSettings.getInstance().init(); } } private void init() { if (!tableExist()) { //New database: Import from added.json dataSettings.load(); } if (!tableExist()) { //New database: Empty createTable(); } } /** * Update if date is before the current value. * @param data current data * @param id unique id * @param added * @return */ public Date getAdd(Map data, Long id, Date added) { Date date = data.get(id); if (date == null) { //Insert date = added; insertQueue(id, date); } if (date.after(added)) { //Update date = added; updateQueue(id, date); } return date; } /** * Update if date is after the current value. * @param data current data * @param id unique id * @param added * @return */ public Date getPut(Map data, Long id, Date added) { Date date = data.get(id); if (date == null) { //Insert date = added; insertQueue(id, date); } if (date.before(added)) { //Update date = added; updateQueue(id, date); } return date; } private void insertQueue(Long id, Date date) { if (insert == null) { insert = new HashMap<>(); } insert.put(id, date); } private void updateQueue(Long id, Date date) { if (update == null) { update = new HashMap<>(); } update.put(id, date); } public void commitQueue() { insert(insert); update(update); update = null; insert = null; } public boolean isEmpty() { String sql = "SELECT * FROM " + dataSettings.getTableName(); try (Connection connection = DriverManager.getConnection(getConnectionURL()); PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery()) { while (rs.next()) { return false; } } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } return true; } public void set(Map data) { if (data == null || data.isEmpty() || tableExist()) { return; } createTable(); insert(data); } private void insert(Map data) { if (data == null || data.isEmpty()) { return; } String sql = "INSERT INTO " + dataSettings.getTableName() + "(itemid,date) VALUES(?,?)"; try (Connection connection = DriverManager.getConnection(getConnectionURL()); PreparedStatement statement = connection.prepareStatement(sql)) { connection.setAutoCommit(false); Rows rows = new Rows(statement, data.size()); for (Map.Entry entry : data.entrySet()) { statement.setLong(1, entry.getKey()); statement.setLong(2, entry.getValue().getTime()); rows.addRow(); } connection.commit(); connection.setAutoCommit(true); } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } public void update(Map data) { if (data == null || data.isEmpty()) { return; } String sql = "UPDATE " + dataSettings.getTableName() + " SET date = ? WHERE itemid = ?"; try (Connection connection = DriverManager.getConnection(getConnectionURL()); PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, data.size()); connection.setAutoCommit(false); for (Map.Entry entry : data.entrySet()) { statement.setLong(1, entry.getValue().getTime()); statement.setLong(2, entry.getKey()); rows.addRow(); } connection.commit(); connection.setAutoCommit(true); } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } public Map getAll() { Map map = new HashMap<>(); String sql = "SELECT * FROM " + dataSettings.getTableName(); try (Connection connection = DriverManager.getConnection(getConnectionURL()); PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery(); ) { while (rs.next()) { map.put(rs.getLong("itemid"), new Date(rs.getLong("date"))); } } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } return map; //can not return null } private void createTable() { String sql = "CREATE TABLE IF NOT EXISTS " + dataSettings.getTableName() + " (\n" + " itemid integer PRIMARY KEY,\n" + " date integer NOT NULL\n" + ");"; try (Connection connection = DriverManager.getConnection(getConnectionURL()); Statement statement = connection.createStatement()) { statement.execute(sql); } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } private boolean tableExist() { String sql = "SELECT name FROM sqlite_master WHERE type='table' AND name='" + dataSettings.getTableName() + "'"; try (Connection connection = DriverManager.getConnection(getConnectionURL()); Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery(sql)) { while (rs.next()) { return true; } } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } return false; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/Citadel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.StaticData; public class Citadel { public static enum CitadelSource { ESI_STRUCTURES(3), //Certified fresh ESI_LOCATIONS(3), //Good source ESI_PLANET(3), //Planet source ESI_MOON(3), //Moon source FUZZWORK_PLANET(3), //Planet source USER(2), //User set this data (unless we have top-notch info, don't overwrite) ZKILL(1), //Outdated source HAMMERTIME(1), //Outdated source OLD(1), //Unknown source - keep if? ESI_BOOKMARKS(0), //Unknown location name, but, known system and region EVEKIT_BOOKMARKS(0), //Unknown location name, but, known system and region EMPTY(-1) //100% Unknown location ; private final int priority; private CitadelSource(int priority) { this.priority = priority; } public int getPriority() { return priority; } } private long locationID; private String location; private long systemID; private boolean userLocation; private boolean citadel; private CitadelSource source; private MyLocation myLocation; /** * Empty location * @param id locationID */ public Citadel(long id) { this(id, "", 0, false, true, CitadelSource.EMPTY); } /** * * @param locationID * @param location * @param systemID * @param userLocation * @param citadel * @param source */ public Citadel(long locationID, String location, long systemID, boolean userLocation, boolean citadel, CitadelSource source) { this.locationID = locationID; this.location = location; this.systemID = systemID; this.userLocation = userLocation; this.citadel = citadel; this.source = source; updateLocation(); } public void update(Citadel citadel) { this.locationID = citadel.locationID; this.location = citadel.location; this.systemID = citadel.systemID; this.userLocation = citadel.userLocation; this.citadel = citadel.citadel; this.source = citadel.source; updateLocation(); } private void updateLocation() { MyLocation system = StaticData.get().getLocation(systemID); if (!isEmpty() && system != null) { //Location is valid -> return locations if (userLocation) { myLocation = MyLocation.create(locationID, system.getSystem() + " - " + location, systemID, system.getSystem(), system.getConstellationID(), system.getConstellation(), system.getRegionID(), system.getRegion(), system.getSecurity(), citadel, userLocation); } else { myLocation = MyLocation.create(locationID, location, systemID, system.getSystem(), system.getConstellationID(), system.getConstellation(), system.getRegionID(), system.getRegion(), system.getSecurity(), citadel, userLocation); } } else { //Location not valid -> return fallback location myLocation = null; } } public long getLocationID() { return locationID; } public String getLocation() { return location; } public long getSystemID() { return systemID; } public boolean isEmpty() { return systemID == 0; } public boolean isUserLocation() { return userLocation; } public boolean isCitadel() { return citadel; } public CitadelSource getSource() { return source; } public MyLocation toLocation() { return myLocation; } @Override public String toString() { return myLocation.toString(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/CitadelSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.HashMap; import java.util.Map; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class CitadelSettings { private final Map cache = new HashMap<>(); public Citadel get(long location) { return cache.get(location); } public Iterable> getCache() { return cache.entrySet(); } public void put(long locationID, Citadel citadel) { Citadel old = cache.get(locationID); if (old != null && !old.isEmpty() && old.getSource().getPriority() > citadel.getSource().getPriority()) { return; } if (old == null) { cache.put(locationID, citadel); ApiIdConverter.addLocation(citadel); } else { old.update(citadel); } } public void remove(long locationID) { cache.remove(locationID); MyLocation.reset(locationID); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/ColorEntry.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import net.nikr.eve.jeveasset.i18n.DataColors; public enum ColorEntry { ASSETS_REPROCESSING_EQUAL(ColorEntryGroup.ASSETS, DataColors.get().assetsReprocessingEqual()), ASSETS_REPROCESSING_REPROCES(ColorEntryGroup.ASSETS, DataColors.get().assetsReprocessingReproces()), ASSETS_REPROCESSING_SELL(ColorEntryGroup.ASSETS, DataColors.get().assetsReprocessingSell()), ASSETS_REPROCESS(ColorEntryGroup.ASSETS, DataColors.get().assetsReprocess()), ASSETS_NEW(ColorEntryGroup.ASSETS, DataColors.get().assetsNew()), CUSTOM_PRICE(ColorEntryGroup.CUSTOM, DataColors.get().customPrice()), CUSTOM_ASSET_NAME(ColorEntryGroup.CUSTOM, DataColors.get().customAssetName()), CUSTOM_USER_LOCATION(ColorEntryGroup.CUSTOM, DataColors.get().customUserLocation()), CONTRACTS_COURIER(ColorEntryGroup.CONTRACTS, DataColors.get().contractsCourier()), CONTRACTS_INCLUDED(ColorEntryGroup.CONTRACTS, DataColors.get().contractsIncluded()), CONTRACTS_EXCLUDED(ColorEntryGroup.CONTRACTS, DataColors.get().contractsExcluded()), EXTRACTIONS_DAYS(ColorEntryGroup.EXTRACTIONS, DataColors.get().extractionsDays()), EXTRACTIONS_WEEK(ColorEntryGroup.EXTRACTIONS, DataColors.get().extractionsWeek()), EXTRACTIONS_WEEKS(ColorEntryGroup.EXTRACTIONS, DataColors.get().extractionsWeeks()), OVERVIEW_GROUPED_LOCATIONS(ColorEntryGroup.OVERVIEW, DataColors.get().overviewGroupedLocations()), STOCKPILE_TABLE_BELOW_THRESHOLD(ColorEntryGroup.STOCKPILE, DataColors.get().stockpileTableBelowThreshold()), STOCKPILE_ICON_BELOW_THRESHOLD(ColorEntryGroup.STOCKPILE, DataColors.get().stockpileIconBelowThreshold(), Background.EDITABLE_AND_NOT_NULL, Foreground.NOT_EDITABLE), STOCKPILE_TABLE_BELOW_THRESHOLD_2ND(ColorEntryGroup.STOCKPILE, DataColors.get().stockpileTableBelowThreshold2nd()), STOCKPILE_ICON_BELOW_THRESHOLD_2ND(ColorEntryGroup.STOCKPILE, DataColors.get().stockpileIconBelowThreshold2nd(), Background.EDITABLE_AND_NOT_NULL, Foreground.NOT_EDITABLE), STOCKPILE_TABLE_OVER_THRESHOLD(ColorEntryGroup.STOCKPILE, DataColors.get().stockpileTableOverThreshold()), STOCKPILE_ICON_OVER_THRESHOLD(ColorEntryGroup.STOCKPILE, DataColors.get().stockpileIconOverThreshold(), Background.EDITABLE_AND_NOT_NULL, Foreground.NOT_EDITABLE), MARKET_ORDERS_OUTBID_NOT_BEST(ColorEntryGroup.MARKET_ORDERS, DataColors.get().marketOrdersOutbidNotBest()), MARKET_ORDERS_OUTBID_NOT_BEST_OWNED(ColorEntryGroup.MARKET_ORDERS, DataColors.get().marketOrdersOutbidNotBestOwned()), MARKET_ORDERS_OUTBID_BEST(ColorEntryGroup.MARKET_ORDERS, DataColors.get().marketOrdersOutbidBest()), MARKET_ORDERS_OUTBID_UNKNOWN(ColorEntryGroup.MARKET_ORDERS, DataColors.get().marketOrdersOutbidUnknown()), MARKET_ORDERS_EXPIRED(ColorEntryGroup.MARKET_ORDERS, DataColors.get().marketOrdersExpired()), MARKET_ORDERS_NEAR_EXPIRED(ColorEntryGroup.MARKET_ORDERS, DataColors.get().marketOrdersNearExpired()), MARKET_ORDERS_NEAR_FILLED(ColorEntryGroup.MARKET_ORDERS, DataColors.get().marketOrdersNearFilled()), MARKET_ORDERS_NEW(ColorEntryGroup.MARKET_ORDERS, DataColors.get().marketOrdersNew()), INDUSTRY_JOBS_DELIVERED(ColorEntryGroup.INDUSTRY_JOBS, DataColors.get().industryJobsDelivered()), INDUSTRY_JOBS_DONE(ColorEntryGroup.INDUSTRY_JOBS, DataColors.get().industryJobsDone()), INDUSTRY_JOBS_ACTIVITY_MANUFACTURING(ColorEntryGroup.INDUSTRY_JOBS, DataColors.get().industryJobsManufacturing()), INDUSTRY_JOBS_ACTIVITY_RESEARCHING_TECHNOLOGY(ColorEntryGroup.INDUSTRY_JOBS, DataColors.get().industryJobsResearchingTechnology()), INDUSTRY_JOBS_ACTIVITY_RESEARCHING_TIME_PRODUCTIVITY(ColorEntryGroup.INDUSTRY_JOBS, DataColors.get().industryJobsResearchingTimeProductivity()), INDUSTRY_JOBS_ACTIVITY_RESEARCHING_METERIAL_PRODUCTIVITY(ColorEntryGroup.INDUSTRY_JOBS, DataColors.get().industryJobsResearchingMeterialProductivity()), INDUSTRY_JOBS_ACTIVITY_COPYING(ColorEntryGroup.INDUSTRY_JOBS, DataColors.get().industryJobsCopying()), INDUSTRY_JOBS_ACTIVITY_DUPLICATING(ColorEntryGroup.INDUSTRY_JOBS, DataColors.get().industryJobsDuplicating()), INDUSTRY_JOBS_ACTIVITY_REVERSE_ENGINEERING(ColorEntryGroup.INDUSTRY_JOBS, DataColors.get().industryJobsReverseEngineering()), INDUSTRY_JOBS_ACTIVITY_REVERSE_INVENTION(ColorEntryGroup.INDUSTRY_JOBS, DataColors.get().industryJobsReverseInvention()), INDUSTRY_JOBS_ACTIVITY_REACTIONS(ColorEntryGroup.INDUSTRY_JOBS, DataColors.get().industryJobsReactions()), INDUSTRY_SLOTS_FREE(ColorEntryGroup.SLOTS, DataColors.get().slotsFree()), INDUSTRY_SLOTS_DONE(ColorEntryGroup.SLOTS, DataColors.get().slotsDone()), INDUSTRY_SLOTS_FULL(ColorEntryGroup.SLOTS, DataColors.get().slotsFull()), JOURNAL_NEW(ColorEntryGroup.JOURNAL, DataColors.get().journalNew()), TRANSACTIONS_BOUGHT(ColorEntryGroup.TRANSACTIONS, DataColors.get().transactionsBought()), TRANSACTIONS_SOLD(ColorEntryGroup.TRANSACTIONS, DataColors.get().transactionsSold()), TRANSACTIONS_NEW(ColorEntryGroup.TRANSACTIONS, DataColors.get().transactionsNew()), NPC_STANDING_NEGATIVE(ColorEntryGroup.NPC_STANDING, DataColors.get().npcStandingNegative()), NPC_STANDING_POSITIVE(ColorEntryGroup.NPC_STANDING, DataColors.get().npcStandingPositive()), NPC_STANDING_NEGATIVE_MIDDLE(ColorEntryGroup.NPC_STANDING, DataColors.get().npcStandingNegativeMiddle()), NPC_STANDING_POSITIVE_MIDDLE(ColorEntryGroup.NPC_STANDING, DataColors.get().npcStandingPositiveMiddle()), GLOBAL_BPC(ColorEntryGroup.GLOBAL, DataColors.get().globalBPC()), GLOBAL_BPO(ColorEntryGroup.GLOBAL, DataColors.get().globalBPO()), GLOBAL_VALUE_NEGATIVE(ColorEntryGroup.GLOBAL, DataColors.get().globalValueNegative()), GLOBAL_VALUE_POSITIVE(ColorEntryGroup.GLOBAL, DataColors.get().globalValuePositive(), Background.NOT_EDITABLE, Foreground.NOT_EDITABLE), GLOBAL_ENTRY_INVALID(ColorEntryGroup.GLOBAL, DataColors.get().globalEntryInvalid()), GLOBAL_ENTRY_WARNING(ColorEntryGroup.GLOBAL, DataColors.get().globalEntryWarning()), GLOBAL_ENTRY_VALID(ColorEntryGroup.GLOBAL, DataColors.get().globalEntryValid()), GLOBAL_GRAND_TOTAL(ColorEntryGroup.GLOBAL, DataColors.get().globalGrandTotal(), Background.NOT_EDITABLE, Foreground.NOT_EDITABLE), GLOBAL_SELECTED_ROW_HIGHLIGHTING(ColorEntryGroup.GLOBAL, DataColors.get().globalSelectedRowHighlighting()), FILTER_OR_GROUP_1(ColorEntryGroup.FILTERS, DataColors.get().filterOrGroup1(), Background.EDITABLE_AND_NOT_NULL, Foreground.NOT_EDITABLE), FILTER_OR_GROUP_2(ColorEntryGroup.FILTERS, DataColors.get().filterOrGroup2(), Background.EDITABLE_AND_NOT_NULL, Foreground.NOT_EDITABLE), FILTER_OR_GROUP_3(ColorEntryGroup.FILTERS, DataColors.get().filterOrGroup3(), Background.EDITABLE_AND_NOT_NULL, Foreground.NOT_EDITABLE), FILTER_OR_GROUP_4(ColorEntryGroup.FILTERS, DataColors.get().filterOrGroup4(), Background.EDITABLE_AND_NOT_NULL, Foreground.NOT_EDITABLE), FILTER_OR_GROUP_5(ColorEntryGroup.FILTERS, DataColors.get().filterOrGroup5(), Background.EDITABLE_AND_NOT_NULL, Foreground.NOT_EDITABLE), FILTER_OR_GROUP_6(ColorEntryGroup.FILTERS, DataColors.get().filterOrGroup6(), Background.EDITABLE_AND_NOT_NULL, Foreground.NOT_EDITABLE), FILTER_OR_GROUP_7(ColorEntryGroup.FILTERS, DataColors.get().filterOrGroup7(), Background.EDITABLE_AND_NOT_NULL, Foreground.NOT_EDITABLE), REPROCESSED_SELL(ColorEntryGroup.REPROCESSED, DataColors.get().reprocessedSell(), Background.EDITABLE_AND_NOT_NULL, Foreground.NOT_EDITABLE), REPROCESSED_REPROCESS(ColorEntryGroup.REPROCESSED, DataColors.get().reprocessedReprocess(), Background.EDITABLE_AND_NOT_NULL, Foreground.NOT_EDITABLE), REPROCESSED_EQUAL(ColorEntryGroup.REPROCESSED, DataColors.get().reprocessedEqual(), Background.EDITABLE_AND_NOT_NULL, Foreground.NOT_EDITABLE), ; private final ColorEntryGroup group; private final String description; private final Background backgroundType; private final Foreground foregroundType; private ColorEntry(ColorEntryGroup group, String description) { this(group, description, Background.EDITABLE_AND_NULLABLE, Foreground.EDITABLE_AND_NULLABLE); } private ColorEntry(ColorEntryGroup group, String description, Background backgroundType, Foreground foregroundType) { this.group = group; this.description = description; this.backgroundType = backgroundType; this.foregroundType = foregroundType; } public ColorEntryGroup getGroup() { return group; } public String getDescription() { return description; } public boolean isBackgroundEditable() { return backgroundType == Background.EDITABLE_AND_NULLABLE || backgroundType == Background.EDITABLE_AND_NOT_NULL; } public boolean isBackgroundNullable() { return backgroundType == Background.EDITABLE_AND_NULLABLE; } public boolean isForegroundEditable() { return foregroundType == Foreground.EDITABLE_AND_NULLABLE || foregroundType == Foreground.EDITABLE_AND_NOT_NULL; } public boolean isForegroundNullable() { return foregroundType == Foreground.EDITABLE_AND_NULLABLE; } private static enum Background { EDITABLE_AND_NULLABLE, EDITABLE_AND_NOT_NULL, NOT_EDITABLE } private static enum Foreground { EDITABLE_AND_NULLABLE, EDITABLE_AND_NOT_NULL, NOT_EDITABLE } public static enum ColorEntryGroup { ASSETS(DataColors.get().groupAssets()), CUSTOM(DataColors.get().groupCustom()), CONTRACTS(DataColors.get().groupContracts()), EXTRACTIONS(DataColors.get().groupExtractions()), OVERVIEW(DataColors.get().groupOverview()), MARKET_ORDERS(DataColors.get().groupMarketOrders()), INDUSTRY_JOBS(DataColors.get().groupIndustryJobs()), SLOTS(DataColors.get().groupSlots()), JOURNAL(DataColors.get().groupJournal()), TRANSACTIONS(DataColors.get().groupTransactions()), NPC_STANDING(DataColors.get().groupNpcStanding()), GLOBAL(DataColors.get().groupGlobal()), FILTERS(DataColors.get().groupFilters()), REPROCESSED(DataColors.get().groupReprocessed()), STOCKPILE(DataColors.get().groupStockpile()); private final String name; private ColorEntryGroup(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return name; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/ColorSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.awt.Color; import java.awt.Component; import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JTextField; import javax.swing.UIManager; import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.border.Border; import net.nikr.eve.jeveasset.data.settings.ColorTheme.ColorThemeTypes; import net.nikr.eve.jeveasset.gui.shared.ColorUtil; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class ColorSettings { public static enum PredefinedLookAndFeel { DEFAULT(null, UIManager.getSystemLookAndFeelClassName(), true), FLAT_LIGHT(DialoguesSettings.get().lookAndFeelFlatLight(), "com.formdev.flatlaf.FlatLightLaf"), FLAT_INTELLIJ(DialoguesSettings.get().lookAndFeelFlatIntelliJ(), "com.formdev.flatlaf.FlatIntelliJLaf"), FLAT_DARK(DialoguesSettings.get().lookAndFeelFlatDark(), "com.formdev.flatlaf.FlatDarkLaf"), FLAT_DARCULA(DialoguesSettings.get().lookAndFeelFlatDarcula(), "com.formdev.flatlaf.FlatDarculaLaf"), DARK_NIMBUS(DialoguesSettings.get().lookAndFeelNimbusDark(), DarkNimbus.class.getName()), ; private final String name; private final String className; private final boolean selected; private PredefinedLookAndFeel(String name, String className) { this(name, className, false); } private PredefinedLookAndFeel(String name, String className, boolean selected) { if (name == null) { for (LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) { if (laf.getClassName().equals(UIManager.getSystemLookAndFeelClassName())) { name = DialoguesSettings.get().lookAndFeelDefaultName(laf.getName()); break; } } if (name == null) { name = DialoguesSettings.get().lookAndFeelDefault(); } } this.name = name; this.className = className; this.selected = selected; } public boolean isSelected() { return selected; } public LookAndFeelInfo getLookAndFeelInfo() { return new LookAndFeelInfo(name, className); } } private String lookAndFeelClass = UIManager.getSystemLookAndFeelClassName(); private ColorTheme colorTheme = ColorThemeTypes.DEFAULT.getInstance(); private final Map backgrounds = new EnumMap<>(ColorEntry.class); private final Map foregrounds = new EnumMap<>(ColorEntry.class); private static final Map BORDERS = new HashMap<>(); public ColorSettings() { for (ColorEntry colorEntry : ColorEntry.values()) { backgrounds.put(colorEntry, colorTheme.getDefaultBackground(colorEntry)); foregrounds.put(colorEntry, colorTheme.getDefaultForeground(colorEntry)); } } public String getLookAndFeelClass() { return lookAndFeelClass; } public boolean isFlatLAF() { return lookAndFeelClass.startsWith("com.formdev.flatlaf"); } public void setLookAndFeelClass(String lookAndFeelClass) { this.lookAndFeelClass = lookAndFeelClass; } public ColorTheme getColorTheme() { return colorTheme; } public void setColorTheme(ColorTheme colorTheme, boolean overwrite) { //Setting new colors for (ColorEntry colorEntry : ColorEntry.values()) { boolean defaultBackground = Objects.equals(getBackgrounds().get(colorEntry), getColorTheme().getDefaultBackground(colorEntry)); if (defaultBackground || overwrite) { getBackgrounds().put(colorEntry, colorTheme.getDefaultBackground(colorEntry)); } boolean defaultForeground = Objects.equals(getForegrounds().get(colorEntry), getColorTheme().getDefaultForeground(colorEntry)); if (defaultForeground || overwrite) { getForegrounds().put(colorEntry, colorTheme.getDefaultForeground(colorEntry)); } } //Setting ColorTheme (must be done last) this.colorTheme = colorTheme; } private Map getBackgrounds() { return backgrounds; } private Map getForegrounds() { return foregrounds; } public Color getBackground(ColorEntry colorEntry) { return getBackgrounds().get(colorEntry); } public Color getForeground(ColorEntry colorEntry) { return getForegrounds().get(colorEntry); } public boolean setForeground(ColorEntry colorEntry, Color foreground) { return setMap(colorEntry, foreground, getForegrounds()); } public boolean setBackground(ColorEntry colorEntry, Color background) { return setMap(colorEntry, background, getBackgrounds()); } private boolean setMap(ColorEntry colorEntry, Color color, Map map) { if (color == null) { //None Color removed = map.remove(colorEntry); return removed != null; //Removed } else { //Color Color old = map.put(colorEntry, color); if (old != null) { return !old.equals(color); //Changed } else { return true; //New } } } public List get() { List rows = new ArrayList<>(); for (ColorEntry colorEntry : ColorEntry.values()) { if (!colorEntry.isBackgroundEditable() && !colorEntry.isForegroundEditable()) { continue; } rows.add(new ColorRow(colorEntry, colorTheme.getDefaultBackground(colorEntry), colorTheme.getDefaultForeground(colorEntry), getBackground(colorEntry), getForeground(colorEntry))); } return rows; } public boolean set(ColorRow colorRow) { boolean changed = setForeground(colorRow.getColorEntry(), colorRow.getForeground()); return setBackground(colorRow.getColorEntry(), colorRow.getBackground()) || changed; } public static Color background(ColorEntry colorEntry) { return Settings.get().getColorSettings().getBackground(colorEntry); } private static Color foreground(ColorEntry colorEntry) { return Settings.get().getColorSettings().getForeground(colorEntry); } public static void config(Component component, ColorEntry colorEntry) { Color foreground = foreground(colorEntry); Color background = background(colorEntry); if (background != null) { component.setBackground(background); } if (foreground != null) { component.setForeground(foreground); } else { component.setForeground(Colors.COMPONENT_FOREGROUND.getColor()); } } public static void config(JComponent component, ColorEntry colorEntry) { Color foreground = foreground(colorEntry); Color background = background(colorEntry); if (component == null) { return; } if (background != null) { /** * Nimbus JTextField opaque workaround. * Making the JTextField opaque on Nimbus makes it look very ugly */ if ("Nimbus".equalsIgnoreCase(UIManager.getLookAndFeel().getID()) && component instanceof JTextField) { component.setOpaque(false); } else { component.setOpaque(true); } component.setBackground(background); /** * GTK JTextField background workaround. * Use Borders instead of background color on GTK, as setting background color have no effect * Save the original border and set new border with the background color */ if ("GTK".equalsIgnoreCase(UIManager.getLookAndFeel().getID()) && component instanceof JTextField) { JTextField jTextField = (JTextField) component; BorderWrap borderWrap = BORDERS.get(jTextField); if (borderWrap == null) { //Original border //Save original border borderWrap = new BorderWrap(jTextField.getBorder()); BORDERS.put(jTextField, borderWrap); } //Set background color border jTextField.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createMatteBorder(4, 4, 4, 4, background), BorderFactory.createEmptyBorder(0, 7, 0, 7))); } } else { component.setOpaque(false); } if (foreground != null) { component.setForeground(foreground); } else { component.setForeground(Colors.COMPONENT_FOREGROUND.getColor()); } } public static void configReset(JTextField jTextField) { jTextField.setBackground(Colors.TEXTFIELD_BACKGROUND.getColor()); jTextField.setForeground(Colors.TEXTFIELD_FOREGROUND.getColor()); /** * GTK JTextField background workaround. * Use Borders instead of background color on GTK, as setting background color have no effect * Load the original border */ if ("GTK".equals(UIManager.getLookAndFeel().getID())) { BorderWrap borderWrap = BORDERS.get(jTextField); if (borderWrap != null) { //Restore original border (if saved) jTextField.setBorder(borderWrap.getBorder()); } } } public static void configReset(JButton jButton) { jButton.setBackground(Colors.BUTTON_BACKGROUND.getColor()); jButton.setForeground(Colors.BUTTON_FOREGROUND.getColor()); if ("Nimbus".equalsIgnoreCase(UIManager.getLookAndFeel().getID())) { jButton.setOpaque(false); } } public static void configCell(Component component, ColorEntry colorEntry, boolean selected) { configCell(component, foreground(colorEntry), background(colorEntry), selected, false); } public static void configCell(Component component, ColorEntry colorEntry, boolean selected, boolean darker) { configCell(component, foreground(colorEntry), background(colorEntry), selected, darker); } public static void configCell(Component component, Color foreground, Color background, boolean selected) { configCell(component, foreground, background, selected, false); } public static void configCell(Component component, Color foreground, Color background, boolean selected, boolean darker) { if (selected) { if (darker) { if (background != null) { component.setBackground(background.darker()); } if (foreground != null) { double luminance = ColorUtil.luminance(foreground) - 0.2; component.setForeground(ColorUtil.brighter(foreground, luminance)); } else { component.setForeground(Color.BLACK); } } else { if (background != null) { component.setBackground(Colors.TABLE_SELECTION_BACKGROUND.getColor().darker()); } else { component.setBackground(Colors.TABLE_SELECTION_BACKGROUND.getColor()); } if (foreground != null) { double luminance = ColorUtil.luminance(foreground) - 0.2; component.setForeground(ColorUtil.brighter(foreground, luminance)); } else { component.setForeground(Colors.TABLE_SELECTION_FOREGROUND.getColor()); } } } else { if (background != null) { component.setBackground(background); } if (foreground != null) { component.setForeground(foreground); } } } public static class ColorRow { private final ColorEntry colorEntry; private final Color defaultBackground; private final Color defaultForeground; private Color background; private Color foreground; public ColorRow(ColorEntry colorEntry, Color defaultBackground, Color defaultForeground, Color background, Color foreground) { this.colorEntry = colorEntry; this.background = background; this.foreground = foreground; this.defaultBackground = defaultBackground; this.defaultForeground = defaultForeground; } public ColorEntry getColorEntry() { return colorEntry; } public Color getBackground() { return background; } public Color getDefaultBackground() { return defaultBackground; } public void setBackground(Color background) { this.background = background; } public Color getDefaultForeground() { return defaultForeground; } public Color getForeground() { return foreground; } public void setForeground(Color foreground) { this.foreground = foreground; } public boolean isForegroundDefault() { return Objects.equals(foreground, defaultForeground); } public boolean isBackgroundDefault() { return Objects.equals(background, defaultBackground); } @Override public int hashCode() { int hash = 7; hash = 37 * hash + java.util.Objects.hashCode(this.colorEntry); hash = 37 * hash + java.util.Objects.hashCode(this.defaultBackground); hash = 37 * hash + java.util.Objects.hashCode(this.defaultForeground); hash = 37 * hash + java.util.Objects.hashCode(this.background); hash = 37 * hash + java.util.Objects.hashCode(this.foreground); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ColorRow other = (ColorRow) obj; if (this.colorEntry != other.colorEntry) { return false; } if (!java.util.Objects.equals(this.defaultBackground, other.defaultBackground)) { return false; } if (!java.util.Objects.equals(this.defaultForeground, other.defaultForeground)) { return false; } if (!java.util.Objects.equals(this.background, other.background)) { return false; } if (!java.util.Objects.equals(this.foreground, other.foreground)) { return false; } return true; } } /** * Wrap border. * Differentiate null border from null map value (unset) */ private static class BorderWrap { private final Border border; public BorderWrap(Border border) { this.border = border; } public Border getBorder() { return border; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/ColorTheme.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.awt.Color; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import net.nikr.eve.jeveasset.data.settings.ColorSettings.ColorRow; public abstract class ColorTheme { public static enum ColorThemeTypes { DEFAULT(new ColorThemeDefault()), STRONG(new ColorThemeStrong()), COLORBLIND(new ColorThemeColorblind()), DARK(new ColorThemeDark()), ; private final ColorTheme colorTheme; private ColorThemeTypes(ColorTheme colorTheme) { this.colorTheme = colorTheme; } public ColorTheme getInstance() { return colorTheme; } @Override public String toString() { return colorTheme.getName(); } } private Map colors = null; protected ColorTheme() { } public Map getColors() { if (colors == null) { colors = new HashMap<>(); createColors(colors); } return colors; } public boolean isValid() { for (ColorEntry entry : ColorEntry.values()) { ColorThemeEntry colorThemeEntry = getColors().get(entry); if (colorThemeEntry == null) { return false; } } return true; } public List get(boolean overwrite, List old) { Map loopup = new HashMap<>(); for (ColorRow colorRow : old) { loopup.put(colorRow.getColorEntry(), colorRow); } List rows = new ArrayList<>(); for (ColorEntry colorEntry : ColorEntry.values()) { if (!colorEntry.isBackgroundEditable() && !colorEntry.isForegroundEditable()) { continue; } ColorRow current = loopup.get(colorEntry); Color defaultBackground = getDefaultBackground(colorEntry); Color defaultForeground = getDefaultForeground(colorEntry); Color currentBackground; Color currentForeground; if (overwrite || current.isBackgroundDefault()) { currentBackground = defaultBackground; } else { currentBackground = current.getBackground(); } if (overwrite || current.isForegroundDefault()) { currentForeground = defaultForeground; } else { currentForeground = current.getForeground(); } rows.add(new ColorRow(colorEntry, defaultBackground, defaultForeground, currentBackground, currentForeground)); } return rows; } public Color getDefaultBackground(ColorEntry colorEntry) { ColorThemeEntry entry = getColors().get(colorEntry); if (entry == null) { return null; } else { return entry.getBackground(); } } public Color getDefaultForeground(ColorEntry colorEntry) { ColorThemeEntry entry = getColors().get(colorEntry); if (entry == null) { return null; } else { return entry.getForeground(); } } @Override public int hashCode() { int hash = 3; hash = 43 * hash + Objects.hashCode(this.colors); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ColorTheme other = (ColorTheme) obj; if (!Objects.equals(this.colors, other.colors)) { return false; } return true; } public boolean isDefault() { return getType() != null; } public abstract String getName(); public abstract ColorThemeTypes getType(); protected abstract void createColors(Map colors); public class ColorThemeEntry { private final Color background; private final Color foreground; public ColorThemeEntry(Colors background) { this.background = toColor(background); this.foreground = null; } public ColorThemeEntry(Colors background, Colors foreground) { this.background = toColor(background); this.foreground = toColor(foreground); } public Color getBackground() { return background; } public Color getForeground() { return foreground; } private Color toColor(Colors colors) { if (colors != null) { return colors.getColor(); } else { return null; } } @Override public int hashCode() { int hash = 7; hash = 17 * hash + Objects.hashCode(this.background); hash = 17 * hash + Objects.hashCode(this.foreground); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ColorThemeEntry other = (ColorThemeEntry) obj; if (!Objects.equals(this.background, other.background)) { return false; } if (!Objects.equals(this.foreground, other.foreground)) { return false; } return true; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/ColorThemeColorblind.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.Map; import net.nikr.eve.jeveasset.i18n.DataColors; public class ColorThemeColorblind extends ColorTheme { protected ColorThemeColorblind() {} @Override public String getName() { return DataColors.get().colorThemeColorblind(); } @Override public ColorThemeTypes getType() { return ColorThemeTypes.COLORBLIND; } @Override protected void createColors(Map colors) { colors.put(ColorEntry.ASSETS_NEW, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.ASSETS_REPROCESSING_EQUAL, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.ASSETS_REPROCESSING_REPROCES, new ColorThemeEntry(Colors.COLORBLIND_MAGENTA)); colors.put(ColorEntry.ASSETS_REPROCESSING_SELL, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.ASSETS_REPROCESS, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.CUSTOM_PRICE, new ColorThemeEntry(Colors.COLORBLIND_GRAY)); colors.put(ColorEntry.CUSTOM_ASSET_NAME, new ColorThemeEntry(Colors.COLORBLIND_GRAY)); colors.put(ColorEntry.CUSTOM_USER_LOCATION, new ColorThemeEntry(Colors.COLORBLIND_GRAY)); colors.put(ColorEntry.CONTRACTS_COURIER, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.CONTRACTS_INCLUDED, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.CONTRACTS_EXCLUDED, new ColorThemeEntry(Colors.COLORBLIND_MAGENTA)); colors.put(ColorEntry.EXTRACTIONS_DAYS, new ColorThemeEntry(Colors.COLORBLIND_MAGENTA)); colors.put(ColorEntry.EXTRACTIONS_WEEK, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.EXTRACTIONS_WEEKS, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.OVERVIEW_GROUPED_LOCATIONS, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.STOCKPILE_TABLE_BELOW_THRESHOLD, new ColorThemeEntry(Colors.COLORBLIND_MAGENTA)); colors.put(ColorEntry.STOCKPILE_ICON_BELOW_THRESHOLD, new ColorThemeEntry(Colors.COLORBLIND_MAGENTA)); colors.put(ColorEntry.STOCKPILE_TABLE_BELOW_THRESHOLD_2ND, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.STOCKPILE_ICON_BELOW_THRESHOLD_2ND, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.STOCKPILE_TABLE_OVER_THRESHOLD, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.STOCKPILE_ICON_OVER_THRESHOLD, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_NOT_BEST, new ColorThemeEntry(Colors.COLORBLIND_MAGENTA)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_NOT_BEST_OWNED, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_BEST, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_UNKNOWN, new ColorThemeEntry(Colors.COLORBLIND_GRAY)); colors.put(ColorEntry.MARKET_ORDERS_EXPIRED, new ColorThemeEntry(Colors.COLORBLIND_MAGENTA)); colors.put(ColorEntry.MARKET_ORDERS_NEAR_EXPIRED, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.MARKET_ORDERS_NEAR_FILLED, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.MARKET_ORDERS_NEW, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.INDUSTRY_JOBS_DELIVERED, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.INDUSTRY_JOBS_DONE, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_MANUFACTURING, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_TECHNOLOGY, new ColorThemeEntry(Colors.COLORBLIND_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_METERIAL_PRODUCTIVITY, new ColorThemeEntry(Colors.COLORBLIND_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_TIME_PRODUCTIVITY, new ColorThemeEntry(Colors.COLORBLIND_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_COPYING, new ColorThemeEntry(Colors.COLORBLIND_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_DUPLICATING, new ColorThemeEntry(Colors.COLORBLIND_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_REVERSE_ENGINEERING, new ColorThemeEntry(Colors.COLORBLIND_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_REVERSE_INVENTION, new ColorThemeEntry(Colors.COLORBLIND_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_REACTIONS, new ColorThemeEntry(Colors.COLORBLIND_GREEN)); colors.put(ColorEntry.INDUSTRY_SLOTS_FREE, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.INDUSTRY_SLOTS_DONE, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.INDUSTRY_SLOTS_FULL, new ColorThemeEntry(Colors.COLORBLIND_MAGENTA)); colors.put(ColorEntry.JOURNAL_NEW, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.TRANSACTIONS_BOUGHT, new ColorThemeEntry(Colors.COLORBLIND_MAGENTA)); colors.put(ColorEntry.TRANSACTIONS_SOLD, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.TRANSACTIONS_NEW, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.NPC_STANDING_NEGATIVE, new ColorThemeEntry(Colors.COLORBLIND_MAGENTA)); colors.put(ColorEntry.NPC_STANDING_POSITIVE, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.NPC_STANDING_NEGATIVE_MIDDLE, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.NPC_STANDING_POSITIVE_MIDDLE, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.GLOBAL_BPC, new ColorThemeEntry(Colors.COLORBLIND_MAGENTA)); colors.put(ColorEntry.GLOBAL_BPO, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.GLOBAL_VALUE_NEGATIVE, new ColorThemeEntry(null, Colors.COLORBLIND_FOREGROUND_RED)); colors.put(ColorEntry.GLOBAL_VALUE_POSITIVE, new ColorThemeEntry(null, Colors.COLORBLIND_FOREGROUND_GREEN)); colors.put(ColorEntry.GLOBAL_ENTRY_INVALID, new ColorThemeEntry(Colors.COLORBLIND_MAGENTA)); colors.put(ColorEntry.GLOBAL_ENTRY_WARNING, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.GLOBAL_ENTRY_VALID, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.GLOBAL_GRAND_TOTAL, new ColorThemeEntry(Colors.COLORBLIND_GRAY)); colors.put(ColorEntry.GLOBAL_SELECTED_ROW_HIGHLIGHTING, new ColorThemeEntry(Colors.COLORBLIND_BLUE)); colors.put(ColorEntry.FILTER_OR_GROUP_1, new ColorThemeEntry(Colors.COLORBLIND_GRAY)); colors.put(ColorEntry.FILTER_OR_GROUP_2, new ColorThemeEntry(Colors.COLORBLIND_MAGENTA)); colors.put(ColorEntry.FILTER_OR_GROUP_3, new ColorThemeEntry(Colors.COLORBLIND_GREEN)); colors.put(ColorEntry.FILTER_OR_GROUP_4, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.FILTER_OR_GROUP_5, new ColorThemeEntry(Colors.COLORBLIND_BLUE)); colors.put(ColorEntry.FILTER_OR_GROUP_6, new ColorThemeEntry(Colors.COLORBLIND_ORANGE)); colors.put(ColorEntry.FILTER_OR_GROUP_7, new ColorThemeEntry(Colors.COLORBLIND_GRAY)); colors.put(ColorEntry.REPROCESSED_SELL, new ColorThemeEntry(Colors.COLORBLIND_YELLOW)); colors.put(ColorEntry.REPROCESSED_REPROCESS, new ColorThemeEntry(Colors.COLORBLIND_MAGENTA)); colors.put(ColorEntry.REPROCESSED_EQUAL, new ColorThemeEntry(Colors.COLORBLIND_GRAY)); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/ColorThemeDark.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.Map; import net.nikr.eve.jeveasset.i18n.DataColors; public class ColorThemeDark extends ColorTheme { protected ColorThemeDark() { } @Override public String getName() { return DataColors.get().colorThemeDark(); } @Override public ColorThemeTypes getType() { return ColorThemeTypes.DARK; } @Override protected void createColors(Map colors) { colors.put(ColorEntry.ASSETS_NEW, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.ASSETS_REPROCESSING_EQUAL, new ColorThemeEntry(Colors.DARK_YELLOW)); colors.put(ColorEntry.ASSETS_REPROCESSING_REPROCES, new ColorThemeEntry(Colors.DARK_RED)); colors.put(ColorEntry.ASSETS_REPROCESSING_SELL, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.ASSETS_REPROCESS, new ColorThemeEntry(Colors.DARK_YELLOW)); colors.put(ColorEntry.CUSTOM_PRICE, new ColorThemeEntry(Colors.DARK_GRAY)); colors.put(ColorEntry.CUSTOM_ASSET_NAME, new ColorThemeEntry(Colors.DARK_GRAY)); colors.put(ColorEntry.CUSTOM_USER_LOCATION, new ColorThemeEntry(Colors.DARK_GRAY)); colors.put(ColorEntry.CONTRACTS_COURIER, new ColorThemeEntry(Colors.DARK_YELLOW)); colors.put(ColorEntry.CONTRACTS_INCLUDED, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.CONTRACTS_EXCLUDED, new ColorThemeEntry(Colors.DARK_RED)); colors.put(ColorEntry.EXTRACTIONS_DAYS, new ColorThemeEntry(Colors.DARK_RED)); colors.put(ColorEntry.EXTRACTIONS_WEEK, new ColorThemeEntry(Colors.DARK_YELLOW)); colors.put(ColorEntry.EXTRACTIONS_WEEKS, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.OVERVIEW_GROUPED_LOCATIONS, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.STOCKPILE_TABLE_BELOW_THRESHOLD, new ColorThemeEntry(Colors.DARK_RED)); colors.put(ColorEntry.STOCKPILE_ICON_BELOW_THRESHOLD, new ColorThemeEntry(Colors.LIGHT_RED)); colors.put(ColorEntry.STOCKPILE_TABLE_BELOW_THRESHOLD_2ND, new ColorThemeEntry(Colors.DARK_YELLOW)); colors.put(ColorEntry.STOCKPILE_ICON_BELOW_THRESHOLD_2ND, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.STOCKPILE_TABLE_OVER_THRESHOLD, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.STOCKPILE_ICON_OVER_THRESHOLD, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_NOT_BEST, new ColorThemeEntry(Colors.DARK_RED)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_NOT_BEST_OWNED, new ColorThemeEntry(Colors.DARK_ORANGE)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_BEST, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_UNKNOWN, new ColorThemeEntry(Colors.DARK_GRAY)); colors.put(ColorEntry.MARKET_ORDERS_EXPIRED, new ColorThemeEntry(Colors.DARK_RED)); colors.put(ColorEntry.MARKET_ORDERS_NEAR_EXPIRED, new ColorThemeEntry(Colors.DARK_YELLOW)); colors.put(ColorEntry.MARKET_ORDERS_NEAR_FILLED, new ColorThemeEntry(Colors.DARK_YELLOW)); colors.put(ColorEntry.MARKET_ORDERS_NEW, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.INDUSTRY_JOBS_DELIVERED, new ColorThemeEntry(Colors.DARK_YELLOW)); colors.put(ColorEntry.INDUSTRY_JOBS_DONE, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_MANUFACTURING, new ColorThemeEntry(Colors.DARK_ORANGE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_TECHNOLOGY, new ColorThemeEntry(Colors.DARK_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_METERIAL_PRODUCTIVITY, new ColorThemeEntry(Colors.DARK_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_TIME_PRODUCTIVITY, new ColorThemeEntry(Colors.DARK_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_COPYING, new ColorThemeEntry(Colors.DARK_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_DUPLICATING, new ColorThemeEntry(Colors.DARK_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_REVERSE_ENGINEERING, new ColorThemeEntry(Colors.DARK_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_REVERSE_INVENTION, new ColorThemeEntry(Colors.DARK_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_REACTIONS, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.INDUSTRY_SLOTS_FREE, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.INDUSTRY_SLOTS_DONE, new ColorThemeEntry(Colors.DARK_YELLOW)); colors.put(ColorEntry.INDUSTRY_SLOTS_FULL, new ColorThemeEntry(Colors.DARK_RED)); colors.put(ColorEntry.JOURNAL_NEW, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.TRANSACTIONS_BOUGHT, new ColorThemeEntry(Colors.DARK_RED)); colors.put(ColorEntry.TRANSACTIONS_SOLD, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.TRANSACTIONS_NEW, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.NPC_STANDING_NEGATIVE, new ColorThemeEntry(Colors.DARK_RED)); colors.put(ColorEntry.NPC_STANDING_POSITIVE, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.NPC_STANDING_NEGATIVE_MIDDLE, new ColorThemeEntry(Colors.DARK_YELLOW)); colors.put(ColorEntry.NPC_STANDING_POSITIVE_MIDDLE, new ColorThemeEntry(Colors.DARK_YELLOW)); colors.put(ColorEntry.GLOBAL_BPC, new ColorThemeEntry(Colors.DARK_MAGENTA)); colors.put(ColorEntry.GLOBAL_BPO, new ColorThemeEntry(Colors.DARK_YELLOW)); colors.put(ColorEntry.GLOBAL_VALUE_NEGATIVE, new ColorThemeEntry(null, Colors.DARK_FOREGROUND_RED)); colors.put(ColorEntry.GLOBAL_VALUE_POSITIVE, new ColorThemeEntry(null, Colors.DARK_FOREGROUND_GREEN)); colors.put(ColorEntry.GLOBAL_ENTRY_INVALID, new ColorThemeEntry(Colors.DARK_RED)); colors.put(ColorEntry.GLOBAL_ENTRY_WARNING, new ColorThemeEntry(Colors.DARK_YELLOW)); colors.put(ColorEntry.GLOBAL_ENTRY_VALID, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.GLOBAL_GRAND_TOTAL, new ColorThemeEntry(Colors.DARK_GRAY)); colors.put(ColorEntry.GLOBAL_SELECTED_ROW_HIGHLIGHTING, new ColorThemeEntry(Colors.DARK_BLUE)); colors.put(ColorEntry.FILTER_OR_GROUP_1, new ColorThemeEntry(Colors.DARK_GRAY)); colors.put(ColorEntry.FILTER_OR_GROUP_2, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.FILTER_OR_GROUP_3, new ColorThemeEntry(Colors.DARK_YELLOW)); colors.put(ColorEntry.FILTER_OR_GROUP_4, new ColorThemeEntry(Colors.DARK_ORANGE)); colors.put(ColorEntry.FILTER_OR_GROUP_5, new ColorThemeEntry(Colors.DARK_RED)); colors.put(ColorEntry.FILTER_OR_GROUP_6, new ColorThemeEntry(Colors.DARK_MAGENTA)); colors.put(ColorEntry.FILTER_OR_GROUP_7, new ColorThemeEntry(Colors.DARK_BLUE)); colors.put(ColorEntry.REPROCESSED_SELL, new ColorThemeEntry(Colors.DARK_GREEN)); colors.put(ColorEntry.REPROCESSED_REPROCESS, new ColorThemeEntry(Colors.DARK_RED)); colors.put(ColorEntry.REPROCESSED_EQUAL, new ColorThemeEntry(Colors.DARK_GRAY)); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/ColorThemeDefault.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.Map; import net.nikr.eve.jeveasset.i18n.DataColors; public class ColorThemeDefault extends ColorTheme { protected ColorThemeDefault() { } @Override public String getName() { return DataColors.get().colorThemeDefault(); } @Override public ColorThemeTypes getType() { return ColorThemeTypes.DEFAULT; } @Override protected void createColors(Map colors) { colors.put(ColorEntry.ASSETS_NEW, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.ASSETS_REPROCESSING_EQUAL, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.ASSETS_REPROCESSING_REPROCES, new ColorThemeEntry(Colors.LIGHT_RED)); colors.put(ColorEntry.ASSETS_REPROCESSING_SELL, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.ASSETS_REPROCESS, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.CUSTOM_PRICE, new ColorThemeEntry(Colors.LIGHT_GRAY)); colors.put(ColorEntry.CUSTOM_ASSET_NAME, new ColorThemeEntry(Colors.LIGHT_GRAY)); colors.put(ColorEntry.CUSTOM_USER_LOCATION, new ColorThemeEntry(Colors.LIGHT_GRAY)); colors.put(ColorEntry.CONTRACTS_COURIER, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.CONTRACTS_INCLUDED, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.CONTRACTS_EXCLUDED, new ColorThemeEntry(Colors.LIGHT_RED)); colors.put(ColorEntry.EXTRACTIONS_DAYS, new ColorThemeEntry(Colors.LIGHT_RED)); colors.put(ColorEntry.EXTRACTIONS_WEEK, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.EXTRACTIONS_WEEKS, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.OVERVIEW_GROUPED_LOCATIONS, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.STOCKPILE_TABLE_BELOW_THRESHOLD, new ColorThemeEntry(Colors.LIGHT_RED)); colors.put(ColorEntry.STOCKPILE_ICON_BELOW_THRESHOLD, new ColorThemeEntry(Colors.LIGHT_RED)); colors.put(ColorEntry.STOCKPILE_TABLE_BELOW_THRESHOLD_2ND, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.STOCKPILE_ICON_BELOW_THRESHOLD_2ND, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.STOCKPILE_TABLE_OVER_THRESHOLD, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.STOCKPILE_ICON_OVER_THRESHOLD, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_NOT_BEST, new ColorThemeEntry(Colors.LIGHT_RED)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_NOT_BEST_OWNED, new ColorThemeEntry(Colors.LIGHT_ORANGE)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_BEST, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_UNKNOWN, new ColorThemeEntry(Colors.LIGHT_GRAY)); colors.put(ColorEntry.MARKET_ORDERS_EXPIRED, new ColorThemeEntry(Colors.LIGHT_RED)); colors.put(ColorEntry.MARKET_ORDERS_NEAR_EXPIRED, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.MARKET_ORDERS_NEAR_FILLED, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.MARKET_ORDERS_NEW, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.INDUSTRY_JOBS_DELIVERED, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.INDUSTRY_JOBS_DONE, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_MANUFACTURING, new ColorThemeEntry(Colors.LIGHT_ORANGE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_TECHNOLOGY, new ColorThemeEntry(Colors.LIGHT_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_METERIAL_PRODUCTIVITY, new ColorThemeEntry(Colors.LIGHT_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_TIME_PRODUCTIVITY, new ColorThemeEntry(Colors.LIGHT_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_COPYING, new ColorThemeEntry(Colors.LIGHT_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_DUPLICATING, new ColorThemeEntry(Colors.LIGHT_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_REVERSE_ENGINEERING, new ColorThemeEntry(Colors.LIGHT_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_REVERSE_INVENTION, new ColorThemeEntry(Colors.LIGHT_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_REACTIONS, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.INDUSTRY_SLOTS_FREE, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.INDUSTRY_SLOTS_DONE, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.INDUSTRY_SLOTS_FULL, new ColorThemeEntry(Colors.LIGHT_RED)); colors.put(ColorEntry.JOURNAL_NEW, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.TRANSACTIONS_BOUGHT, new ColorThemeEntry(Colors.LIGHT_RED)); colors.put(ColorEntry.TRANSACTIONS_SOLD, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.TRANSACTIONS_NEW, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.NPC_STANDING_NEGATIVE, new ColorThemeEntry(Colors.LIGHT_RED)); colors.put(ColorEntry.NPC_STANDING_POSITIVE, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.NPC_STANDING_NEGATIVE_MIDDLE, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.NPC_STANDING_POSITIVE_MIDDLE, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.GLOBAL_BPC, new ColorThemeEntry(Colors.LIGHT_MAGENTA)); colors.put(ColorEntry.GLOBAL_BPO, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.GLOBAL_VALUE_NEGATIVE, new ColorThemeEntry(null, Colors.FOREGROUND_RED)); colors.put(ColorEntry.GLOBAL_VALUE_POSITIVE, new ColorThemeEntry(null, Colors.FOREGROUND_GREEN)); colors.put(ColorEntry.GLOBAL_ENTRY_INVALID, new ColorThemeEntry(Colors.LIGHT_RED)); colors.put(ColorEntry.GLOBAL_ENTRY_WARNING, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.GLOBAL_ENTRY_VALID, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.GLOBAL_GRAND_TOTAL, new ColorThemeEntry(Colors.LIGHT_GRAY)); colors.put(ColorEntry.GLOBAL_SELECTED_ROW_HIGHLIGHTING, new ColorThemeEntry(Colors.LIGHT_BLUE)); colors.put(ColorEntry.FILTER_OR_GROUP_1, new ColorThemeEntry(Colors.LIGHT_GRAY)); colors.put(ColorEntry.FILTER_OR_GROUP_2, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.FILTER_OR_GROUP_3, new ColorThemeEntry(Colors.LIGHT_YELLOW)); colors.put(ColorEntry.FILTER_OR_GROUP_4, new ColorThemeEntry(Colors.LIGHT_ORANGE)); colors.put(ColorEntry.FILTER_OR_GROUP_5, new ColorThemeEntry(Colors.LIGHT_RED)); colors.put(ColorEntry.FILTER_OR_GROUP_6, new ColorThemeEntry(Colors.LIGHT_MAGENTA)); colors.put(ColorEntry.FILTER_OR_GROUP_7, new ColorThemeEntry(Colors.LIGHT_BLUE)); colors.put(ColorEntry.REPROCESSED_SELL, new ColorThemeEntry(Colors.LIGHT_GREEN)); colors.put(ColorEntry.REPROCESSED_REPROCESS, new ColorThemeEntry(Colors.LIGHT_RED)); colors.put(ColorEntry.REPROCESSED_EQUAL, new ColorThemeEntry(Colors.LIGHT_GRAY)); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/ColorThemeStrong.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.Map; import net.nikr.eve.jeveasset.i18n.DataColors; public class ColorThemeStrong extends ColorTheme { protected ColorThemeStrong() {} @Override public String getName() { return DataColors.get().colorThemeStrong(); } @Override public ColorThemeTypes getType() { return ColorThemeTypes.STRONG; } @Override protected void createColors(Map colors) { colors.put(ColorEntry.ASSETS_NEW, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.ASSETS_REPROCESSING_EQUAL, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.ASSETS_REPROCESSING_REPROCES, new ColorThemeEntry(Colors.STRONG_RED)); colors.put(ColorEntry.ASSETS_REPROCESSING_SELL, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.ASSETS_REPROCESS, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.CUSTOM_PRICE, new ColorThemeEntry(Colors.STRONG_GRAY)); colors.put(ColorEntry.CUSTOM_ASSET_NAME, new ColorThemeEntry(Colors.STRONG_GRAY)); colors.put(ColorEntry.CUSTOM_USER_LOCATION, new ColorThemeEntry(Colors.STRONG_GRAY)); colors.put(ColorEntry.CONTRACTS_COURIER, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.CONTRACTS_INCLUDED, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.CONTRACTS_EXCLUDED, new ColorThemeEntry(Colors.STRONG_RED)); colors.put(ColorEntry.EXTRACTIONS_DAYS, new ColorThemeEntry(Colors.STRONG_RED)); colors.put(ColorEntry.EXTRACTIONS_WEEK, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.EXTRACTIONS_WEEKS, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.OVERVIEW_GROUPED_LOCATIONS, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.STOCKPILE_TABLE_BELOW_THRESHOLD, new ColorThemeEntry(Colors.STRONG_RED)); colors.put(ColorEntry.STOCKPILE_ICON_BELOW_THRESHOLD, new ColorThemeEntry(Colors.STRONG_RED)); colors.put(ColorEntry.STOCKPILE_TABLE_BELOW_THRESHOLD_2ND, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.STOCKPILE_ICON_BELOW_THRESHOLD_2ND, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.STOCKPILE_TABLE_OVER_THRESHOLD, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.STOCKPILE_ICON_OVER_THRESHOLD, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_NOT_BEST, new ColorThemeEntry(Colors.STRONG_RED)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_NOT_BEST_OWNED, new ColorThemeEntry(Colors.STRONG_ORANGE)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_BEST, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.MARKET_ORDERS_OUTBID_UNKNOWN, new ColorThemeEntry(Colors.STRONG_GRAY)); colors.put(ColorEntry.MARKET_ORDERS_EXPIRED, new ColorThemeEntry(Colors.STRONG_RED)); colors.put(ColorEntry.MARKET_ORDERS_NEAR_EXPIRED, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.MARKET_ORDERS_NEAR_FILLED, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.MARKET_ORDERS_NEW, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.INDUSTRY_JOBS_DELIVERED, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.INDUSTRY_JOBS_DONE, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_MANUFACTURING, new ColorThemeEntry(Colors.STRONG_ORANGE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_TECHNOLOGY, new ColorThemeEntry(Colors.STRONG_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_METERIAL_PRODUCTIVITY, new ColorThemeEntry(Colors.STRONG_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_TIME_PRODUCTIVITY, new ColorThemeEntry(Colors.STRONG_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_COPYING, new ColorThemeEntry(Colors.STRONG_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_DUPLICATING, new ColorThemeEntry(Colors.STRONG_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_REVERSE_ENGINEERING, new ColorThemeEntry(Colors.STRONG_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_REVERSE_INVENTION, new ColorThemeEntry(Colors.STRONG_BLUE)); colors.put(ColorEntry.INDUSTRY_JOBS_ACTIVITY_REACTIONS, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.INDUSTRY_SLOTS_FREE, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.INDUSTRY_SLOTS_DONE, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.INDUSTRY_SLOTS_FULL, new ColorThemeEntry(Colors.STRONG_RED)); colors.put(ColorEntry.JOURNAL_NEW, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.TRANSACTIONS_BOUGHT, new ColorThemeEntry(Colors.STRONG_RED)); colors.put(ColorEntry.TRANSACTIONS_SOLD, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.TRANSACTIONS_NEW, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.NPC_STANDING_NEGATIVE, new ColorThemeEntry(Colors.STRONG_RED)); colors.put(ColorEntry.NPC_STANDING_POSITIVE, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.NPC_STANDING_NEGATIVE_MIDDLE, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.NPC_STANDING_POSITIVE_MIDDLE, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.GLOBAL_BPC, new ColorThemeEntry(Colors.STRONG_MAGENTA)); colors.put(ColorEntry.GLOBAL_BPO, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.GLOBAL_VALUE_NEGATIVE, new ColorThemeEntry(null, Colors.FOREGROUND_RED)); colors.put(ColorEntry.GLOBAL_VALUE_POSITIVE, new ColorThemeEntry(null, Colors.FOREGROUND_GREEN)); colors.put(ColorEntry.GLOBAL_ENTRY_INVALID, new ColorThemeEntry(Colors.STRONG_RED)); colors.put(ColorEntry.GLOBAL_ENTRY_WARNING, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.GLOBAL_ENTRY_VALID, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.GLOBAL_GRAND_TOTAL, new ColorThemeEntry(Colors.STRONG_GRAY)); colors.put(ColorEntry.GLOBAL_SELECTED_ROW_HIGHLIGHTING, new ColorThemeEntry(Colors.STRONG_BLUE)); colors.put(ColorEntry.FILTER_OR_GROUP_1, new ColorThemeEntry(Colors.STRONG_GRAY)); colors.put(ColorEntry.FILTER_OR_GROUP_2, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.FILTER_OR_GROUP_3, new ColorThemeEntry(Colors.STRONG_YELLOW)); colors.put(ColorEntry.FILTER_OR_GROUP_4, new ColorThemeEntry(Colors.STRONG_ORANGE)); colors.put(ColorEntry.FILTER_OR_GROUP_5, new ColorThemeEntry(Colors.STRONG_RED)); colors.put(ColorEntry.FILTER_OR_GROUP_6, new ColorThemeEntry(Colors.STRONG_MAGENTA)); colors.put(ColorEntry.FILTER_OR_GROUP_7, new ColorThemeEntry(Colors.STRONG_BLUE)); colors.put(ColorEntry.REPROCESSED_SELL, new ColorThemeEntry(Colors.STRONG_GREEN)); colors.put(ColorEntry.REPROCESSED_REPROCESS, new ColorThemeEntry(Colors.STRONG_RED)); colors.put(ColorEntry.REPROCESSED_EQUAL, new ColorThemeEntry(Colors.STRONG_GRAY)); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/Colors.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.awt.Color; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.UIManager; public enum Colors { /** * 230, 230, 230 */ LIGHT_GRAY(230, 230, 230), /** * 190, 190, 190 */ STRONG_GRAY(190, 190, 190), /** * 190, 190, 190 */ COLORBLIND_GRAY(190, 190, 190), /** * 81, 81, 81 */ DARK_GRAY(81, 81, 81), /** * 255, 200, 200 */ LIGHT_RED(255, 200, 200), /** * 255, 160, 160 */ STRONG_RED(255, 160, 160), /** * Dark Red */ FOREGROUND_RED(Color.RED.darker()), /** * Dark Red */ DARK_FOREGROUND_RED(239, 143, 143), /** * 120, 45, 30 */ DARK_RED(120, 45, 30), /** * 213, 94, 0 */ COLORBLIND_FOREGROUND_RED(213, 94, 0), /** * 200, 255, 200 */ LIGHT_GREEN(200, 255, 200), /** * 160, 255, 160 */ STRONG_GREEN(160, 255, 160), /** * 0, 158, 115 */ COLORBLIND_GREEN(0, 158, 115), /** * Dark Green */ FOREGROUND_GREEN(Color.GREEN.darker()), /** * 22, 153, 0 */ DARK_FOREGROUND_GREEN(152, 229, 152), /** * 45, 67, 34 */ DARK_GREEN(45, 67, 34), /** * 0, 114, 178 (not really green, it's blue) */ COLORBLIND_FOREGROUND_GREEN(0, 114, 178), /** * 255, 255, 200 */ LIGHT_YELLOW(255, 255, 200), /** * 255, 255, 160 */ STRONG_YELLOW(255, 255, 160), /** * 255, 176, 0 */ COLORBLIND_YELLOW(240, 228, 66), /** * 132, 103, 14 */ DARK_YELLOW(132, 103, 14), /** * 220, 240, 255 */ LIGHT_BLUE(220, 240, 255), /** * 180, 220, 255 */ STRONG_BLUE(180, 220, 255), /** * 86, 106, 143 */ DARK_BLUE(86, 106, 143), /** * 100, 143, 255 */ COLORBLIND_BLUE(86, 180, 233), /** * 255, 220, 200 */ LIGHT_ORANGE(255, 220, 200), /** * 255, 180, 120 */ STRONG_ORANGE(255, 180, 120), /** * 254, 97, 0 */ COLORBLIND_ORANGE(230, 159, 0), /** * 114, 77, 38 */ DARK_ORANGE(114, 77, 38), /** * 255, 220, 255 */ LIGHT_MAGENTA(255, 220, 255), /** * 255, 180, 255 */ STRONG_MAGENTA(255, 180, 255), /** * 220, 38, 127 */ COLORBLIND_MAGENTA(204, 121, 167), /** * 77, 50, 64 */ DARK_MAGENTA(77, 50, 64), /** * Table selection background */ TABLE_SELECTION_BACKGROUND("Table.selectionBackground") { @Override public Color getComponentColor() { return new JTable().getSelectionBackground(); } }, /** * Table selection foreground */ TABLE_SELECTION_FOREGROUND("Table.selectionForeground") { @Override public Color getComponentColor() { return new JTable().getSelectionForeground(); } }, /** * TextField background */ TEXTFIELD_BACKGROUND("TextField.background") { @Override public Color getComponentColor() { return new JTextField().getBackground(); } }, /** * TextField foreground */ TEXTFIELD_FOREGROUND("TextField.foreground") { @Override public Color getComponentColor() { return new JTextField().getForeground(); } }, /** * Component background */ COMPONENT_BACKGROUND("Panel.background") { @Override public Color getComponentColor() { return new JPanel().getBackground(); } }, /** * Transparent component background */ COMPONENT_TRANSPARENT("Panel.background", 0) { @Override public Color getComponentColor() { return new JPanel().getBackground(); } }, /** * Component foreground */ COMPONENT_FOREGROUND("Panel.foreground") { @Override public Color getComponentColor() { return new JPanel().getForeground(); } }, /** * Component background */ BUTTON_BACKGROUND("Button.background") { @Override public Color getComponentColor() { return new JButton().getBackground(); } }, /** * Component foreground */ BUTTON_FOREGROUND("Button.foreground") { @Override public Color getComponentColor() { return new JButton().getForeground(); } }, ; private final Color color; private final String key; private final Integer alpha; private Colors(String key) { this(key, null); } private Colors(String key, Integer alpha) { this.color = null; this.key = key; this.alpha = alpha; } private Colors(Color color) { this.color = color; this.key = null; this.alpha = null; } private Colors(int r, int g, int b) { this.color = new Color(r, g, b); this.key = null; this.alpha = null; } public Color getColor() { if (alpha != null) { Color c = getColorWithoutAlpha(); return new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha); } else { return getColorWithoutAlpha(); } } private Color getColorWithoutAlpha() { if (color != null) { return color; } if (key != null) { Color ui = UIManager.getColor(key); if (ui != null) { return ui; } } Color component = getComponentColor(); if (component != null) { return component; } else { throw new RuntimeException(name() + " have no valid color"); } } public Color getComponentColor() { return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/CopySettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import net.nikr.eve.jeveasset.data.settings.ExportSettings.DecimalSeparator; public class CopySettings { //Copy private DecimalSeparator copyDecimalSeparator; public CopySettings() { copyDecimalSeparator = DecimalSeparator.DOT; } public DecimalSeparator getCopyDecimalSeparator() { return copyDecimalSeparator; } public void setCopyDecimalSeparator(DecimalSeparator copyDecimalSeparator) { this.copyDecimalSeparator = copyDecimalSeparator; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/DarkNimbus.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.awt.Color; import javax.swing.UIDefaults; import javax.swing.plaf.nimbus.NimbusLookAndFeel; public class DarkNimbus extends NimbusLookAndFeel { private UIDefaults defaults; @Override public UIDefaults getDefaults() { if (defaults == null) { defaults = super.getDefaults(); defaults.put("control", new Color(128, 128, 128)); defaults.put("info", new Color(128, 128, 128)); defaults.put("nimbusBase", new Color(18, 30, 49)); defaults.put("nimbusAlertYellow", new Color(248, 187, 0)); defaults.put("nimbusDisabledText", new Color(128, 128, 128)); defaults.put("nimbusFocus", new Color(115, 164, 209)); defaults.put("nimbusGreen", new Color(176, 179, 50)); defaults.put("nimbusInfoBlue", new Color(66, 139, 221)); defaults.put("nimbusLightBackground", new Color(18, 30, 49)); defaults.put("nimbusOrange", new Color(191, 98, 4)); defaults.put("nimbusRed", new Color(169, 46, 34)); defaults.put("nimbusSelectedText", new Color(255, 255, 255)); defaults.put("nimbusSelectionBackground", new Color(104, 93, 156)); defaults.put("text", new Color(230, 230, 230)); } return defaults; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/ExportSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.io.File; import java.util.ArrayList; import java.util.List; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.i18n.DialoguesExport; import net.nikr.eve.jeveasset.io.shared.FileUtil; public class ExportSettings { public enum FieldDelimiter { COMMA(',') { @Override String getI18N() { return DialoguesExport.get().comma(); } }, SEMICOLON(';') { @Override String getI18N() { return DialoguesExport.get().semicolon(); } }; private final char character; private FieldDelimiter(final char character) { this.character = character; } public char getValue() { return character; } @Override public String toString() { return getI18N(); } abstract String getI18N(); } public enum LineDelimiter { DOS("\r\n") { @Override String getI18N() { return DialoguesExport.get().lineEndingsWindows(); } }, UNIX("\n") { @Override String getI18N() { return DialoguesExport.get().lineEndingsUnix(); } }, MAC("\r") { @Override String getI18N() { return DialoguesExport.get().lineEndingsMac(); } }; private final String string; private LineDelimiter(final String string) { this.string = string; } public String getValue() { return string; } @Override public String toString() { return getI18N(); } abstract String getI18N(); } public enum DecimalSeparator { DOT(FieldDelimiter.COMMA) { @Override String getI18N() { return DialoguesExport.get().dot(); } }, COMMA(FieldDelimiter.SEMICOLON) { @Override String getI18N() { return DialoguesExport.get().comma(); } }; private final FieldDelimiter fieldDelimiter; private DecimalSeparator(FieldDelimiter fieldDelimiter) { this.fieldDelimiter = fieldDelimiter; } @Override public String toString() { return getI18N(); } public FieldDelimiter getFieldDelimiter() { return fieldDelimiter; } abstract String getI18N(); } public enum ExportFormat { CSV("csv"), SQL("sql"), HTML("html"); private final String extension; private ExportFormat(String extension) { this.extension = extension; } public String getExtension() { return extension; } } /*** * Enum that contains the options for column selection in column jcombobox. */ public enum ColumnSelection { SHOWN("shown"), SAVED("saved"), SELECTED("selected"); private final String selection; private ColumnSelection(String selection) { this.selection = selection; } public String getSelection() { return selection; } } /*** * Enum that contains the options for filter selection in filter jcombobox. */ public enum FilterSelection { NONE("none"), CURRENT("current"), SAVED("saved"); private final String selection; private FilterSelection(String selection) { this.selection = selection; } public String getSelection() { return selection; } } private static final String PATH = FileUtil.getUserDirectory(); //Common private final String toolName; private final List tableExportColumns = new ArrayList<>(); private String fileName; private ExportFormat exportFormat; private FilterSelection filterSelection; private ColumnSelection columnSelection; private String filterName; private String viewName; private DecimalSeparator decimalSeparator; //CLI private boolean formulas; private boolean jumps; //CSV private LineDelimiter csvLineDelimiter; //SQL private boolean sqlCreateTable; private boolean sqlDropTable; private boolean sqlExtendedInserts; private String sqlTableName; //HTML private boolean htmlStyled; private int htmlRepeatHeader; private boolean htmlIGB; public ExportSettings(String toolName) { this.toolName = toolName; fileName = ""; exportFormat = ExportFormat.CSV; filterSelection = FilterSelection.NONE; columnSelection = ColumnSelection.SHOWN; filterName = ""; viewName = ""; decimalSeparator = DecimalSeparator.DOT; //CSV & HTML formulas = false; jumps = false; csvLineDelimiter = LineDelimiter.DOS; sqlCreateTable = true; sqlDropTable = true; sqlExtendedInserts = true; sqlTableName = ""; htmlStyled = true; htmlRepeatHeader = 0; htmlIGB = false; } public boolean isCsv() { return exportFormat == ExportFormat.CSV; } public DecimalSeparator getDecimalSeparator() { return decimalSeparator; } public void setDecimalSeparator(final DecimalSeparator decimalSeparator) { this.decimalSeparator = decimalSeparator; } public FieldDelimiter getCsvFieldDelimiter() { return decimalSeparator.getFieldDelimiter(); } public LineDelimiter getCsvLineDelimiter() { return csvLineDelimiter; } public void setCsvLineDelimiter(final LineDelimiter csvLineDelimiter) { this.csvLineDelimiter = csvLineDelimiter; } public boolean isSql() { return exportFormat == ExportFormat.SQL; } public boolean isSqlCreateTable() { return sqlCreateTable; } public void setSqlCreateTable(final boolean sqlCreateTable) { this.sqlCreateTable = sqlCreateTable; } public boolean isSqlDropTable() { return sqlDropTable; } public void setSqlDropTable(final boolean sqlDropTable) { this.sqlDropTable = sqlDropTable; } public boolean isSqlExtendedInserts() { return sqlExtendedInserts; } public void setSqlExtendedInserts(final boolean sqlExtendedInserts) { this.sqlExtendedInserts = sqlExtendedInserts; } public String getSqlTableName() { if (sqlTableName.isEmpty()) { //Ensure never empty return getDefaultTableName(toolName); } return sqlTableName; } public void setSqlTableName(String sqlTableName) { this.sqlTableName = sqlTableName; } public boolean isHtml() { return exportFormat == ExportFormat.HTML; } public boolean isHtmlStyled() { return htmlStyled; } public void setHtmlStyled(boolean htmlStyled) { this.htmlStyled = htmlStyled; } public int getHtmlRepeatHeader() { return htmlRepeatHeader; } public void setHtmlRepeatHeader(int htmlRepeatHeader) { this.htmlRepeatHeader = htmlRepeatHeader; } public boolean isHtmlIGB() { return htmlIGB; } public void setHtmlIGB(boolean htmlIGB) { this.htmlIGB = htmlIGB; } public ExportFormat getExportFormat() { return exportFormat; } public void setExportFormat(ExportFormat exportFormat) { this.exportFormat = exportFormat; } public FilterSelection getFilterSelection() { return filterSelection; } public void setFilterSelection(FilterSelection filterSelection) { this.filterSelection = filterSelection; } public ColumnSelection getColumnSelection() { return columnSelection; } public void setColumnSelection(ColumnSelection columnSelection) { this.columnSelection = columnSelection; } public String getFilterName() { return filterName; } public void setFilterName(String filterName) { this.filterName = filterName; } public String getViewName() { return viewName; } public void setViewName(String viewName) { this.viewName = viewName; } public boolean isFormulas() { return formulas; } public void setFormulas(boolean formulas) { this.formulas = formulas; } public boolean isJumps() { return jumps; } public void setJumps(boolean jumps) { this.jumps = jumps; } public String getFilename() { if(this.fileName != null && !this.fileName.isEmpty()) { return this.fileName; } return getDefaultFilename(); } public String getPath() { String pathname = getFilename(); int end = pathname.lastIndexOf(File.separator); if (end >= 0) { return pathname.substring(0, end + 1); } else { return getDefaultPath(); } } public void setFilename(final String fileName) { this.fileName = fileName; } public List getTableExportColumns() { return tableExportColumns; } public void putTableExportColumns(final List selectedColumns) { tableExportColumns.clear(); if (selectedColumns != null) { tableExportColumns.addAll(selectedColumns); } } public String getDefaultPath() { return PATH; } public String getDefaultFilename() { return PATH + this.toolName + "_export." + exportFormat.getExtension(); } public static String getDefaultTableName(String toolName) { return Program.PROGRAM_NAME.toLowerCase() + "_" + toolName.toLowerCase(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/ManufacturingSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import static net.nikr.eve.jeveasset.data.settings.Settings.getNow; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class ManufacturingSettings { public static enum ManufacturingFacility { STATION(0,0) { @Override public String getText() { return DialoguesSettings.get().manufacturingFacilityStation(); } }, ENGINEERING_COMPLEX_MEDIUM(1, 3){ @Override public String getText() { return DialoguesSettings.get().manufacturingFacilityMedium(); } }, ENGINEERING_COMPLEX_LARGE(1, 4){ @Override public String getText() { return DialoguesSettings.get().manufacturingFacilityLarge(); } }, ENGINEERING_COMPLEX_XLARGE(1, 5){ @Override public String getText() { return DialoguesSettings.get().manufacturingFacilityXLarge(); } }; private final double materialBonus; private final double feeBonus; private ManufacturingFacility(double materialBonus, double feeBonus) { this.materialBonus = materialBonus; this.feeBonus = feeBonus; } public abstract String getText(); @Override public String toString() { return getText(); } public double getMaterialBonus() { return materialBonus; } public double getFeeBonus() { return feeBonus; } public static ManufacturingFacility getDefault() { return ENGINEERING_COMPLEX_MEDIUM; } } public static enum ManufacturingRigs { NONE(0) { @Override public String getText() { return DialoguesSettings.get().manufacturingRigsNone(); } }, T1(2.0) { @Override public String getText() { return DialoguesSettings.get().manufacturingRigsT1(); } }, T2(2.40) { @Override public String getText() { return DialoguesSettings.get().manufacturingRigsT2(); } }; private final double materialBonus; private ManufacturingRigs(double materialBonus) { this.materialBonus = materialBonus; } public abstract String getText(); @Override public String toString() { return getText(); //return getText() + " (" + materialBonus + "%)"; } public double getMaterialBonus() { return materialBonus; } public static ManufacturingRigs getDefault() { return NONE; } } public static enum ReactionRigs { NONE(0) { @Override public String getText() { return DialoguesSettings.get().manufacturingRigsNone(); } }, T1(2.0) { @Override public String getText() { return DialoguesSettings.get().manufacturingRigsT1(); } }, T2(2.40) { @Override public String getText() { return DialoguesSettings.get().manufacturingRigsT2(); } }; private final double materialBonus; private ReactionRigs(double materialBonus) { this.materialBonus = materialBonus; } public abstract String getText(); @Override public String toString() { return getText(); //return getText() + " (" + materialBonus + "%)"; } public double getMaterialBonus() { return materialBonus; } public static ReactionRigs getDefault() { return NONE; } } public static enum ManufacturingSecurity { HIGHSEC(1) { @Override public String getText() { return DialoguesSettings.get().manufacturingSecurityHighSec(); } }, LOWSEC(1.9) { @Override public String getText() { return DialoguesSettings.get().manufacturingSecurityLowSec(); } }, NULLSEC(2.1) { @Override public String getText() { return DialoguesSettings.get().manufacturingSecurityNullSec(); } }; private final double rigBonus; private ManufacturingSecurity(double rigBonus) { this.rigBonus = rigBonus; } public abstract String getText(); public double getRigBonus() { return rigBonus; } @Override public String toString() { return getText(); //return getText() + " (" + rigBonus + "%)"; } public static ManufacturingSecurity getDefault() { return HIGHSEC; } } public static enum ReactionSecurity { LOWSEC(1.0) { @Override public String getText() { return DialoguesSettings.get().manufacturingSecurityLowSec(); } }, NULLSEC(1.1) { @Override public String getText() { return DialoguesSettings.get().manufacturingSecurityNullSec(); } }; private final double rigBonus; private ReactionSecurity(double rigBonus) { this.rigBonus = rigBonus; } public abstract String getText(); public double getRigBonus() { return rigBonus; } @Override public String toString() { return getText(); //return getText() + " (" + rigBonus + "%)"; } public static ReactionSecurity getDefault() { return LOWSEC; } } private Map prices = new HashMap<>(); //Adjusted Prices private Map systems = new HashMap<>(); //System Indexs private Date nextUpdate = getNow(); //Defaults private int systemID = 30000142; //Jita for now private int materialEfficiency = 0; private ManufacturingFacility facility = ManufacturingFacility.getDefault(); private ManufacturingRigs rigs = ManufacturingRigs.getDefault(); private ManufacturingSecurity security = ManufacturingSecurity.getDefault(); private double tax = 0; public Map getPrices() { return prices; } public void setPrices(Map prices) { this.prices = prices; } public Map getSystems() { return systems; } public void setSystems(Map systems) { this.systems = systems; } public Date getNextUpdate() { return nextUpdate; } public boolean isSystemsNeedsUpdating() { return systems.isEmpty() || Settings.getNow().after(new Date(nextUpdate.getTime() + TimeUnit.HOURS.toMillis(23))); //Last updated 1 day ago } public void setNextUpdate(Date nextUpdate) { this.nextUpdate = nextUpdate; } public int getSystemID() { return systemID; } public void setSystemID(int systemID) { this.systemID = systemID; } public int getMaterialEfficiency() { return materialEfficiency; } public void setMaterialEfficiency(int materialEfficiency) { this.materialEfficiency = materialEfficiency; } public ManufacturingFacility getFacility() { return facility; } public void setFacility(ManufacturingFacility facility) { this.facility = facility; } public ManufacturingRigs getRigs() { return rigs; } public void setRigs(ManufacturingRigs rigs) { this.rigs = rigs; } public ManufacturingSecurity getSecurity() { return security; } public void setSecurity(ManufacturingSecurity security) { this.security = security; } public double getTax() { return tax; } public void setTax(double tax) { this.tax = tax; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/MarketOrdersSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; public class MarketOrdersSettings { private int expireWarnDays = 1; //Default, one day private int remainingWarnPercent = 10; //Default, 10 percent public MarketOrdersSettings() { } public int getExpireWarnDays() { return expireWarnDays; } public void setExpireWarnDays(int expireWarnDays) { this.expireWarnDays = expireWarnDays; } public int getRemainingWarnPercent() { return remainingWarnPercent; } public void setRemainingWarnPercent(int remainingWarnPercent) { this.remainingWarnPercent = remainingWarnPercent; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/MarketPriceData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.Date; public class MarketPriceData { private Date latestDate = null; private double latest = 0; private double maximum = 0; private double minimum = -1; private double total = 0; private double count = 0; public MarketPriceData() { } public void update(final double price, final double count, final Date date) { //Max if (price > maximum) { this.maximum = price; } //Min if (price < minimum || minimum < 0) { this.minimum = price; } //Average this.total = total + (price * count); this.count = this.count + count; //Latest if (latestDate == null || latestDate.before(date)) { latest = price; latestDate = date; } } public double getLatest() { return latest; } public double getMaximum() { return maximum; } public double getMinimum() { if (minimum < 0) { return 0; } else { return minimum; } } public double getAverage() { if (total > 0 && count > 0) { return total / count; } else { return 0; } } public static double getAverage(MarketPriceData buy, MarketPriceData sell) { double total = buy.total + sell.total; double count = buy.count + sell.count; if (total > 0 && count > 0) { return total / count; } else { return 0; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/PriceData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; public class PriceData { public static PriceData EMPTY = new PriceData(); private double sellMax = 0; private double sellAvg = 0; private double sellMedian = 0; private double sellPercentile = 0; private double sellMin = 0; private double buyMax = 0; private double buyAvg = 0; private double buyMedian = 0; private double buyPercentile = 0; private double buyMin = 0; public PriceData() { } public double getBuyAvg() { return buyAvg; } public void setBuyAvg(final double buyAvg) { this.buyAvg = buyAvg; } public double getBuyMax() { return buyMax; } public void setBuyMax(final double buyMax) { this.buyMax = buyMax; } public double getBuyMedian() { return buyMedian; } public void setBuyMedian(final double buyMedian) { this.buyMedian = buyMedian; } public double getBuyMin() { return buyMin; } public void setBuyMin(final double buyMin) { this.buyMin = buyMin; } public double getSellAvg() { return sellAvg; } public void setSellAvg(final double sellAvg) { this.sellAvg = sellAvg; } public double getSellMax() { return sellMax; } public void setSellMax(final double sellMax) { this.sellMax = sellMax; } public double getSellMedian() { return sellMedian; } public void setSellMedian(final double sellMedian) { this.sellMedian = sellMedian; } public double getSellMin() { return sellMin; } public double getBuyPercentile() { return buyPercentile; } public void setBuyPercentile(final double buyPercentile) { this.buyPercentile = buyPercentile; } public double getSellPercentile() { return sellPercentile; } public void setSellPercentile(final double sellPercentile) { this.sellPercentile = sellPercentile; } public void setSellMin(final double sellMin) { this.sellMin = sellMin; } public boolean isEmpty() { return !(sellMax > 0 || sellAvg > 0 || sellMedian > 0 || sellPercentile > 0 || sellMin > 0 || buyMax > 0 || buyAvg > 0 || buyMedian > 0 || buyPercentile > 0 || buyMin > 0 ); } @Override public String toString() { return "sellMax : " + sellMax + " sellAvg: " + sellAvg + " sellMedian: " + sellMedian + " sellPercentile: " + sellPercentile + " sellMin: " + sellMin + " buyMax: " + buyMax + " buyAvg: " + buyAvg + " buyMedian: " + buyMedian + " buyPercentile: " + buyPercentile + " buyMin: " + buyMin; } @Override public int hashCode() { int hash = 7; hash = 37 * hash + (int) (Double.doubleToLongBits(this.sellMax) ^ (Double.doubleToLongBits(this.sellMax) >>> 32)); hash = 37 * hash + (int) (Double.doubleToLongBits(this.sellAvg) ^ (Double.doubleToLongBits(this.sellAvg) >>> 32)); hash = 37 * hash + (int) (Double.doubleToLongBits(this.sellMedian) ^ (Double.doubleToLongBits(this.sellMedian) >>> 32)); hash = 37 * hash + (int) (Double.doubleToLongBits(this.sellPercentile) ^ (Double.doubleToLongBits(this.sellPercentile) >>> 32)); hash = 37 * hash + (int) (Double.doubleToLongBits(this.sellMin) ^ (Double.doubleToLongBits(this.sellMin) >>> 32)); hash = 37 * hash + (int) (Double.doubleToLongBits(this.buyMax) ^ (Double.doubleToLongBits(this.buyMax) >>> 32)); hash = 37 * hash + (int) (Double.doubleToLongBits(this.buyAvg) ^ (Double.doubleToLongBits(this.buyAvg) >>> 32)); hash = 37 * hash + (int) (Double.doubleToLongBits(this.buyMedian) ^ (Double.doubleToLongBits(this.buyMedian) >>> 32)); hash = 37 * hash + (int) (Double.doubleToLongBits(this.buyPercentile) ^ (Double.doubleToLongBits(this.buyPercentile) >>> 32)); hash = 37 * hash + (int) (Double.doubleToLongBits(this.buyMin) ^ (Double.doubleToLongBits(this.buyMin) >>> 32)); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final PriceData other = (PriceData) obj; if (Double.doubleToLongBits(this.sellMax) != Double.doubleToLongBits(other.sellMax)) { return false; } if (Double.doubleToLongBits(this.sellAvg) != Double.doubleToLongBits(other.sellAvg)) { return false; } if (Double.doubleToLongBits(this.sellMedian) != Double.doubleToLongBits(other.sellMedian)) { return false; } if (Double.doubleToLongBits(this.sellPercentile) != Double.doubleToLongBits(other.sellPercentile)) { return false; } if (Double.doubleToLongBits(this.sellMin) != Double.doubleToLongBits(other.sellMin)) { return false; } if (Double.doubleToLongBits(this.buyMax) != Double.doubleToLongBits(other.buyMax)) { return false; } if (Double.doubleToLongBits(this.buyAvg) != Double.doubleToLongBits(other.buyAvg)) { return false; } if (Double.doubleToLongBits(this.buyMedian) != Double.doubleToLongBits(other.buyMedian)) { return false; } if (Double.doubleToLongBits(this.buyPercentile) != Double.doubleToLongBits(other.buyPercentile)) { return false; } return Double.doubleToLongBits(this.buyMin) == Double.doubleToLongBits(other.buyMin); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/PriceDataSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.ArrayList; import java.util.List; import java.util.Objects; import javax.swing.Icon; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.i18n.DataModelPriceDataSettings; import uk.me.candle.eve.pricing.impl.Janice.JaniceLocation; import uk.me.candle.eve.pricing.options.LocationType; import uk.me.candle.eve.pricing.options.PriceType; import uk.me.candle.eve.pricing.options.PricingFetch; public class PriceDataSettings { public enum PriceSource { FUZZWORK(PricingFetch.FUZZWORK, LocationType.REGION, 10000002L, Images.LINK_FUZZWORK.getIcon()) { @Override String getI18N() { return DataModelPriceDataSettings.get().sourceFuzzwork(); } }, /* EVE_TYCOON(PricingFetch.EVE_TYCOON, LocationType.REGION, 10000002L, Images.LINK_EVE_TYCOON.getIcon()) { @Override String getI18N() { return DataModelPriceDataSettings.get().sourceEveTycoon(); } }, */ JANICE(PricingFetch.JANICE, LocationType.STATION, JaniceLocation.JITA_4_4.getPriceLocation().getLocationID(), Images.LINK_JANICE.getIcon()) { @Override String getI18N() { return DataModelPriceDataSettings.get().sourceJanice(); } }, ; private final PricingFetch pricingFetch; private final LocationType defaultLocationType; private final Long defaultLocationID; private final Icon icon; private PriceSource(final PricingFetch pricingFetch, final LocationType defaultLocationType, final Long defaultLocationID, final Icon icon) { this.pricingFetch = pricingFetch; this.defaultLocationType = defaultLocationType; this.defaultLocationID = defaultLocationID; this.icon = icon; } abstract String getI18N(); @Override public String toString() { return getI18N(); } public List getSupportedPriceModes() { List priceModes = new ArrayList<>(); for (PriceMode priceMode : PriceMode.values()) { if (pricingFetch.getSupportedPricingTypes().contains(priceMode.getPricingType())) { priceModes.add(priceMode); } else if (priceMode == PriceMode.PRICE_MIDPOINT && pricingFetch.getSupportedPricingTypes().contains(PriceType.SELL_LOW) && pricingFetch.getSupportedPricingTypes().contains(PriceType.BUY_HIGH) ) { priceModes.add(priceMode); } } return priceModes; } public LocationType getDefaultLocationType() { return defaultLocationType; } public Long getDefaultLocationID() { return defaultLocationID; } public PricingFetch getPricingFetch() { return pricingFetch; } public boolean supportRegions() { return pricingFetch.getSupportedLocationTypes().contains(LocationType.REGION); } public boolean supportStations() { return pricingFetch.getSupportedLocationTypes().contains(LocationType.STATION); } public boolean supportSystems() { return pricingFetch.getSupportedLocationTypes().contains(LocationType.SYSTEM); } public Icon getIcon() { return icon; } public boolean isValid(LocationType locationType, Long locationID) { if (null != locationType && locationID != null) { if (this == JANICE && !JaniceLocation.isValid(locationID)) { return false; } switch (locationType) { case REGION: return supportRegions(); case SYSTEM: return supportSystems(); case STATION: return supportStations(); } } return false; //Should never happen } } public enum PriceMode { PRICE_SELL_MAX(PriceType.SELL_HIGH) { @Override String getI18N() { return DataModelPriceDataSettings.get().priceSellMax(); } }, PRICE_SELL_AVG(PriceType.SELL_MEAN) { @Override String getI18N() { return DataModelPriceDataSettings.get().priceSellAvg(); } }, PRICE_SELL_MEDIAN(PriceType.SELL_MEDIAN) { @Override String getI18N() { return DataModelPriceDataSettings.get().priceSellMedian(); } }, PRICE_SELL_PERCENTILE(PriceType.SELL_PERCENTILE) { @Override String getI18N() { return DataModelPriceDataSettings.get().priceSellPercentile(); } }, PRICE_SELL_MIN(PriceType.SELL_LOW) { @Override String getI18N() { return DataModelPriceDataSettings.get().priceSellMin(); } }, PRICE_MIDPOINT(null) { @Override String getI18N() { return DataModelPriceDataSettings.get().priceMidpoint(); } }, PRICE_BUY_MAX(PriceType.BUY_HIGH) { @Override String getI18N() { return DataModelPriceDataSettings.get().priceBuyMax(); } }, PRICE_BUY_PERCENTILE(PriceType.BUY_PERCENTILE) { @Override String getI18N() { return DataModelPriceDataSettings.get().priceBuyPercentile(); } }, PRICE_BUY_AVG(PriceType.BUY_MEAN) { @Override String getI18N() { return DataModelPriceDataSettings.get().priceBuyAvg(); } }, PRICE_BUY_MEDIAN(PriceType.BUY_MEDIAN) { @Override String getI18N() { return DataModelPriceDataSettings.get().priceBuyMedian(); } }, PRICE_BUY_MIN(PriceType.BUY_LOW) { @Override String getI18N() { return DataModelPriceDataSettings.get().priceBuyMin(); } }; abstract String getI18N(); @Override public String toString() { return getI18N(); } PriceType priceType; private PriceMode(PriceType priceType) { this.priceType = priceType; } public PriceType getPricingType() { return priceType; } public static void setDefaultPrice(final PriceData priceData, final PriceMode priceMode, final double price) { if (priceData != null) { if (priceMode == PriceMode.PRICE_SELL_MAX) { priceData.setSellMax(price); } if (priceMode == PriceMode.PRICE_SELL_AVG) { priceData.setSellAvg(price); } if (priceMode == PriceMode.PRICE_SELL_MEDIAN) { priceData.setSellMedian(price); } if (priceMode == PriceMode.PRICE_SELL_PERCENTILE) { priceData.setSellPercentile(price); } if (priceMode == PriceMode.PRICE_SELL_MIN) { priceData.setSellMin(price); } if (priceMode == PriceMode.PRICE_MIDPOINT) { //Ignore calculated prices } if (priceMode == PriceMode.PRICE_BUY_MAX) { priceData.setBuyMax(price); } if (priceMode == PriceMode.PRICE_BUY_AVG) { priceData.setBuyAvg(price); } if (priceMode == PriceMode.PRICE_BUY_MEDIAN) { priceData.setBuyMedian(price); } if (priceMode == PriceMode.PRICE_BUY_PERCENTILE) { priceData.setBuyPercentile(price); } if (priceMode == PriceMode.PRICE_BUY_MIN) { priceData.setBuyMin(price); } } } public static double getDefaultPrice(final PriceData priceData, final PriceMode priceMode) { if (priceData != null) { if (priceMode == PriceMode.PRICE_SELL_MAX) { return priceData.getSellMax(); } if (priceMode == PriceMode.PRICE_SELL_AVG) { return priceData.getSellAvg(); } if (priceMode == PriceMode.PRICE_SELL_MEDIAN) { return priceData.getSellMedian(); } if (priceMode == PriceMode.PRICE_SELL_PERCENTILE) { return priceData.getSellPercentile(); } if (priceMode == PriceMode.PRICE_SELL_MIN) { return priceData.getSellMin(); } if (priceMode == PriceMode.PRICE_MIDPOINT) { if (priceData.getSellMin() > 0 && priceData.getBuyMax() > 0) { //Working as intended return (priceData.getSellMin() + priceData.getBuyMax()) / 2; } else if (priceData.getBuyMax() > 0) { //Using BuyMax (fallback) return priceData.getBuyMax(); } else { //Using SellMin (fallback) return priceData.getSellMin(); //SellMin or Zero } } if (priceMode == PriceMode.PRICE_BUY_MAX) { return priceData.getBuyMax(); } if (priceMode == PriceMode.PRICE_BUY_AVG) { return priceData.getBuyAvg(); } if (priceMode == PriceMode.PRICE_BUY_MEDIAN) { return priceData.getBuyMedian(); } if (priceMode == PriceMode.PRICE_BUY_PERCENTILE) { return priceData.getBuyPercentile(); } if (priceMode == PriceMode.PRICE_BUY_MIN) { return priceData.getBuyMin(); } } return 0; } public static PriceMode getDefaultPriceType() { return PriceMode.PRICE_MIDPOINT; } } //Default private final LocationType locationType; private final Long locationID; private final PriceSource priceSource; private PriceMode priceType; private PriceMode priceReprocessedType; private PriceMode priceManufacturingType; private String janiceKey; public PriceDataSettings() { locationType = LocationType.REGION; locationID = getDefaultLocationID(); priceSource = getDefaultPriceSource(); priceType = PriceMode.getDefaultPriceType(); priceReprocessedType = PriceMode.getDefaultPriceType(); priceManufacturingType = PriceMode.getDefaultPriceType(); } public PriceDataSettings(final LocationType locationType, final Long locationID, final PriceSource priceSource, final PriceMode priceType, final PriceMode priceReprocessedType, final PriceMode priceManufacturingType, final String janiceKey) { if (locationType != null && locationID != null) { this.locationType = locationType; this.locationID = locationID; } else { this.locationType = LocationType.REGION; this.locationID = getDefaultLocationID(); } this.priceSource = priceSource; this.priceType = priceType; this.priceReprocessedType = priceReprocessedType; this.priceManufacturingType = priceManufacturingType; if (janiceKey == null) { //empty string instead of null this.janiceKey = ""; } else { this.janiceKey = janiceKey; } } public PriceSource getSource() { return priceSource; } public Long getLocationID() { return locationID; } public LocationType getLocationType() { return locationType; } public double getDefaultPrice(final PriceData priceData) { return PriceMode.getDefaultPrice(priceData, priceType); } public double getDefaultPriceReprocessed(final PriceData priceData) { return PriceMode.getDefaultPrice(priceData, priceReprocessedType); } public double getDefaultPriceManufacturing(final PriceData priceData) { return PriceMode.getDefaultPrice(priceData, priceManufacturingType); } public static Long getDefaultLocationID() { return 10000002L; } public static PriceSource getDefaultPriceSource() { return PriceSource.FUZZWORK; } public void setPriceType(final PriceMode priceSource) { this.priceType = priceSource; } public void setPriceReprocessedType(final PriceMode reprocessedPriceType) { this.priceReprocessedType = reprocessedPriceType; } public void setPriceManufacturingType(PriceMode priceManufacturingType) { this.priceManufacturingType = priceManufacturingType; } public PriceMode getPriceType() { return priceType; } public PriceMode getPriceReprocessedType() { return priceReprocessedType; } public PriceMode getPriceManufacturingType() { return priceManufacturingType; } public String getJaniceKey() { return janiceKey; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final PriceDataSettings other = (PriceDataSettings) obj; if (this.locationType != other.locationType) { return false; } if (!Objects.equals(this.locationID, other.locationID)) { return false; } if (this.priceSource != other.priceSource) { return false; } return true; } @Override public int hashCode() { int hash = 5; hash = 29 * hash + Objects.hashCode(this.locationType); hash = 29 * hash + Objects.hashCode(this.locationID); hash = 29 * hash + Objects.hashCode(this.priceSource); return hash; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/PriceHistoryDatabase.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.text.ParseException; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.NavigableSet; import java.util.Set; import java.util.TreeSet; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings.PriceMode; import net.nikr.eve.jeveasset.gui.shared.Formatter.DateFormatThreadSafe; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceChangesTab.PriceChange; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceHistoryTab.PriceHistoryData; import net.nikr.eve.jeveasset.io.local.profile.ProfileTable.Rows; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class PriceHistoryDatabase { private static final Logger LOG = LoggerFactory.getLogger(PriceHistoryDatabase.class); public static final String ZKILLBOARD_TABLE = "zkillboard"; public static final String ZBLACKLIST_TABLE = "zblacklist"; public static final String PRICEDATA_TABLE = "pricedata"; public static final DateFormatThreadSafe DATE = new DateFormatThreadSafe("yyyy-MM-dd", true); private static PriceHistoryDatabase instance; public PriceHistoryDatabase() { this(false); } protected PriceHistoryDatabase(boolean createTable) { if (createTable) { init(); } } private void init() { if (!tableZKillboardExist()) { //New database: Empty createZKillboardTable(); } if (!tableZBlacklistExist()) { //New database: Empty createZBlacklistTable(); } if (!tablePriceDataExist()) { //New database: Empty createPriceDataTable(); } } private static String getConnectionUrl() { return "jdbc:sqlite:" + FileUtil.getPathPriceHistoryDatabase(); } private static PriceHistoryDatabase getInstance() { if (instance == null) { instance = new PriceHistoryDatabase(); } return instance; } public static void load() { getInstance().init(); } /** * Get typeIDs that have data for today. * @return */ public static Set getZKillboardUpdated() { return getInstance().selectZKillboardUpdated(); } /** * Add data to database. * Handles duplicates * @param data */ public static void setZKillboard(Map> data) { getInstance().updateZKillboard(data); } /** * Add typeIDs to database. * Handles duplicates * @param typeIDs */ public static void setZBlacklist(Set typeIDs) { getInstance().insertZBlaclist(typeIDs); } /** * clear database. */ public static void clearZBlacklist() { getInstance().deleteZBlaclist(); } /** * Get typeIDs * @return */ public static Set getZBlacklist() { return getInstance().selectZBlacklist(); } /** * Add data to database. * Handles duplicates * @param data */ public static void setPriceData(Map data) { getInstance().insertPriceData(data); } /** * Get all data in database. * @param typeIDs * @return */ public static Map> getZKillboard(Set typeIDs) { return getInstance().selectZKillboard(typeIDs); } /** * Get all data in database. * @param typeIDs * @param priceMode * @return */ public static Map> getPriceData(Set typeIDs, PriceMode priceMode) { return getInstance().selectPriceData(typeIDs, priceMode); } /** * Get price changes between from and to in database. * @param priceMode * @param ownedOnly * @param typeIDs * @param from * @param to * @return */ public static Set getPriceChanges(Map typeIDs, boolean ownedOnly, PriceMode priceMode, Date from, Date to) { return getInstance().selectPriceChanges(typeIDs, ownedOnly, priceMode, from, to); } /** * Get all dates in database. * @param typeIDs * @return */ public static NavigableSet getPriceChangesDate(Set typeIDs) { return getInstance().selectPriceChangesDate(typeIDs); } private void updateZKillboard(Map> map) { Set insert = new HashSet<>(); //Add new data for (Set set : map.values()) { insert.addAll(set); } //Update database insertZKillboard(insert); } private void insertZKillboard(Set insert) { if (insert == null || insert.isEmpty()) { return; } String sql = "INSERT OR IGNORE INTO " + ZKILLBOARD_TABLE + " (typeid,date,price) VALUES(?,?,?)"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, insert.size()); connection.setAutoCommit(false); for (PriceHistoryData killboardData : insert) { statement.setInt(1, killboardData.getTypeID()); statement.setString(2, killboardData.getDateString()); statement.setDouble(3, killboardData.getPrice()); rows.addRow(); } connection.commit(); connection.setAutoCommit(true); } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } private void insertZBlaclist(Set insert) { if (insert == null || insert.isEmpty()) { return; } String sql = "INSERT OR IGNORE INTO " + ZBLACKLIST_TABLE + " (typeid) VALUES(?)"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, insert.size()); connection.setAutoCommit(false); for (Integer typeID : insert) { statement.setInt(1, typeID); rows.addRow(); } connection.commit(); connection.setAutoCommit(true); } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } private void deleteZBlaclist() { String sql = "DELETE FROM " + ZBLACKLIST_TABLE; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); Statement statement = connection.createStatement()) { statement.execute(sql); } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } private void insertPriceData(Map insert) { if (insert == null || insert.isEmpty()) { return; } String date = DATE.format(new Date()); //Todays date String sql = "INSERT OR REPLACE INTO " + PRICEDATA_TABLE + " (typeid,date," + "sellmax," + "sellavg," + "sellmedian," + "sellpercentile," + "sellmin," + "buymax," + "buypercentile," + "buyavg," + "buymedian," + "buymin)" + "VALUES(?,?,?,?,?,?,?,?,?,?,?,?)"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, insert.size()); connection.setAutoCommit(false); for (Map.Entry entry : insert.entrySet()) { statement.setInt(1, entry.getKey()); statement.setString(2, date); statement.setDouble(3, entry.getValue().getSellMax()); statement.setDouble(4, entry.getValue().getSellAvg()); statement.setDouble(5, entry.getValue().getSellMedian()); statement.setDouble(6, entry.getValue().getSellPercentile()); statement.setDouble(7, entry.getValue().getSellMin()); statement.setDouble(8, entry.getValue().getBuyMax()); statement.setDouble(9, entry.getValue().getBuyPercentile()); statement.setDouble(10, entry.getValue().getBuyAvg()); statement.setDouble(11, entry.getValue().getBuyMedian()); statement.setDouble(12, entry.getValue().getBuyMin()); rows.addRow(); } connection.commit(); connection.setAutoCommit(true); } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } private Map> selectZKillboard(Set typeIDs) { Map> data = new HashMap<>(); StringBuilder builder = new StringBuilder(); boolean first = true; for (int typeID : typeIDs) { if (first) { first = false; } else { builder.append(", "); } builder.append(typeID); } for (int typeID : typeIDs) { data.put(ApiIdConverter.getItem(typeID), new TreeSet<>()); } String sql = "SELECT * FROM " + ZKILLBOARD_TABLE + " WHERE typeid IN (" + builder.toString() + ")"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { int typeID = rs.getInt("typeid"); String date = rs.getString("date"); double price = rs.getDouble("price"); try { Item item = ApiIdConverter.getItem(typeID); data.get(item).add(new PriceHistoryData(typeID, item, date, price)); } catch (ParseException ex) { //Ignore } } } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } return data; } private Map> selectPriceData(Set typeIDs, PriceMode priceMode) { Map> data = new HashMap<>(); StringBuilder builder = new StringBuilder(); boolean first = true; for (int typeID : typeIDs) { if (first) { first = false; } else { builder.append(", "); } builder.append(typeID); } for (int typeID : typeIDs) { data.put(ApiIdConverter.getItem(typeID), new TreeSet<>()); } String sql = "SELECT * FROM " + PRICEDATA_TABLE + " WHERE typeid IN (" + builder.toString() + ")"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { int typeID = rs.getInt("typeid"); String date = rs.getString("date"); PriceData priceData = new PriceData(); priceData.setSellMax(rs.getDouble("sellmax")); priceData.setSellAvg(rs.getDouble("sellavg")); priceData.setSellMedian(rs.getDouble("sellmedian")); priceData.setSellPercentile(rs.getDouble("sellpercentile")); priceData.setSellMin(rs.getDouble("sellmin")); priceData.setBuyMax(rs.getDouble("buymax")); priceData.setBuyPercentile(rs.getDouble("buypercentile")); priceData.setBuyAvg(rs.getDouble("buyavg")); priceData.setBuyMedian(rs.getDouble("buymedian")); priceData.setBuyMin(rs.getDouble("buymin")); try { Item item = ApiIdConverter.getItem(typeID); data.get(item).add(new PriceHistoryData(typeID, item, date, PriceMode.getDefaultPrice(priceData, priceMode))); } catch (ParseException ex) { //Ignore } } } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } return data; } private NavigableSet selectPriceChangesDate(Set typeIDs) { NavigableSet data = new TreeSet<>(); StringBuilder typeFilter = new StringBuilder(); if (!typeIDs.isEmpty()) { typeFilter.append(" WHERE typeid IN ("); boolean first = true; for (int typeID : typeIDs) { if (first) { first = false; } else { typeFilter.append(", "); } typeFilter.append(typeID); } typeFilter.append(") "); } String sql = "SELECT date FROM " + PRICEDATA_TABLE + typeFilter.toString() + " GROUP BY date"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String date = rs.getString("date"); data.add(date); } } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } return data; } private Set selectPriceChanges(Map typeIDs, boolean ownedOnly, PriceMode priceMode, Date from, Date to) { String fromString = DATE.format(from); String toString = DATE.format(to); Map data = new HashMap<>(); StringBuilder typeFilter = new StringBuilder(); if (!typeIDs.isEmpty() && ownedOnly) { typeFilter.append(" AND typeid IN ("); boolean first = true; for (int typeID : typeIDs.keySet()) { if (first) { first = false; } else { typeFilter.append(", "); } typeFilter.append(typeID); } typeFilter.append(") "); } StringBuilder dateFilter = new StringBuilder(); dateFilter.append("\""); dateFilter.append(fromString); dateFilter.append("\",\""); dateFilter.append(toString); dateFilter.append("\""); String sql = "SELECT * FROM " + PRICEDATA_TABLE + " WHERE date IN (" + dateFilter.toString() + ") " + typeFilter.toString() + " ORDER BY date"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { int typeID = rs.getInt("typeid"); String date = rs.getString("date"); PriceData priceData = new PriceData(); priceData.setSellMax(rs.getDouble("sellmax")); priceData.setSellAvg(rs.getDouble("sellavg")); priceData.setSellMedian(rs.getDouble("sellmedian")); priceData.setSellPercentile(rs.getDouble("sellpercentile")); priceData.setSellMin(rs.getDouble("sellmin")); priceData.setBuyMax(rs.getDouble("buymax")); priceData.setBuyPercentile(rs.getDouble("buypercentile")); priceData.setBuyAvg(rs.getDouble("buyavg")); priceData.setBuyMedian(rs.getDouble("buymedian")); priceData.setBuyMin(rs.getDouble("buymin")); PriceChange priceChange = data.get(typeID); double price = PriceMode.getDefaultPrice(priceData, priceMode); if (priceChange == null) { Item item = ApiIdConverter.getItem(typeID); priceChange = new PriceChange(typeID, item, typeIDs.getOrDefault(typeID, 0L)); data.put(typeID, priceChange); } if (date.equals(fromString)) { priceChange.setPriceFrom(price); } else if (date.equals(toString)) { priceChange.setPriceTo(price); } else { LOG.warn("Date is don't equals to or from???"); } } } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } return new HashSet<>(data.values()); } public static String getZKillboardDate() { Calendar cal = Calendar.getInstance(); cal.set(Calendar.MINUTE,0); cal.set(Calendar.SECOND,0); cal.set(Calendar.MILLISECOND,0); cal.add(Calendar.DAY_OF_MONTH, -2); return DATE.format(cal.getTime()); } private Set selectZKillboardUpdated() { Set typeIDs = new HashSet<>(); String sql = "SELECT typeid FROM " + ZKILLBOARD_TABLE + " WHERE date = ?"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); PreparedStatement statement = connection.prepareStatement(sql); ) { statement.setString(1, getZKillboardDate()); ResultSet rs = statement.executeQuery(); while (rs.next()) { typeIDs.add(rs.getInt("typeid")); } } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } return typeIDs; } private Set selectZBlacklist() { Set typeIDs = new HashSet<>(); String sql = "SELECT typeid FROM " + ZBLACKLIST_TABLE; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery(); ) { while (rs.next()) { typeIDs.add(rs.getInt("typeid")); } } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } return typeIDs; } private void createZKillboardTable() { String sql = "CREATE TABLE IF NOT EXISTS " + ZKILLBOARD_TABLE + " (\n" + " typeid INTEGER,\n" + " date TEXT,\n" + " price REAL,\n" + " UNIQUE(typeid, date)\n" + ");"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); Statement statement = connection.createStatement()) { statement.execute(sql); } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } private void createZBlacklistTable() { String sql = "CREATE TABLE IF NOT EXISTS " + ZBLACKLIST_TABLE + " (\n" + " typeid INTEGER\n" + ");"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); Statement statement = connection.createStatement()) { statement.execute(sql); } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } private void createPriceDataTable() { String sql = "CREATE TABLE IF NOT EXISTS " + PRICEDATA_TABLE + " (\n" + " typeid INTEGER,\n" + " date TEXT,\n" + " sellmax REAL,\n" + " sellavg REAL,\n" + " sellmedian REAL,\n" + " sellpercentile REAL,\n" + " sellmin REAL,\n" + " buymax REAL,\n" + " buypercentile REAL,\n" + " buyavg REAL,\n" + " buymedian REAL,\n" + " buymin REAL,\n" + " UNIQUE(typeid, date)\n" + ");"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); Statement statement = connection.createStatement()) { statement.execute(sql); } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } } private boolean tableZKillboardExist() { return tableExist(ZKILLBOARD_TABLE); } private boolean tableZBlacklistExist() { return tableExist(ZBLACKLIST_TABLE); } private boolean tablePriceDataExist() { return tableExist(PRICEDATA_TABLE); } public static boolean tableExist(String tableName) { String sql = "SELECT name FROM sqlite_master WHERE type='table' AND name='" + tableName + "'"; try (Connection connection = DriverManager.getConnection(getConnectionUrl()); Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery(sql)) { while (rs.next()) { return true; } } catch (SQLException ex) { LOG.error(ex.getMessage(), ex); } return false; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/ProxyData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.io.IOException; import java.net.Authenticator; import java.net.InetSocketAddress; import java.net.PasswordAuthentication; import java.net.Proxy; import java.net.ProxySelector; import java.net.SocketAddress; import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class ProxyData { private final String address; private final Proxy.Type type; private final int port; private final String username; private final String password; public ProxyData() { this.address = ""; this.type = Proxy.Type.DIRECT; this.port = 0; this.username = null; this.password = null; updateProxy(); } public ProxyData(String address, Proxy.Type type, int port, String username, String password) { this.address = address; this.type = type; this.port = port; this.username = username; this.password = password; updateProxy(); } public boolean isAuth() { return username != null && password != null; } private void updateProxy() { //Reset everything Authenticator.setDefault(null); //Auth ProxySelector.setDefault(new ProxyHost(Proxy.NO_PROXY)); //Proxy //Host System.clearProperty("http.proxyHost"); //http System.clearProperty("https.proxyHost");//https System.clearProperty("socksProxyHost"); //socks //Port System.clearProperty("http.proxyPort"); //http System.clearProperty("https.proxyPort");//https System.clearProperty("socksProxyPort"); //socks //Username System.clearProperty("http.proxyUser"); //http System.clearProperty("https.proxyUser");//https System.clearProperty("java.net.socks.username"); //socks //Password System.clearProperty("http.proxyPassword"); //http System.clearProperty("https.proxyPassword");//https System.clearProperty("java.net.socks.password"); //socks if (type == Proxy.Type.HTTP) { //HTTP/HTTPS Proxy //Proxy ProxySelector.setDefault(new ProxyHost(getProxy())); //Address System.setProperty("http.proxyHost", getAddress()); System.setProperty("https.proxyHost", getAddress()); //Port System.setProperty("http.proxyPort", String.valueOf(getPort())); System.setProperty("https.proxyPort", String.valueOf(getPort())); if (isAuth()) { //Username System.setProperty("http.proxyUser", getUsername()); System.setProperty("https.proxyUser", getUsername()); //Password System.setProperty("http.proxyPassword", getPassword()); System.setProperty("https.proxyPassword", getPassword()); //Auth Authenticator.setDefault(new ProxyAuth(getUsername(), getPassword())); } } else if (type == Proxy.Type.SOCKS) { //SOCKS Proxy //Proxy ProxySelector.setDefault(new ProxyHost(getProxy())); //Address System.setProperty("socksProxyHost", getAddress()); //Port System.setProperty("socksProxyPort", String.valueOf(getPort())); if (isAuth()) { //Username System.setProperty("java.net.socks.username", getUsername()); //Password System.setProperty("java.net.socks.password", getPassword()); //Auth Authenticator.setDefault(new ProxyAuth(getUsername(), getPassword())); } } } private Proxy getProxy() { if (type == Proxy.Type.DIRECT) { return Proxy.NO_PROXY; } else { return new Proxy(type, new InetSocketAddress(address, port)); } } public String getAddress() { return address; } public Proxy.Type getType() { return type; } public int getPort() { return port; } public String getUsername() { return username; } public String getPassword() { return password; } public List getArgs() { List args = new ArrayList(); if (type == Proxy.Type.HTTP) { // HTTP/HTTPS Proxy //Address args.add(format("https.proxyHost", getAddress())); //Port args.add(format("https.proxyPort", String.valueOf(getPort()))); if (isAuth()) { //Username args.add(format("https.proxyUser", getUsername())); //Password args.add(format("https.proxyPassword", getPassword())); } } //SOCKS Proxy if (type == Proxy.Type.SOCKS) { //Address args.add(format("socksProxyHost", getAddress())); //Port args.add(format("socksProxyPort", String.valueOf(getPort()))); if (isAuth()) { //Username args.add(format("java.net.socks.username", getUsername())); //Password args.add(format("java.net.socks.password", getPassword())); //Auth Authenticator.setDefault(new ProxyAuth(getUsername(), getPassword())); } } return args; } private String format(String key, String value) { return "-D" + key + "=" + value; } public static class ProxyAuth extends Authenticator { private final PasswordAuthentication auth; private ProxyAuth(String user, String password) { auth = new PasswordAuthentication(user, password == null ? new char[]{} : password.toCharArray()); } @Override protected PasswordAuthentication getPasswordAuthentication() { return auth; } } public static class ProxyHost extends ProxySelector { private final Proxy proxy; public ProxyHost(Proxy proxy) { this.proxy = proxy; } @Override public List select(URI uri) { return Collections.singletonList(proxy); } @Override public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/ReprocessSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; public class ReprocessSettings { private static final ReprocessSettings MAX = new ReprocessSettings(65.129, 5, 5, 5, 5); private final double station; private final int reprocessingLevel; private final int reprocessingEfficiencyLevel; private final int oreProcessingLevel; private final int scrapmetalProcessingLevel; //Defaults public ReprocessSettings() { this(50, 0, 0, 0, 0); } public ReprocessSettings(final double station, final int reprocessingLevel, final int reprocessingEfficiencyLevel, int oreProcessingLevel, final int scrapmetalProcessing) { this.station = station; this.reprocessingLevel = inRange(reprocessingLevel); this.reprocessingEfficiencyLevel = inRange(reprocessingEfficiencyLevel, this.reprocessingLevel); this.oreProcessingLevel = inRange(oreProcessingLevel, this.reprocessingEfficiencyLevel); this.scrapmetalProcessingLevel = inRange(scrapmetalProcessing); } private int inRange(final int level, int required) { if (required < 4) { return 0; } return inRange(level); } private int inRange(final int level) { if (level < 0) { return 0; } else if (level > 5) { return 5; } else { return level; } } public int getReprocessingEfficiencyLevel() { return reprocessingEfficiencyLevel; } public int getReprocessingLevel() { return reprocessingLevel; } public int getOreProcessingLevel() { return oreProcessingLevel; } public int getScrapmetalProcessingLevel() { return scrapmetalProcessingLevel; } public double getStation() { return station; } public static int getMax(final long start, final boolean ore) { return MAX.getLeft(start, ore); } public int getLeft(final long start, final boolean ore) { return (int) Math.floor((((double) start) / 100.0) * getPercent(ore)); } protected double getPercent(final boolean ore) { double percent; if (ore) { percent = ((station / 100.0) * (1.0 + ((double) reprocessingLevel * 0.03)) * (1.0 + ((double) reprocessingEfficiencyLevel * 0.02)) * (1.0 + ((double) oreProcessingLevel * 0.02)) ) * 100.0; } else { percent = (0.5 //Station is always 50% for scrap metal * (1.0 + ((double) scrapmetalProcessingLevel * 0.02)) ) * 100.0; } if (percent > 100) { return 100; } return percent; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ReprocessSettings other = (ReprocessSettings) obj; if (Double.doubleToLongBits(this.station) != Double.doubleToLongBits(other.station)) { return false; } if (this.reprocessingLevel != other.reprocessingLevel) { return false; } if (this.reprocessingEfficiencyLevel != other.reprocessingEfficiencyLevel) { return false; } if (this.oreProcessingLevel != other.oreProcessingLevel) { return false; } if (this.scrapmetalProcessingLevel != other.scrapmetalProcessingLevel) { return false; } return true; } @Override public int hashCode() { int hash = 5; hash = 61 * hash + (int) (Double.doubleToLongBits(this.station) ^ (Double.doubleToLongBits(this.station) >>> 32)); hash = 61 * hash + this.reprocessingLevel; hash = 61 * hash + this.reprocessingEfficiencyLevel; hash = 61 * hash + this.oreProcessingLevel; hash = 61 * hash + this.scrapmetalProcessingLevel; return hash; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/RouteAvoidSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Set; import net.nikr.eve.jeveasset.gui.tabs.routing.SolarSystem; public class RouteAvoidSettings { private double secMin; private double secMax; private final Map avoid = new HashMap<>(); private final Map> presets = new HashMap<>(); public RouteAvoidSettings() { secMin = 0.0; secMax = 1.0; } public double getSecMin() { return secMin; } public void setSecMin(double secMin) { this.secMin = secMin; } public double getSecMax() { return secMax; } public void setSecMax(double secMax) { this.secMax = secMax; } public Map getAvoid() { return avoid; } public Map> getPresets() { return presets; } public void update(RouteAvoidSettings avoidSettings) { secMin = avoidSettings.getSecMin(); secMax = avoidSettings.getSecMax(); avoid.clear(); avoid.putAll(avoidSettings.getAvoid()); presets.clear(); presets.putAll(avoidSettings.getPresets()); } @Override public int hashCode() { int hash = 5; hash = 53 * hash + (int) (Double.doubleToLongBits(this.secMin) ^ (Double.doubleToLongBits(this.secMin) >>> 32)); hash = 53 * hash + (int) (Double.doubleToLongBits(this.secMax) ^ (Double.doubleToLongBits(this.secMax) >>> 32)); hash = 53 * hash + Objects.hashCode(this.avoid); hash = 53 * hash + Objects.hashCode(this.presets); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final RouteAvoidSettings other = (RouteAvoidSettings) obj; if (Double.doubleToLongBits(this.secMin) != Double.doubleToLongBits(other.secMin)) { return false; } if (Double.doubleToLongBits(this.secMax) != Double.doubleToLongBits(other.secMax)) { return false; } if (!Objects.equals(this.avoid, other.avoid)) { return false; } return Objects.equals(this.presets, other.presets); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/RouteResult.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.List; import java.util.Map; import java.util.Objects; import net.nikr.eve.jeveasset.gui.tabs.routing.SolarSystem; import net.nikr.eve.jeveasset.i18n.TabsRouting; public class RouteResult { private final List> route; private final Map> stations; private final int waypoints; private final String algorithmName; private final long algorithmTime; private final int jumps; private final String avoid; private final String security; public RouteResult(List> route, Map> stations, int waypoints, String algorithmName, long algorithmTime, int jumps, String avoid, String security) { this.route = route; this.stations = stations; this.waypoints = waypoints; this.algorithmName = algorithmName; this.algorithmTime = algorithmTime; this.jumps = jumps; if (avoid != null) { this.avoid = avoid; } else { this.avoid = TabsRouting.get().resultUnknownValue(); } if (security != null) { this.security = security; } else { this.security = TabsRouting.get().resultUnknownValue(); } } public List> getRoute() { return route; } public Map> getStations() { return stations; } public int getWaypoints() { return waypoints; } public String getAlgorithmName() { return algorithmName; } public long getAlgorithmTime() { return algorithmTime; } public int getJumps() { return jumps; } public String getAvoid() { return avoid; } public String getSecurity() { return security; } @Override public int hashCode() { int hash = 5; hash = 97 * hash + Objects.hashCode(this.route); hash = 97 * hash + Objects.hashCode(this.stations); hash = 97 * hash + this.waypoints; hash = 97 * hash + Objects.hashCode(this.algorithmName); hash = 97 * hash + (int) (this.algorithmTime ^ (this.algorithmTime >>> 32)); hash = 97 * hash + this.jumps; hash = 97 * hash + Objects.hashCode(this.avoid); hash = 97 * hash + Objects.hashCode(this.security); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final RouteResult other = (RouteResult) obj; if (this.waypoints != other.waypoints) { return false; } if (this.algorithmTime != other.algorithmTime) { return false; } if (this.jumps != other.jumps) { return false; } if (!Objects.equals(this.algorithmName, other.algorithmName)) { return false; } if (!Objects.equals(this.avoid, other.avoid)) { return false; } if (!Objects.equals(this.security, other.security)) { return false; } if (!Objects.equals(this.route, other.route)) { return false; } if (!Objects.equals(this.stations, other.stations)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/RoutingSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.Map; import java.util.Set; import java.util.TreeMap; import net.nikr.eve.jeveasset.gui.tabs.routing.SolarSystem; public class RoutingSettings { private final RouteAvoidSettings avoidSettings = new RouteAvoidSettings(); private final Map routes = new TreeMap<>(); public Map getRoutes() { return routes; } public RouteAvoidSettings getAvoidSettings() { return avoidSettings; } public double getSecMin() { return avoidSettings.getSecMin(); } public void setSecMin(double secMin) { avoidSettings.setSecMin(secMin); } public double getSecMax() { return avoidSettings.getSecMax(); } public void setSecMax(double secMax) { avoidSettings.setSecMax(secMax); } public Map getAvoid() { return avoidSettings.getAvoid(); } public Map> getPresets() { return avoidSettings.getPresets(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/Settings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.awt.Dimension; import java.awt.Point; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import net.nikr.eve.jeveasset.SplashUpdater; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob.IndustryJobStatus; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.MarketOrderRange; import net.nikr.eve.jeveasset.data.settings.tag.Tag; import net.nikr.eve.jeveasset.data.settings.tag.TagID; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.dialogs.settings.SoundsSettingsPanel.SoundOption; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog.Formula; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuJumps.Jump; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.ResizeMode; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.SimpleColumn; import net.nikr.eve.jeveasset.gui.shared.table.View; import net.nikr.eve.jeveasset.gui.sounds.Sound; import net.nikr.eve.jeveasset.gui.tabs.jobs.IndustryJobTableFormat; import net.nikr.eve.jeveasset.gui.tabs.jobs.IndustryJobsTab; import net.nikr.eve.jeveasset.gui.tabs.mining.ExtractionsTab; import net.nikr.eve.jeveasset.gui.tabs.mining.ExtractionsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.journal.JournalTab; import net.nikr.eve.jeveasset.gui.tabs.journal.JournalTableFormat; import net.nikr.eve.jeveasset.gui.tabs.orders.MarketOrdersTab; import net.nikr.eve.jeveasset.gui.tabs.orders.MarketTableFormat; import net.nikr.eve.jeveasset.gui.tabs.orders.Outbid; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewGroup; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTab; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTableFormat; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; import net.nikr.eve.jeveasset.i18n.TabsJobs; import net.nikr.eve.jeveasset.i18n.TabsJournal; import net.nikr.eve.jeveasset.i18n.TabsMining; import net.nikr.eve.jeveasset.i18n.TabsOrders; import net.nikr.eve.jeveasset.i18n.TabsTransaction; import net.nikr.eve.jeveasset.io.local.SettingsReader; import net.nikr.eve.jeveasset.io.local.SettingsWriter; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Settings { private static final Logger LOG = LoggerFactory.getLogger(Settings.class); public static enum SettingFlag { FLAG_IGNORE_SECURE_CONTAINERS, FLAG_FILTER_ON_ENTER, FLAG_REPROCESS_COLORS, FLAG_INCLUDE_SELL_ORDERS, FLAG_INCLUDE_BUY_ORDERS, FLAG_INCLUDE_SELL_CONTRACTS, FLAG_INCLUDE_BUY_CONTRACTS, FLAG_INCLUDE_MANUFACTURING, FLAG_INCLUDE_COPYING, FLAG_INCLUDE_JUMP_CLONES, FLAG_INCLUDE_PLUGGED_IN_IMPLANTS, FLAG_HIGHLIGHT_SELECTED_ROWS, FLAG_STOCKPILE_FOCUS_TAB, FLAG_STOCKPILE_HALF_COLORS, FLAG_BLUEPRINT_BASE_PRICE_TECH_1, FLAG_BLUEPRINT_BASE_PRICE_TECH_2, FLAG_TRANSACTION_HISTORY, FLAG_JOURNAL_HISTORY, FLAG_MARKET_ORDER_HISTORY, FLAG_ASKED_CHECK_ALL_TRACKER, FLAG_TRACKER_USE_ASSET_PRICE_FOR_SELL_ORDERS, FLAG_FOCUS_EVE_ONLINE_ON_ESI_UI_CALLS, FLAG_SAVE_TOOLS_ON_EXIT, FLAG_SAVE_CONTRACT_HISTORY, FLAG_SAVE_MINING_HISTORY, FLAG_MANUFACTURING_DEFAULT, FLAG_EASY_CHART_COLORS, FLAG_CONTAINERS_SHOW_ITEM_ID, FLAG_LOCK_TOOLS, FLAG_SHOW_SUBPILE_TREE, FLAG_INDUSTRY_JOBS_HISTORY, FLAG_ASSETS_CONTRACTS_OWNER_CORP, FLAG_ASSETS_CONTRACTS_OWNER_BOTH, FLAG_CELL_VALUE_CACHE, FLAG_LOAD_TOOLS_BACKGROUND, FLAG_LOAD_TOOLS_STARTUP, FLAG_EVE_GATECAMP_CHECK_SET, FLAG_EVE_GATECAMP_CHECK_ALWAYS_OPEN, FLAG_EVE_GATECAMP_CHECK_NEVER_OPEN, FLAG_EVE_GATECAMP_CHECK_SECURE, FLAG_EVE_GATECAMP_CHECK_UNSECURE } public static enum TransactionProfitPrice { LASTEST() { @Override public String getText() { return DialoguesSettings.get().transactionsPriceLatest(); } }, AVERAGE() { @Override public String getText() { return DialoguesSettings.get().transactionsPriceAverage(); } }, MINIMUM() { @Override public String getText() { return DialoguesSettings.get().transactionsPriceMinimum(); } }, MAXIMUM() { @Override public String getText() { return DialoguesSettings.get().transactionsPriceMaximum(); } }; @Override public String toString() { return getText(); } protected abstract String getText(); } private static final SettingsLock LOCK = new SettingsLock(); private static Settings settings; private static boolean testMode = false; //External //Price Saved by PriceDataGetter.process() in pricedata.dat (on api update) private Map priceDatas = new HashMap<>(); //TypeID : int //API Data //Api id to owner name Saved by TaskDialog.update() (on API update) private final Map ownersNextUpdate = new HashMap<>(); private final Map owners = new HashMap<>(); //!! - Values //OK - Custom Price Saved by JUserListPanel.edit()/delete() + SettingsDialog.save() //Lock OK private Map> userPrices = new HashMap<>(); //TypeID : int //OK - Custom Item Name Saved by JUserListPanel.edit()/delete() + SettingsDialog.save() //Lock OK private Map> userNames = new HashMap<>(); //ItemID : long //Eve Item Name Saved by TaskDialog.update() (on API update) //Lock ??? private Map eveNames = new HashMap<>(); //!! - Stockpile Saved by StockpileTab.removeItems() / addStockpile() / removeStockpile() // Could be more selective... //Lock FAIL!!! private final List stockpiles = new ArrayList<>(); private int stockpileColorGroup2 = 100; private int stockpileColorGroup3 = 0; private final StockpileGroupSettings stockpileGroupSettings = new StockpileGroupSettings(); //Routing Saved by ??? //Lock ??? private final RoutingSettings routingSettings = new RoutingSettings(); //Jumps //Lock ??? private final RouteAvoidSettings jumpsAvoidSettings = new RouteAvoidSettings(); //Overview Saved by JOverviewMenu.ListenerClass.NEW/DELETE/RENAME //Lock OK private final Map overviewGroups = new HashMap<>(); //Export Saved in ExportDialog.saveSettings() //Lock OK private final CopySettings copySettings = new CopySettings(); private final Map exportSettings = new HashMap<>(); //Import private final Map importSettings = new HashMap<>(); //Tracker Saved by TaskDialog.update() (on API update) private final TrackerSettings trackerSettings = new TrackerSettings(); //Price History private final Map> priceHistorySets = new HashMap<>(); //Runtime flags Is not saved to file private boolean settingsLoadError = false; //Settings Dialog: Saved by SettingsDialog.save() //Lock OK //Mixed boolean flags private final Map flags = new EnumMap<>(SettingFlag.class); //Price private PriceDataSettings priceDataSettings = new PriceDataSettings(); //Proxy (API) private ProxyData proxyData = new ProxyData(); //FIXME - - > Settings: Create windows settings //Window // Saved by MainWindow.ListenerClass.componentMoved() (on change) private Point windowLocation = new Point(0, 0); // Saved by MainWindow.ListenerClass.componentResized() (on change) private Dimension windowSize = new Dimension(800, 600); // Saved by MainWindow.ListenerClass.componentMoved() (on change) private boolean windowMaximized = false; // Saved by SettingsDialog.save() private boolean windowAutoSave = true; private boolean windowAlwaysOnTop = false; //Assets private int maximumPurchaseAge = 0; private int transactionProfitMargin = 0; private TransactionProfitPrice transactionProfitPrice = TransactionProfitPrice.LASTEST; //Reprocess price private ReprocessSettings reprocessSettings = new ReprocessSettings(); //Public Market Orders Last Update private Date publicMarketOrdersLastUpdate = null; //Public Market Orders Next Update private Date publicMarketOrdersNextUpdate = getNow(); //Faction Warfare System Owners private Map factionWarfareSystemOwners = new HashMap<>(); //Faction Warfare Next Update private Date factionWarfareNextUpdate = getNow(); //Market Orders Outbid private Map marketOrdersOutbid = new HashMap<>(); //SellOrderRange private MarketOrderRange outbidOrderRange = MarketOrderRange.REGION; //Expire Warning Days private final MarketOrdersSettings marketOrdersSettings = new MarketOrdersSettings(); //Cache private Boolean filterOnEnter = null; //Filter tools private Boolean highlightSelectedRows = null; //Assets private Boolean reprocessColors = null; //Assets private Boolean stockpileHalfColors = null; //Stockpile private Boolean containersShowItemID = null; //Container ItemID private Boolean cellValueCache = null; //Cell value cache //Table settings //Filters Saved by ExportFilterControl.saveSettings() //Lock OK private final Map>> tableFilters = new HashMap<>(); //Columns Saved by EnumTableFormatAdaptor.getMenu() - Reset // EditColumnsDialog.save() - Edit Columns // JAutoColumnTable.ListenerClass.mouseReleased() - Moved // ViewManager.loadView() - Load View //Lock OK private final Map>> defaultTableFilters = new HashMap<>(); private final Map> currentTableFilters = new HashMap<>(); private final Map currentTableFiltersShown = new HashMap<>(); private final Map currentTableSorting = new HashMap<>(); private final Map> tableColumns = new HashMap<>(); //Column Width Saved by JAutoColumnTable.saveColumnsWidth() //Lock OK private final Map> tableColumnsWidth = new HashMap<>(); //Resize Mode Saved by EnumTableFormatAdaptor.getMenu() //Lock OK private final Map tableResize = new HashMap<>(); //Views Saved by EnumTableFormatAdaptor.getMenu() - New // ViewManager.rename() - Rename // ViewManager.delete() - Delete //Lock OK private final Map> tableViews = new HashMap<>(); //Formula Columns private final Map> tableFormulas = new HashMap<>(); //Jump Columns private final Map> tableJumps = new HashMap<>(); // Skill Plans: plan name -> (skill typeID -> target level) private final Map> skillPlans = new HashMap<>(); //Tags Saved by JMenuTags.addTag()/removeTag() + SettingsDialog.save() //Lock OK private final Map tags = new HashMap<>(); private final Map tagIds = new HashMap<>(); //Changed private final Map tableChanged = new HashMap<>(); //Tools private final List showTools = new ArrayList<>(); //Colors private final ColorSettings colorSettings = new ColorSettings(); //Sounds private final Map soundSettings = new EnumMap<>(SoundOption.class); //Manufacturing private final ManufacturingSettings manufacturingSettings = new ManufacturingSettings(); protected Settings() { //Settings flags.put(SettingFlag.FLAG_FILTER_ON_ENTER, false); //Cached flags.put(SettingFlag.FLAG_HIGHLIGHT_SELECTED_ROWS, true); //Cached flags.put(SettingFlag.FLAG_REPROCESS_COLORS, false); //Cached flags.put(SettingFlag.FLAG_IGNORE_SECURE_CONTAINERS, true); flags.put(SettingFlag.FLAG_STOCKPILE_FOCUS_TAB, true); flags.put(SettingFlag.FLAG_STOCKPILE_HALF_COLORS, false); //Cached flags.put(SettingFlag.FLAG_INCLUDE_SELL_ORDERS, false); flags.put(SettingFlag.FLAG_INCLUDE_BUY_ORDERS, false); flags.put(SettingFlag.FLAG_INCLUDE_SELL_CONTRACTS, false); flags.put(SettingFlag.FLAG_INCLUDE_BUY_CONTRACTS, false); flags.put(SettingFlag.FLAG_INCLUDE_MANUFACTURING, false); flags.put(SettingFlag.FLAG_INCLUDE_COPYING, false); flags.put(SettingFlag.FLAG_INCLUDE_JUMP_CLONES, true); flags.put(SettingFlag.FLAG_INCLUDE_PLUGGED_IN_IMPLANTS, true); flags.put(SettingFlag.FLAG_BLUEPRINT_BASE_PRICE_TECH_1, true); flags.put(SettingFlag.FLAG_BLUEPRINT_BASE_PRICE_TECH_2, false); flags.put(SettingFlag.FLAG_TRANSACTION_HISTORY, true); flags.put(SettingFlag.FLAG_JOURNAL_HISTORY, true); flags.put(SettingFlag.FLAG_MARKET_ORDER_HISTORY, true); flags.put(SettingFlag.FLAG_ASKED_CHECK_ALL_TRACKER, false); flags.put(SettingFlag.FLAG_TRACKER_USE_ASSET_PRICE_FOR_SELL_ORDERS, false); flags.put(SettingFlag.FLAG_FOCUS_EVE_ONLINE_ON_ESI_UI_CALLS, true); flags.put(SettingFlag.FLAG_SAVE_TOOLS_ON_EXIT, false); flags.put(SettingFlag.FLAG_SAVE_CONTRACT_HISTORY, true); flags.put(SettingFlag.FLAG_SAVE_MINING_HISTORY, true); flags.put(SettingFlag.FLAG_MANUFACTURING_DEFAULT, true); flags.put(SettingFlag.FLAG_EASY_CHART_COLORS, false); flags.put(SettingFlag.FLAG_CONTAINERS_SHOW_ITEM_ID, true); flags.put(SettingFlag.FLAG_LOCK_TOOLS, false); flags.put(SettingFlag.FLAG_SHOW_SUBPILE_TREE, true); flags.put(SettingFlag.FLAG_INDUSTRY_JOBS_HISTORY, true); flags.put(SettingFlag.FLAG_ASSETS_CONTRACTS_OWNER_CORP, false); flags.put(SettingFlag.FLAG_ASSETS_CONTRACTS_OWNER_BOTH, false); flags.put(SettingFlag.FLAG_CELL_VALUE_CACHE, true); flags.put(SettingFlag.FLAG_LOAD_TOOLS_BACKGROUND, true); flags.put(SettingFlag.FLAG_LOAD_TOOLS_STARTUP, false); flags.put(SettingFlag.FLAG_EVE_GATECAMP_CHECK_SET, false); flags.put(SettingFlag.FLAG_EVE_GATECAMP_CHECK_ALWAYS_OPEN, false); flags.put(SettingFlag.FLAG_EVE_GATECAMP_CHECK_NEVER_OPEN, false); flags.put(SettingFlag.FLAG_EVE_GATECAMP_CHECK_UNSECURE, false); flags.put(SettingFlag.FLAG_EVE_GATECAMP_CHECK_SECURE, false); cacheFlags(); //Default Filters List filter; //Market Orders: Default Filters Map> marketOrdersDefaultFilters = new HashMap<>(); filter = new ArrayList<>(); filter.add(new Filter(Filter.LogicType.AND, MarketTableFormat.ORDER_TYPE, Filter.CompareType.EQUALS, TabsOrders.get().buy())); filter.add(new Filter(Filter.LogicType.AND, MarketTableFormat.STATUS, Filter.CompareType.EQUALS, TabsOrders.get().statusActive())); marketOrdersDefaultFilters.put(TabsOrders.get().activeBuyOrders(), filter); filter = new ArrayList<>(); filter.add(new Filter(Filter.LogicType.AND, MarketTableFormat.ORDER_TYPE, Filter.CompareType.EQUALS, TabsOrders.get().sell())); filter.add(new Filter(Filter.LogicType.AND, MarketTableFormat.STATUS, Filter.CompareType.EQUALS, TabsOrders.get().statusActive())); marketOrdersDefaultFilters.put(TabsOrders.get().activeSellOrders(), filter); defaultTableFilters.put(MarketOrdersTab.NAME, marketOrdersDefaultFilters); //Journal: Default Filters Map> journalDefaultFilters = new HashMap<>(); filter = new ArrayList<>(); filter.add(new Filter(Filter.LogicType.OR, JournalTableFormat.REF_TYPE, Filter.CompareType.CONTAINS, "Bounty")); filter.add(new Filter(Filter.LogicType.OR, JournalTableFormat.REF_TYPE, Filter.CompareType.CONTAINS, "ESS")); filter.add(new Filter(Filter.LogicType.AND, JournalTableFormat.DATE, Filter.CompareType.LAST_DAYS, "7")); journalDefaultFilters.put(TabsJournal.get().rattingIncome(), filter); defaultTableFilters.put(JournalTab.NAME, journalDefaultFilters); //Transactions: Default Filters Map> transactionsDefaultFilters = new HashMap<>(); filter = new ArrayList<>(); filter.add(new Filter(Filter.LogicType.AND, TransactionTableFormat.TYPE, Filter.CompareType.EQUALS, TabsTransaction.get().buy())); transactionsDefaultFilters.put(TabsTransaction.get().buy(), filter); filter = new ArrayList<>(); filter.add(new Filter(Filter.LogicType.AND, TransactionTableFormat.TYPE, Filter.CompareType.EQUALS, TabsTransaction.get().sell())); transactionsDefaultFilters.put(TabsTransaction.get().sell(), filter); defaultTableFilters.put(TransactionTab.NAME, transactionsDefaultFilters); //Industry Jobs: Default Filters Map> industryJobsTabDefaultFilters = new HashMap<>(); filter = new ArrayList<>(); filter.add(new Filter(Filter.LogicType.AND, IndustryJobTableFormat.STATE, Filter.CompareType.EQUALS_NOT, MyIndustryJob.getStatusName(IndustryJobStatus.DELIVERED))); filter.add(new Filter(Filter.LogicType.AND, IndustryJobTableFormat.STATE, Filter.CompareType.EQUALS_NOT, MyIndustryJob.getStatusName(IndustryJobStatus.CANCELLED))); filter.add(new Filter(Filter.LogicType.AND, IndustryJobTableFormat.STATE, Filter.CompareType.EQUALS_NOT, MyIndustryJob.getStatusName(IndustryJobStatus.REVERTED))); filter.add(new Filter(Filter.LogicType.AND, IndustryJobTableFormat.STATE, Filter.CompareType.EQUALS_NOT, MyIndustryJob.getStatusName(IndustryJobStatus.ARCHIVED))); industryJobsTabDefaultFilters.put(TabsJobs.get().active(), filter); filter = new ArrayList<>(); filter.add(new Filter(Filter.LogicType.OR, IndustryJobTableFormat.STATE, Filter.CompareType.EQUALS, MyIndustryJob.getStatusName(IndustryJobStatus.DELIVERED))); filter.add(new Filter(Filter.LogicType.OR, IndustryJobTableFormat.STATE, Filter.CompareType.EQUALS, MyIndustryJob.getStatusName(IndustryJobStatus.CANCELLED))); filter.add(new Filter(Filter.LogicType.OR, IndustryJobTableFormat.STATE, Filter.CompareType.EQUALS, MyIndustryJob.getStatusName(IndustryJobStatus.REVERTED))); filter.add(new Filter(Filter.LogicType.OR, IndustryJobTableFormat.STATE, Filter.CompareType.EQUALS, MyIndustryJob.getStatusName(IndustryJobStatus.ARCHIVED))); industryJobsTabDefaultFilters.put(TabsJobs.get().completed(), filter); defaultTableFilters.put(IndustryJobsTab.NAME, industryJobsTabDefaultFilters); //Extractions Default Filters Map> extractionsDefaultFilters = new HashMap<>(); filter = new ArrayList<>(); filter.add(new Filter(Filter.LogicType.OR, ExtractionsTableFormat.ARRIVAL, Filter.CompareType.NEXT_DAYS, "2")); filter.add(new Filter(Filter.LogicType.OR, ExtractionsTableFormat.DECAY, Filter.CompareType.LAST_DAYS, "2")); extractionsDefaultFilters.put(TabsMining.get().extractionsActiveSoon(), filter); defaultTableFilters.put(ExtractionsTab.NAME, extractionsDefaultFilters); } public static Settings get() { load(); return settings; } public static void setTestMode(boolean testMode) { Settings.testMode = testMode; } public static boolean isTestMode() { return testMode; } public static void lock(String msg) { LOCK.lock(msg); } public static void unlock(String msg) { LOCK.unlock(msg); } public static boolean ignoreSave() { return LOCK.ignoreSave(); } public static void waitForEmptySaveQueue() { LOCK.waitForEmptySaveQueue(); } public static void saveStart() { LOCK.saveStart(); } public static void saveEnd() { LOCK.saveEnd(); } public synchronized static void load() { if (settings == null) { SplashUpdater.setProgress(30); settings = SettingsReader.load(new EmptySettingsFactory(), FileUtil.getPathSettings()); SplashUpdater.setProgress(35); } } /*** * * @return */ public Map getExportSettings() { return exportSettings; } /*** * * @param toolName * @return */ public ExportSettings getExportSettings(String toolName) { if (!exportSettings.containsKey(toolName)) { exportSettings.put(toolName, new ExportSettings(toolName)); } return exportSettings.get(toolName); } /*** * * @return */ public Map getImportSettings() { return importSettings; } /*** * * @param toolName * @param defaultValue * @return */ public String getImportSettings(String toolName, Enum defaultValue) { if (!importSettings.containsKey(toolName)) { importSettings.put(toolName, defaultValue.name()); } return importSettings.get(toolName); } /*** * * @param toolName * @param type */ public void putImportSettings(String toolName, Enum type) { importSettings.put(toolName, type.name()); } public CopySettings getCopySettings() { return copySettings; } public static void saveSettings() { LOCK.lock("Save Settings"); try { SettingsWriter.save(settings, FileUtil.getPathSettings()); } finally { LOCK.unlock("Save Settings"); } } public TrackerSettings getTrackerSettings() { return trackerSettings; } public Map> getPriceHistorySets() { return priceHistorySets; } public PriceDataSettings getPriceDataSettings() { return priceDataSettings; } public void setPriceDataSettings(final PriceDataSettings priceDataSettings) { this.priceDataSettings = priceDataSettings; } public Map> getUserPrices() { return userPrices; } public void setUserPrices(final Map> userPrices) { this.userPrices = userPrices; } public Map> getUserItemNames() { return userNames; } public void setUserItemNames(final Map> userItemNames) { this.userNames = userItemNames; } public void setPriceData(final Map priceData) { this.priceDatas = priceData; } public Map getEveNames() { return eveNames; } public void setEveNames(Map eveNames) { this.eveNames = eveNames; } public Map getPriceData() { return priceDatas; } public Map getFlags() { return flags; } public final void cacheFlags() { highlightSelectedRows = flags.get(SettingFlag.FLAG_HIGHLIGHT_SELECTED_ROWS); filterOnEnter = flags.get(SettingFlag.FLAG_FILTER_ON_ENTER); reprocessColors = flags.get(SettingFlag.FLAG_REPROCESS_COLORS); stockpileHalfColors = flags.get(SettingFlag.FLAG_STOCKPILE_HALF_COLORS); containersShowItemID = flags.get(SettingFlag.FLAG_CONTAINERS_SHOW_ITEM_ID); cellValueCache = flags.get(SettingFlag.FLAG_CELL_VALUE_CACHE); } public ReprocessSettings getReprocessSettings() { return reprocessSettings; } public void setReprocessSettings(final ReprocessSettings reprocessSettings) { this.reprocessSettings = reprocessSettings; } public RoutingSettings getRoutingSettings() { return routingSettings; } public RouteAvoidSettings getJumpsAvoidSettings() { return jumpsAvoidSettings; } public Map> getTableJumps() { return tableJumps; } public List getTableJumps(String toolName) { List jumps = tableJumps.get(toolName); if (jumps == null) { jumps = new ArrayList<>(); tableJumps.put(toolName, jumps); } return jumps; } public Map getSoundSettings() { return soundSettings; } public Map getTableChanged() { return tableChanged; } public Date getTableChanged(String toolName) { Date date = tableChanged.get(toolName); if (date == null) { date = new Date(); tableChanged.put(toolName, date); } return date; } public ProxyData getProxyData() { return proxyData; } public void setProxyData(ProxyData proxyData) { this.proxyData = proxyData; } public Map getOwnersNextUpdate() { return ownersNextUpdate; } public Map getOwners() { return owners; } public Map>> getTableFilters() { return tableFilters; } public Map> getTableFilters(final String key) { if (!tableFilters.containsKey(key)) { tableFilters.put(key, new HashMap<>()); } return tableFilters.get(key); } public Map> getDefaultTableFilters(final String key) { if (!defaultTableFilters.containsKey(key)) { defaultTableFilters.put(key, new HashMap<>()); } return defaultTableFilters.get(key); } /*** * @return Current table filters, list may be empty but should never be null. */ public Map> getCurrentTableFilters() { return currentTableFilters; } /*** * @param tableName Table to look up. * @return The value of the filter if {@code key} is found. If {@code key} is not found it will be added with an * empty list and then returned. */ public List getCurrentTableFilters(final String tableName) { if (!currentTableFilters.containsKey(tableName)) { currentTableFilters.put(tableName, new ArrayList<>()); } return currentTableFilters.get(tableName); } /*** * @return current table filters visibility state, list may be empty but should never be null. */ public Map getCurrentTableFiltersShown() { return currentTableFiltersShown; } /*** * @param tableName Table to look up. * @return The value of the filter visibility state if key is found. If key is not found it will be added as visible * and then returned. */ public boolean getCurrentTableFiltersShown(final String tableName) { if (!currentTableFiltersShown.containsKey(tableName)) { currentTableFiltersShown.put(tableName, true); } return currentTableFiltersShown.get(tableName); } /*** * @return Current table sorting state, values may be empty but should never be null. */ public Map getCurrentTableSorting() { return currentTableSorting; } /*** * @param toolName Tool to look up. * @return Current table sorting. Can be empty, but, never null. */ public String getCurrentTableSorting(final String toolName) { return currentTableSorting.getOrDefault(toolName, ""); } public Map> getTableColumns() { return tableColumns; } public Map> getTableColumnsWidth() { return tableColumnsWidth; } public Map getTableResize() { return tableResize; } public Map> getTableViews() { return tableViews; } public Map getTableViews(String name) { Map views = tableViews.get(name); if (views == null) { views = new TreeMap<>(StringComparators.CASE_INSENSITIVE); tableViews.put(name, views); } return views; } /** * Skill Plans storage. * Key: plan name; Value: map of skill typeID to target level (1..5). * @return */ public Map> getSkillPlans() { return skillPlans; } public Map> getTableFormulas() { return tableFormulas; } public List getTableFormulas(String name) { List formula = tableFormulas.get(name); if (formula == null) { formula = new ArrayList<>(); tableFormulas.put(name, formula); } return formula; } public Map getTags() { return tags; } public Tags getTags(TagID tagID) { Tags set = tagIds.get(tagID); if (set == null) { set = new Tags(); tagIds.put(tagID, set); } return set; } public Map getFactionWarfareSystemOwners() { return factionWarfareSystemOwners; } public void setFactionWarfareSystemOwners(Map factionWarfareSystemOwners) { this.factionWarfareSystemOwners = factionWarfareSystemOwners; } public Date getFactionWarfareNextUpdate() { return factionWarfareNextUpdate; } public void setFactionWarfareNextUpdate(Date factionWarfareNextUpdate) { this.factionWarfareNextUpdate = factionWarfareNextUpdate; } public ManufacturingSettings getManufacturingSettings() { return manufacturingSettings; } public Date getPublicMarketOrdersNextUpdate() { return publicMarketOrdersNextUpdate; } public void setPublicMarketOrdersNextUpdate(Date publicMarketOrdersNextUpdate) { this.publicMarketOrdersNextUpdate = publicMarketOrdersNextUpdate; } public Date getPublicMarketOrdersLastUpdate() { return publicMarketOrdersLastUpdate; } public void setPublicMarketOrdersLastUpdate(Date publicMarketOrdersLastUpdate) { this.publicMarketOrdersLastUpdate = publicMarketOrdersLastUpdate; } public MarketOrderRange getOutbidOrderRange() { return outbidOrderRange; } public void setOutbidOrderRange(MarketOrderRange sellOrderOutbidRange) { this.outbidOrderRange = sellOrderOutbidRange; } public Map getMarketOrdersOutbid() { return marketOrdersOutbid; } public void setMarketOrdersOutbid(Map marketOrdersOutbid) { this.marketOrdersOutbid = marketOrdersOutbid; } public int getMaximumPurchaseAge() { return maximumPurchaseAge; } public void setMaximumPurchaseAge(final int maximumPurchaseAge) { this.maximumPurchaseAge = maximumPurchaseAge; } public TransactionProfitPrice getTransactionProfitPrice() { return transactionProfitPrice; } public void setTransactionProfitPrice(TransactionProfitPrice transactionProfitPrice) { this.transactionProfitPrice = transactionProfitPrice; } public int getTransactionProfitMargin() { return transactionProfitMargin; } public void setTransactionProfitMargin(int transactionProfitMargin) { this.transactionProfitMargin = transactionProfitMargin; } public boolean isFilterOnEnter() { return filterOnEnter; } public void setFilterOnEnter(final boolean filterOnEnter) { flags.put(SettingFlag.FLAG_FILTER_ON_ENTER, filterOnEnter); //Save & Load this.filterOnEnter = filterOnEnter; } public boolean isHighlightSelectedRows() { //High volume call - Map.get is too slow, use cache return highlightSelectedRows; } public void setHighlightSelectedRows(final boolean highlightSelectedRows) { flags.put(SettingFlag.FLAG_HIGHLIGHT_SELECTED_ROWS, highlightSelectedRows); this.highlightSelectedRows = highlightSelectedRows; } public boolean isIgnoreSecureContainers() { return flags.get(SettingFlag.FLAG_IGNORE_SECURE_CONTAINERS); } public void setIgnoreSecureContainers(final boolean ignoreSecureContainers) { flags.put(SettingFlag.FLAG_IGNORE_SECURE_CONTAINERS, ignoreSecureContainers); } public boolean isReprocessColors() { //High volume call - Map.get is too slow, use cache return reprocessColors; } public void setReprocessColors(final boolean reprocessColors) { flags.put(SettingFlag.FLAG_REPROCESS_COLORS, reprocessColors); this.reprocessColors = reprocessColors; } public boolean isStockpileFocusTab() { return flags.get(SettingFlag.FLAG_STOCKPILE_FOCUS_TAB); } public void setStockpileFocusTab(final boolean stockpileFocusOnAdd) { flags.put(SettingFlag.FLAG_STOCKPILE_FOCUS_TAB, stockpileFocusOnAdd); } public boolean isStockpileHalfColors() { return stockpileHalfColors; } public void setStockpileHalfColors(final boolean stockpileHalfColors) { flags.put(SettingFlag.FLAG_STOCKPILE_HALF_COLORS, stockpileHalfColors); this.stockpileHalfColors = stockpileHalfColors; } public boolean isIncludeSellOrders() { return flags.get(SettingFlag.FLAG_INCLUDE_SELL_ORDERS); } public void setIncludeSellOrders(final boolean includeSellOrders) { flags.put(SettingFlag.FLAG_INCLUDE_SELL_ORDERS, includeSellOrders); } public boolean isIncludeBuyOrders() { return flags.get(SettingFlag.FLAG_INCLUDE_BUY_ORDERS); } public void setIncludeBuyOrders(final boolean includeBuyOrders) { flags.put(SettingFlag.FLAG_INCLUDE_BUY_ORDERS, includeBuyOrders); } public boolean isIncludeBuyContracts() { return flags.get(SettingFlag.FLAG_INCLUDE_BUY_CONTRACTS); } public void setIncludeBuyContracts(final boolean includeBuyContracts) { flags.put(SettingFlag.FLAG_INCLUDE_BUY_CONTRACTS, includeBuyContracts); } public boolean isIncludeSellContracts() { return flags.get(SettingFlag.FLAG_INCLUDE_SELL_CONTRACTS); } public void setIncludeSellContracts(final boolean includeSellContracts) { flags.put(SettingFlag.FLAG_INCLUDE_SELL_CONTRACTS, includeSellContracts); } public boolean isIncludeManufacturing() { return flags.get(SettingFlag.FLAG_INCLUDE_MANUFACTURING); } public boolean setIncludeManufacturing(final boolean includeManufacturing) { return flags.put(SettingFlag.FLAG_INCLUDE_MANUFACTURING, includeManufacturing); } public boolean isIncludeCopying() { return flags.get(SettingFlag.FLAG_INCLUDE_COPYING); } public boolean setIncludeCopying(final boolean includeCopying) { return flags.put(SettingFlag.FLAG_INCLUDE_COPYING, includeCopying); } public boolean isIncludeJumpClones() { return flags.get(SettingFlag.FLAG_INCLUDE_JUMP_CLONES); } public boolean setIncludeJumpClones(final boolean includeJumpClones) { return flags.put(SettingFlag.FLAG_INCLUDE_JUMP_CLONES, includeJumpClones); } public boolean isIncludePluggedInImplants() { return flags.get(SettingFlag.FLAG_INCLUDE_PLUGGED_IN_IMPLANTS); } public boolean setIncludePluggedInImplants(final boolean includePluggedInImplants) { return flags.put(SettingFlag.FLAG_INCLUDE_PLUGGED_IN_IMPLANTS, includePluggedInImplants); } public boolean isBlueprintBasePriceTech1() { return flags.get(SettingFlag.FLAG_BLUEPRINT_BASE_PRICE_TECH_1); } public void setBlueprintBasePriceTech1(final boolean blueprintsTech1) { flags.put(SettingFlag.FLAG_BLUEPRINT_BASE_PRICE_TECH_1, blueprintsTech1); } public boolean isBlueprintBasePriceTech2() { return flags.get(SettingFlag.FLAG_BLUEPRINT_BASE_PRICE_TECH_2); } public void setBlueprintBasePriceTech2(final boolean blueprintsTech2) { flags.put(SettingFlag.FLAG_BLUEPRINT_BASE_PRICE_TECH_2, blueprintsTech2); } public boolean isManufacturingDefault() { return flags.get(SettingFlag.FLAG_MANUFACTURING_DEFAULT); } public void setManufacturingDefault(final boolean manufacturingDefault) { flags.put(SettingFlag.FLAG_MANUFACTURING_DEFAULT, manufacturingDefault); } public boolean isEasyChartColors() { return flags.get(SettingFlag.FLAG_EASY_CHART_COLORS); } public void setEasyChartColors(final boolean easyChartColors) { flags.put(SettingFlag.FLAG_EASY_CHART_COLORS, easyChartColors); } public boolean isToolsLocked() { return flags.get(SettingFlag.FLAG_LOCK_TOOLS); } public void setToolsLocked(final boolean toolsLocked) { flags.put(SettingFlag.FLAG_LOCK_TOOLS, toolsLocked); } public boolean isShowSubpileTree() { return flags.get(SettingFlag.FLAG_SHOW_SUBPILE_TREE); } public void setShowSubpileTree(final boolean showSubpileTree) { flags.put(SettingFlag.FLAG_SHOW_SUBPILE_TREE, showSubpileTree); } public boolean isContainersShowItemID() { return containersShowItemID; } public void setContainersShowItemID(final boolean containersShowItemID) { flags.put(SettingFlag.FLAG_CONTAINERS_SHOW_ITEM_ID, containersShowItemID); this.containersShowItemID = containersShowItemID; } public boolean isTransactionHistory() { return flags.get(SettingFlag.FLAG_TRANSACTION_HISTORY); } public void setTransactionHistory(final boolean transactionHistory) { flags.put(SettingFlag.FLAG_TRANSACTION_HISTORY, transactionHistory); } public boolean isJournalHistory() { return flags.get(SettingFlag.FLAG_JOURNAL_HISTORY); } public void setJournalHistory(final boolean journalHistory) { flags.put(SettingFlag.FLAG_JOURNAL_HISTORY, journalHistory); } public boolean isIndustryJobsHistory() { return flags.get(SettingFlag.FLAG_INDUSTRY_JOBS_HISTORY); } public void setIndustryJobsHistory(final boolean industryJobsHistory) { flags.put(SettingFlag.FLAG_INDUSTRY_JOBS_HISTORY, industryJobsHistory); } public boolean isAssetsContractsOwnerCorporation() { return flags.get(SettingFlag.FLAG_ASSETS_CONTRACTS_OWNER_CORP); } public void setAssetsContractsOwnerCorporation(final boolean assetsContractsOwnerCorporation) { flags.put(SettingFlag.FLAG_ASSETS_CONTRACTS_OWNER_CORP, assetsContractsOwnerCorporation); } public boolean isAssetsContractsOwnerBoth() { return flags.get(SettingFlag.FLAG_ASSETS_CONTRACTS_OWNER_BOTH); } public void setAssetsContractsOwnerBoth(final boolean assetsContractsOwnerBoth) { flags.put(SettingFlag.FLAG_ASSETS_CONTRACTS_OWNER_BOTH, assetsContractsOwnerBoth); } public boolean isColumnValueCache() { return cellValueCache; } public void setCellValueCache(final boolean cellValueCache) { flags.put(SettingFlag.FLAG_CELL_VALUE_CACHE, cellValueCache); this.cellValueCache = cellValueCache; } public boolean isLoadToolsBackground() { return flags.get(SettingFlag.FLAG_LOAD_TOOLS_BACKGROUND); } public void setLoadToolsBackground(final boolean loadToolsBackground) { flags.put(SettingFlag.FLAG_LOAD_TOOLS_BACKGROUND, loadToolsBackground); } public boolean isLoadToolsStartup() { return flags.get(SettingFlag.FLAG_LOAD_TOOLS_STARTUP); } public void setLoadToolsStartup(final boolean loadToolsStartup) { flags.put(SettingFlag.FLAG_LOAD_TOOLS_STARTUP, loadToolsStartup); } public boolean isEveGatecampCheckSet() { return flags.get(SettingFlag.FLAG_EVE_GATECAMP_CHECK_SET); } public void setEveGatecampCheckSet(final boolean eveGatecampCheckSet) { flags.put(SettingFlag.FLAG_EVE_GATECAMP_CHECK_SET, eveGatecampCheckSet); } public boolean isEveGatecampCheckAlwaysOpen() { return flags.get(SettingFlag.FLAG_EVE_GATECAMP_CHECK_ALWAYS_OPEN); } public void setEveGatecampCheckAlwaysOpen(final boolean eveGatecampCheckAlwaysOpen) { flags.put(SettingFlag.FLAG_EVE_GATECAMP_CHECK_ALWAYS_OPEN, eveGatecampCheckAlwaysOpen); } public boolean isEveGatecampCheckNeverOpen() { return flags.get(SettingFlag.FLAG_EVE_GATECAMP_CHECK_NEVER_OPEN); } public void setEveGatecampCheckNeverOpen(final boolean eveGatecampCheckNeverOpen) { flags.put(SettingFlag.FLAG_EVE_GATECAMP_CHECK_NEVER_OPEN, eveGatecampCheckNeverOpen); } public boolean isEveGatecampCheckSecure() { return flags.get(SettingFlag.FLAG_EVE_GATECAMP_CHECK_SECURE); } public void setEveGatecampCheckSecure(final boolean eveGatecampCheckSecure) { flags.put(SettingFlag.FLAG_EVE_GATECAMP_CHECK_SECURE, eveGatecampCheckSecure); } public boolean isEveGatecampCheckUnsecure() { return flags.get(SettingFlag.FLAG_EVE_GATECAMP_CHECK_UNSECURE); } public void setEveGatecampCheckUnsecure(final boolean eveGatecampCheckUnsecure) { flags.put(SettingFlag.FLAG_EVE_GATECAMP_CHECK_UNSECURE, eveGatecampCheckUnsecure); } public boolean isMarketOrderHistory() { return flags.get(SettingFlag.FLAG_MARKET_ORDER_HISTORY); } public void setMarketOrderHistory(final boolean marketOrderHistory) { flags.put(SettingFlag.FLAG_MARKET_ORDER_HISTORY, marketOrderHistory); } public boolean isContractHistory() { return flags.get(SettingFlag.FLAG_SAVE_CONTRACT_HISTORY); } public void setContractHistory(final boolean contractHistory) { flags.put(SettingFlag.FLAG_SAVE_CONTRACT_HISTORY, contractHistory); } public boolean isMiningHistory() { return flags.get(SettingFlag.FLAG_SAVE_MINING_HISTORY); } public void setMiningHistory(final boolean contractHistory) { flags.put(SettingFlag.FLAG_SAVE_MINING_HISTORY, contractHistory); } public MarketOrdersSettings getMarketOrdersSettings() { return marketOrdersSettings; } public boolean isAskedCheckAllTracker() { return flags.get(SettingFlag.FLAG_ASKED_CHECK_ALL_TRACKER); } public void setAskedCheckAllTracker(final boolean checkAllTracker) { flags.put(SettingFlag.FLAG_ASKED_CHECK_ALL_TRACKER, checkAllTracker); } public boolean isTrackerUseAssetPriceForSellOrders() { return flags.get(SettingFlag.FLAG_TRACKER_USE_ASSET_PRICE_FOR_SELL_ORDERS); } public void setTrackerUseAssetPriceForSellOrders(final boolean checkAllTracker) { flags.put(SettingFlag.FLAG_TRACKER_USE_ASSET_PRICE_FOR_SELL_ORDERS, checkAllTracker); } public boolean isFocusEveOnlineOnEsiUiCalls() { return flags.get(SettingFlag.FLAG_FOCUS_EVE_ONLINE_ON_ESI_UI_CALLS); } public void setFocusEveOnlineOnEsiUiCalls(final boolean focusEveOnlineOnEsiUiCalls) { flags.put(SettingFlag.FLAG_FOCUS_EVE_ONLINE_ON_ESI_UI_CALLS, focusEveOnlineOnEsiUiCalls); } public boolean isSaveToolsOnExit() { return flags.get(SettingFlag.FLAG_SAVE_TOOLS_ON_EXIT); } public void setSaveToolsOnExit(final boolean saveToolsOnExit) { flags.put(SettingFlag.FLAG_SAVE_TOOLS_ON_EXIT, saveToolsOnExit); } public List getShowTools() { return showTools; } public ColorSettings getColorSettings() { return colorSettings; } public List getStockpiles() { return stockpiles; } public StockpileGroupSettings getStockpileGroupSettings() { return stockpileGroupSettings; } public int getStockpileColorGroup2() { return stockpileColorGroup2; } public void setStockpileColorGroup2(int stockpileColorGroup1) { this.stockpileColorGroup2 = stockpileColorGroup1; } public int getStockpileColorGroup3() { return stockpileColorGroup3; } public void setStockpileColorGroup3(int stockpileColorGroup2) { this.stockpileColorGroup3 = stockpileColorGroup2; } //Window public Point getWindowLocation() { return windowLocation; } public void setWindowLocation(final Point windowLocation) { this.windowLocation = windowLocation; } public boolean isWindowMaximized() { return windowMaximized; } public void setWindowMaximized(final boolean windowMaximized) { this.windowMaximized = windowMaximized; } public Dimension getWindowSize() { return windowSize; } public void setWindowSize(final Dimension windowSize) { this.windowSize = windowSize; } public boolean isWindowAutoSave() { return windowAutoSave; } public void setWindowAutoSave(final boolean windowAutoSave) { this.windowAutoSave = windowAutoSave; } public boolean isWindowAlwaysOnTop() { return windowAlwaysOnTop; } public void setWindowAlwaysOnTop(final boolean windowAlwaysOnTop) { this.windowAlwaysOnTop = windowAlwaysOnTop; } public boolean isSettingsLoadError() { return settingsLoadError; } public void setSettingsLoadError(boolean settingsLoadError) { this.settingsLoadError = settingsLoadError; } public Map getOverviewGroups() { return overviewGroups; } public static Date getNow() { return new Date(); } public static DateFormat getSettingsDateFormat() { return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); } private static class SettingsLock { private boolean locked = false; private final SettingsQueue settingsQueue = new SettingsQueue(); public boolean ignoreSave() { return settingsQueue.ignoreSave(); } public void saveStart() { settingsQueue.saveStart(); } public void saveEnd() { settingsQueue.saveEnd(); } public void waitForEmptySaveQueue() { settingsQueue.waitForEmptySaveQueue(); } public synchronized void lock(String msg) { while (locked) { try { wait(); } catch (InterruptedException ex) { } } locked = true; LOG.debug("Settings Locked: " + msg); } public synchronized void unlock(String msg) { locked = false; LOG.debug("Settings Unlocked: " + msg); notify(); } } private static class SettingsQueue { private short savesQueue = 0; public synchronized boolean ignoreSave() { LOG.debug("Save Queue: " + savesQueue + " ignore: " + (savesQueue > 1)); return savesQueue > 1; } public synchronized void saveStart() { this.savesQueue++; notifyAll(); } public synchronized void saveEnd() { this.savesQueue--; notifyAll(); } public synchronized void waitForEmptySaveQueue() { while (savesQueue > 0) { try { wait(); } catch (InterruptedException ex) { } } } } private static class EmptySettingsFactory implements SettingsFactory { @Override public Settings create() { return new Settings(); } } public static interface SettingsFactory { public Settings create(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/SettingsUpdateListener.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; /** * Listener for capturing settings updates. */ public interface SettingsUpdateListener { /** * Primary method called on settings update */ void settingChanged(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/StockpileGroupSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile; public class StockpileGroupSettings { //Save/Load private final Map stockpileGroups = new HashMap<>(); private final Map stockpileExpanded = new HashMap<>(); //GUI //List of groups private final Set uniqueGroups = new TreeSet<>(); //List stockpiles in group private final Map> groupStockpiles = new HashMap<>(); //Groups expanded or collapsed private final Map groupExpanded = new HashMap<>(); //The first stockpile in each group private final Map groupFirst = new HashMap<>(); private void updateGroups() { List sortedStockpiles = new ArrayList<>(stockpileGroups.keySet()); Collections.sort(sortedStockpiles); uniqueGroups.clear(); groupStockpiles.clear(); for (Stockpile stockpile : sortedStockpiles) { String group = getGroup(stockpile); uniqueGroups.add(group); List stockpiles = groupStockpiles.get(group); if (stockpiles == null) { stockpiles = new ArrayList<>(); groupStockpiles.put(group, stockpiles); } stockpiles.add(stockpile); } //Remove deleted groups groupExpanded.keySet().retainAll(uniqueGroups); } public Map getStockpileGroups() { return stockpileGroups; } public List getStockpiles(String group) { return groupStockpiles.getOrDefault(group, new ArrayList<>()); } public String getGroup(Stockpile stockpile) { return stockpileGroups.getOrDefault(stockpile, ""); } public void setGroup(Stockpile stockpile, String newGroup) { if (newGroup == null || newGroup.isEmpty()) { return; //Invalid group } stockpileGroups.put(stockpile, newGroup); updateGroups(); } public void removeGroup(Stockpile stockpile) { stockpileGroups.remove(stockpile); stockpileExpanded.remove(stockpile); //No longer part of a group, so no longer tracked updateGroups(); } public Set getGroups() { return uniqueGroups; } public boolean isGroupExpanded(String group) { return groupExpanded.getOrDefault(group, true); } public void setGroupExpanded(String group, boolean expanded) { groupExpanded.put(group, expanded); } public boolean isStockpileExpanded(Stockpile stockpile) { return stockpileExpanded.getOrDefault(stockpile, true); } public void setStockpileExpanded(Stockpile stockpile, boolean expanded) { stockpileExpanded.put(stockpile, expanded); } public void setStockpileExpanded(Collection stockpiles, boolean expanded) { for (Stockpile stockpile: stockpiles) { stockpileExpanded.put(stockpile, expanded); } } public void setGroupFirst(Map groupFirst) { this.groupFirst.clear(); this.groupFirst.putAll(groupFirst); } public boolean isGroupFirst(Stockpile stockpile) { String group = getGroup(stockpile); if (!isGroupExpanded(group)) { return true; //Only one separator, it's always first } Stockpile first = groupFirst.get(group); if (first == null) { return false; } else { return first.equals(stockpile); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/TempDirs.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.io.File; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public enum TempDirs { DEFAULT(System.getProperty("java.io.tmpdir")), //Default USER_HOME(System.getProperty("user.home")), //User Home Directory USER_DIR(System.getProperty("user.dir")), //jEveAssets Working Directory DATA_DIR(FileUtil.getPathDataDirectory()), //jEveAssets Data Directory PROGRAM_DIR(FileUtil.getStaticFile("")), //jEveAssets Program Directory ; private static final Logger LOG = LoggerFactory.getLogger(TempDirs.class); private static boolean fixed = false; private final String dir; private final File file; private TempDirs(String dir) { this.dir = dir; this.file = new File(dir); } public boolean isValid() { return file.exists() && file.isDirectory() && file.canRead() && file.canWrite() && file.canExecute(); } public String getDir() { return dir; } public void setTmpDir() { System.setProperty("java.io.tmpdir", dir); } public static void fixTempDir() { if (fixed) { return; } for (TempDirs tempDirs : TempDirs.values()) { if (tempDirs.isValid()) { tempDirs.setTmpDir(); LOG.info("Using " + tempDirs.name() + " for java.io.tmpdir (" + tempDirs.getDir() + ")"); fixed = true; break; } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/TrackerData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.locks.ReentrantReadWriteLock; import net.nikr.eve.jeveasset.CliOptions; import net.nikr.eve.jeveasset.gui.tabs.values.Value; import net.nikr.eve.jeveasset.io.local.TrackerReader; import net.nikr.eve.jeveasset.io.local.TrackerWriter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TrackerData { private static final Logger LOG = LoggerFactory.getLogger(TrackerData.class); private static final Map> TRACKER_DATA = new HashMap<>(); //ownerID :: long private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock(); private static final Object SAVE_QUEUE_SYNC = new Object(); private static Integer SAVE_QUEUE = 0; public static void readLock() { LOCK.readLock().lock(); } public static void readUnlock() { LOCK.readLock().unlock(); } public static void writeLock() { LOCK.writeLock().lock(); } public static void writeUnlock() { LOCK.writeLock().unlock(); } public static void waitForEmptySaveQueue() { while (!saveQueueEmpty()) { synchronized(SAVE_QUEUE_SYNC) { try { SAVE_QUEUE_SYNC.wait(); } catch (InterruptedException ex) { //No problem } } } } public static void load() { Map> trackerData = TrackerReader.load(); TrackerData.set(trackerData); } public static void save(String msg) { save(msg, false); } public static void save(String msg, boolean wait) { if (saveQueueIgnore()) { return; } saveQueueAdd(); Save save = new Save(msg); save.start(); if (wait) { try { save.join(); } catch (InterruptedException ex) { //No problem } } } public static Map> get() { if (CliOptions.get().isDebug() && LOCK.getReadHoldCount() == 0 && LOCK.getWriteHoldCount() == 0) { throw new RuntimeException("Tracker Data not read locked"); } return TRACKER_DATA; } public static void add(String owner, Value add) { try { LOCK.writeLock().lock(); List list = TRACKER_DATA.get(owner); if (list == null) { list = new ArrayList<>(); TRACKER_DATA.put(owner, list); } list.add(add); } finally { LOCK.writeLock().unlock(); } } public static void addAll(Map> trackerData, boolean overwrite) { try { LOCK.writeLock().lock(); for (Map.Entry> entry : trackerData.entrySet()) { //For each owner String owner = entry.getKey(); List list = TRACKER_DATA.get(owner); if (list == null) { //Owner doesn't exist list = new ArrayList<>(); TRACKER_DATA.put(owner, list); } //Remove duplicates, while staying in order Set set = new TreeSet<>(Value.DATE_COMPARATOR); if (overwrite) { set.addAll(entry.getValue()); //Add new data (First) set.addAll(list); //Add old data (Second, only add if not already contains) } else { set.addAll(list); //Add old data (First) set.addAll(entry.getValue()); //Add new data (Second, only add if not already contains) } list.clear(); //Clear old data list.addAll(set); //Set new merged data } } finally { LOCK.writeLock().unlock(); } } public static void set(Map> trackerData) { if (trackerData == null) { return; } try { LOCK.writeLock().lock(); TRACKER_DATA.clear(); TRACKER_DATA.putAll(trackerData); } finally { LOCK.writeLock().unlock(); } } public static void remove(String owner, Value remove) { try { LOCK.writeLock().lock(); List values = TRACKER_DATA.get(owner); if (values != null) { values.remove(remove); if (values.isEmpty()) { //Remove empty list TRACKER_DATA.remove(owner); } } } finally { LOCK.writeLock().unlock(); } } public static void removeAll(String owner, Collection remove) { try { LOCK.writeLock().lock(); List values = TRACKER_DATA.get(owner); if (values != null) { values.removeAll(remove); if (values.isEmpty()) { //Remove empty list TRACKER_DATA.remove(owner); } } } finally { LOCK.writeLock().unlock(); } } private synchronized static boolean saveQueueIgnore() { return SAVE_QUEUE > 1; } private synchronized static void saveQueueAdd() { SAVE_QUEUE++; synchronized(SAVE_QUEUE_SYNC) { SAVE_QUEUE_SYNC.notifyAll(); } } private synchronized static void saveQueueRemove() { SAVE_QUEUE--; synchronized(SAVE_QUEUE_SYNC) { SAVE_QUEUE_SYNC.notifyAll(); } } private synchronized static boolean saveQueueEmpty() { return SAVE_QUEUE == 0; } private static class Save extends Thread { private final String msg; public Save(String msg) { this.msg = msg; } @Override public void run() { long before = System.currentTimeMillis(); LOG.info("Saving tracker data: " + msg); TrackerData.readLock(); TrackerWriter.save(); TrackerData.readUnlock(); saveQueueRemove(); LOG.debug("Tracker data saved in: " + (System.currentTimeMillis() - before) + "ms"); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/TrackerSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.Date; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerDate; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerNote; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerSkillPointFilter; public class TrackerSettings { public enum ShowOption { ALL, TOTAL, WALLET, ASSET, IMPLANT, SELL_ORDER, ESCROW, ESCROW_TO_COVER, MANUFACTURING, COLLATERAL, CONTRACT, SKILL_POINT; } public enum DisplayType { LINEAR, LOGARITHMIC; } private boolean allProfiles = false; private boolean characterCorporations = false; private DisplayType displayType = DisplayType.LINEAR; private final Map filters = new HashMap<>(); private Date fromDate = null; private boolean includeZero = true; private final Map notes = new HashMap<>(); private boolean selectNew = true; private List selectedOwners = null; private final Set showOptions = EnumSet.noneOf(ShowOption.class); private final Map skillPointFilters = new HashMap<>(); private Date toDate = null; public TrackerSettings() { showOptions.add(ShowOption.ALL); } public boolean isAllProfiles() { return allProfiles; } public void setAllProfiles(boolean allProfiles) { this.allProfiles = allProfiles; } public boolean isCharacterCorporations() { return characterCorporations; } public void setCharacterCorporations(boolean characterCorporations) { this.characterCorporations = characterCorporations; } public DisplayType getDisplayType() { return displayType; } public void setDisplayType(DisplayType displayType) { this.displayType = displayType; } public Map getFilters() { return filters; } public Date getFromDate() { return fromDate; } public void setFromDate(Date fromDate) { this.fromDate = fromDate; } public boolean isIncludeZero() { return includeZero; } public void setIncludeZero(boolean includeZero) { this.includeZero = includeZero; } public Map getNotes() { return notes; } public boolean isSelectNew() { return selectNew; } public void setSelectNew(boolean selectNew) { this.selectNew = selectNew; } public List getSelectedOwners() { return selectedOwners; } public void setSelectedOwners(List trackerOwners) { this.selectedOwners = trackerOwners; } public Set getShowOptions() { return showOptions; } /*** * Helper function to return if the show options has the {@code searchOption}. Null {@code searchOption} will return * false. * @param searchOption The options to look for in the show options. * @return True if the {@code searchOption} is found. False if it is not found or {@code searchOption} is null. */ public boolean hasShowOption(ShowOption searchOption) { if (searchOption == null) { return false; } return this.showOptions.contains(searchOption); } public Map getSkillPointFilters() { return skillPointFilters; } public Date getToDate() { return toDate; } public void setToDate(Date toDate) { this.toDate = toDate; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/UserItem.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; public abstract class UserItem> implements Comparable> { private V value; private String name; private K key; public UserItem(final UserItem item) { this(item.getValue(), item.getKey(), item.getName()); } public UserItem(final V value, final K key, final String name) { this.value = value; this.key = key; this.name = name; } public K getKey() { return key; } public V getValue() { return value; } public void setValue(final V value) { this.value = value; } public String getName() { return name; } public abstract String getValueFormatted(); public abstract int compare(UserItem o1, UserItem o2); @Override public int compareTo(final UserItem o) { return compare(this, o); } @Override public boolean equals(final Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final UserItem other = (UserItem) obj; if (this.value != other.value && (this.value == null || !this.value.equals(other.value))) { return false; } if (this.key != other.key && (this.key == null || !this.key.equals(other.key))) { return false; } return true; } @Override public int hashCode() { int hash = 7; hash = 41 * hash + (this.value != null ? this.value.hashCode() : 0); hash = 41 * hash + (this.key != null ? this.key.hashCode() : 0); return hash; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/tag/Tag.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.tag; import java.util.HashSet; import java.util.Set; public class Tag implements Comparable { private String name; private TagColor color; private final Set ids = new HashSet(); public Tag(String name, TagColor color) { this.name = name; this.color = color; } public String getName() { return name; } public TagColor getColor() { return color; } public final Set getIDs() { return ids; } public void update(Tag tag) { this.name = tag.getName(); this.color = tag.getColor(); } public void setColor(TagColor color) { this.color = color; } @Override public int compareTo(Tag o) { return this.getName().compareToIgnoreCase(o.getName()); } @Override public int hashCode() { int hash = 5; hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Tag other = (Tag) obj; if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/tag/TagColor.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.tag; import java.awt.Color; public class TagColor { private static final TagColor[] VALUES = { new TagColor(Color.WHITE, Color.BLACK), //White and black new TagColor(Color.WHITE, Color.RED.darker().darker()), //White and red new TagColor(Color.WHITE, Color.GREEN.darker().darker()), //White and green new TagColor(Color.WHITE, Color.BLUE.darker().darker()), //White and blue new TagColor(Color.LIGHT_GRAY, Color.BLACK), //Gray new TagColor(Color.BLACK, Color.WHITE), //Black new TagColor(Color.CYAN, Color.BLACK), //Cyan new TagColor(Color.BLUE, Color.WHITE), //Blue new TagColor(Color.MAGENTA, Color.BLACK), //Magenta new TagColor(Color.PINK, Color.BLACK), //Pink new TagColor(Color.RED, Color.BLACK), //Red new TagColor(Color.ORANGE, Color.BLACK), //Orange new TagColor(Color.YELLOW, Color.BLACK), //Yellow new TagColor(Color.GREEN, Color.BLACK), //Green }; private Color backgroundColor; private Color foregroundColor; private String backgroundHtml; private String foregroundHtml; public TagColor(Color background, Color foreground) { this(colorToHex(background), colorToHex(foreground)); } public TagColor(String background, String foreground) { this.backgroundColor = Color.decode("0x"+background); this.foregroundColor = Color.decode("0x"+foreground); this.backgroundHtml = background; this.foregroundHtml = foreground; } public Color getBackground() { return backgroundColor; } public Color getForeground() { return foregroundColor; } public String getBackgroundHtml() { return backgroundHtml; } public String getForegroundHtml() { return foregroundHtml; } public static TagColor[] getValues() { return VALUES; } private static String colorToHex(Color color) { String rgb = Integer.toHexString(color.getRGB()); return rgb.substring(2, rgb.length()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/tag/TagID.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.tag; import java.util.Objects; public class TagID { private final String tool; private final long id; private final double d; public TagID(String tool, long id) { this(tool, id, 0); } public TagID(String tool, long id, double d) { this.tool = tool; this.id = id; this.d = d; } public String getTool() { return tool; } public long getID() { return id; } public double getDouble() { return d; } @Override public int hashCode() { int hash = 5; hash = 67 * hash + Objects.hashCode(this.tool); hash = 67 * hash + (int) (this.id ^ (this.id >>> 32)); hash = 67 * hash + (int) (Double.doubleToLongBits(this.d) ^ (Double.doubleToLongBits(this.d) >>> 32)); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final TagID other = (TagID) obj; if (this.id != other.id) { return false; } if (Double.doubleToLongBits(this.d) != Double.doubleToLongBits(other.d)) { return false; } return Objects.equals(this.tool, other.tool); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/tag/TagUpdate.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.tag; public interface TagUpdate { public void updateTags(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/tag/Tags.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.tag; import ca.odell.glazedlists.GlazedLists; import java.awt.Font; import java.util.Collection; import java.util.Objects; import java.util.TreeSet; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JLabel; import javax.swing.JPanel; import net.nikr.eve.jeveasset.gui.shared.ColorUtil; import net.nikr.eve.jeveasset.i18n.General; public class Tags extends TreeSet implements Comparable{ private static Font emptyFont = null; private static Font plainFont = null; private String tags; private String html; private final JPanel jPanel; private Font font = null; public Tags() { super(GlazedLists.comparableComparator()); jPanel = new JPanel(); BoxLayout layout = new BoxLayout(jPanel, BoxLayout.X_AXIS); jPanel.setLayout(layout); updateTags(); } public static void setFont(Font font) { if (plainFont == null) { plainFont = font; emptyFont = new Font(font.getName(), Font.ITALIC, font.getSize()); } } @Override public boolean add(Tag e) { boolean add = super.add(e); updateTags(); return add; } @Override public boolean addAll(Collection c) { boolean addAll = super.addAll(c); updateTags(); return addAll; } @Override public boolean remove(Object o) { boolean remove = super.remove(o); updateTags(); return remove; } @Override public boolean removeAll(Collection c) { boolean removeAll = super.removeAll(c); updateTags(); return removeAll; } @Override public void clear() { super.clear(); updateTags(); } public final void updateTags() { updateString(); updatePanel(); updateHTML(); } public final void updateFont() { if (font == null || !font.equals(plainFont)) { font = plainFont; updatePanel(); } } private void updateString() { StringBuilder sb = new StringBuilder(); boolean first = true; for (Tag tag : this) { if (first) { first = false; } else { sb.append(" "); } sb.append(tag.getName()); } if (isEmpty()) { tags = General.get().none(); } else { tags = sb.toString(); } } private void updatePanel() { jPanel.removeAll(); boolean first = true; for (Tag tag : this) { if (first) { first = false; } else { jPanel.add(Box.createHorizontalStrut(3)); } JLabel jLabel = new JLabel(tag.getName()); if (plainFont != null) { jLabel.setFont(plainFont); } jLabel.setOpaque(true); jLabel.setBackground(tag.getColor().getBackground()); jLabel.setForeground(tag.getColor().getForeground()); jLabel.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 2)); jPanel.add(jLabel); } if (isEmpty()) { JLabel jLabel = new JLabel(General.get().none()); if (emptyFont != null) { jLabel.setFont(emptyFont); } if (ColorUtil.isBrightColor(jLabel.getBackground())) { //Light background color jLabel.setForeground(jLabel.getBackground().darker().darker().darker()); } else { //Dark background color jLabel.setForeground(jLabel.getBackground().brighter().brighter()); } jPanel.add(jLabel); } } private void updateHTML() { StringBuilder builder = new StringBuilder(); boolean first = true; for (Tag tag : this) { if (first) { first = false; } else { builder.append(" "); } builder.append(""); builder.append(" "); builder.append(tag.getName()); builder.append(" "); builder.append(""); } html = builder.toString(); } public JPanel getPanel() { return jPanel; } public String getHtml() { return html; } @Override public String toString() { return tags; } @Override public int compareTo(Tags o) { if (isEmpty() && o.isEmpty()) { return 0; } else if (isEmpty() && !o.isEmpty()) { return 1; } else if (!isEmpty() && o.isEmpty()) { return -1; } else { return toString().compareTo(o.toString()); } } @Override public int hashCode() { int hash = 3; hash = 89 * hash + Objects.hashCode(this.tags); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Tags other = (Tags) obj; if (!Objects.equals(this.tags, other.tags)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/types/BlueprintType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.types; public interface BlueprintType { public boolean isBPO(); public boolean isBPC(); public int getRuns(); public int getMaterialEfficiency(); public int getTimeEfficiency(); public Integer getTypeID(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/types/CorporationType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.types; public interface CorporationType { public Integer getCorporationID(); public String getCorporationName(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/types/EditableLocationType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.types; import net.nikr.eve.jeveasset.data.sde.MyLocation; public interface EditableLocationType extends LocationType { public void setLocation(MyLocation location); public long getLocationID(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/types/EditablePriceType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.types; import net.nikr.eve.jeveasset.data.sde.Item; public interface EditablePriceType extends PriceType { public void setDynamicPrice(double price); public boolean isBPC(); public Item getItem(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/types/EsiType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.types; public interface EsiType { public boolean archive(); public void setESI(boolean esi); public boolean isESI(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/types/ItemType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.types; import net.nikr.eve.jeveasset.data.sde.Item; public interface ItemType { public Item getItem(); public long getItemCount(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/types/LastTransactionType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.types; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; public interface LastTransactionType { public double getTransactionPrice(); public double getTransactionProfitDifference(); public Percent getTransactionProfitPercent(); default double getTransactionMargin() { return getTransactionPrice() + (getTransactionPrice() / 100.0 * Settings.get().getTransactionProfitMargin()); } public void setTransactionPrice(double transactionPrice); public void setTransactionProfit(double transactionProfit); public void setTransactionProfitPercent(Percent transactionProfitPercent); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/types/LocationType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.types; import net.nikr.eve.jeveasset.data.sde.MyLocation; public interface LocationType { public MyLocation getLocation(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/types/LocationsType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.types; import java.util.Set; import net.nikr.eve.jeveasset.data.sde.MyLocation; public interface LocationsType { public Set getLocations(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/types/MarketDetailType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.types; import javax.swing.JButton; public interface MarketDetailType { public JButton getButton(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/types/OwnersType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.types; import java.util.Set; public interface OwnersType { public Set getOwners(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/types/PriceType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.types; public interface PriceType { public Double getDynamicPrice(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/data/settings/types/TagsType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings.types; import net.nikr.eve.jeveasset.data.settings.tag.TagID; import net.nikr.eve.jeveasset.data.settings.tag.Tags; public interface TagsType { public Tags getTags(); public void setTags(Tags tags); public TagID getTagID(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/AboutDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.URL; import javax.swing.BorderFactory; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.JLabel; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Colors; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.i18n.DialoguesAbout; import net.nikr.eve.jeveasset.io.online.Updater; import net.nikr.eve.jeveasset.io.shared.DesktopUtil; public class AboutDialog extends JDialogCentered { private enum AboutAction { CLOSE } private final JButton jClose; public AboutDialog(final Program program) { super(program, DialoguesAbout.get().about(), Images.DIALOG_ABOUT.getImage()); ListenerClass listener = new ListenerClass(); JLabel jIcon = new JLabel(); jIcon.setIcon(Images.MISC_ASSETS_64.getIcon()); JEditorPane jProgram = createEditorPane(false, "
" + Program.PROGRAM_NAME + "
" + "Copyright © 2009-2026 Contributors
" ); String s = Updater.getPackageMaintainers(); StringBuilder packageManager = new StringBuilder(); if (s != null) { String[] names = s.split(","); packageManager.append("Package Maintainers
"); for (String name : names) { packageManager.append(" "); packageManager.append(name.trim()); packageManager.append("
"); } packageManager.append("
"); } JEditorPane jInfo = createEditorPane( "Version
" + " " + Program.PROGRAM_VERSION + "
" + "
" + "Data
" + " " + program.getProgramDataVersion() + "
" + "
" + "License
" + " GNU General Public License 2.0
" + "
" + "www
" + " Homepage (download and source)
" + " GitHub Project (developers)
" + " Forum Thread (feedback)
" + " Wiki (user documentation)
" + "
" + "Developers
" + " Niklas Kyster Rasmussen (Golden Gnu)
" + " Dultas
" + " Tsuro Tsero
" + "
" + "Testers
" + " Huzid
" + "
" + "Contributors
" + " Flaming Candle
" + " Jochen Bedersdorfer
" + " TryfanMan
" + " Jan
" + " Ima Sohmbadi
" + " Saulvin
" + " AnrDaemon
" + " Madetara (Ray Kavier)
" + " Kaylee Syntax
" + " Inoruuk
" + " Burberius
" + " Lazaren
" + " Boran Lordsworth
" + " Ed Thelleres
" + " Salartarium
" + " WildGear
" + " snipereagle1
" + " Ansirane Solette
" + "
" + "Retired Testers
" + " Varo Jan
" + " Scrapyard Bob
" + " Johann Hemphill
" + " Tomasz (kitsibas) Wiktorski
" + "
" + packageManager.toString() + "Special Thanks
" + " jEveAssets is heavily based on the user interface in EVE Asset Manager by William J. Rogers
" + "
" + "Content
" + " EVE-Online (api and sde)
" + " fuzzwork.co.uk (price data api)
" + " Janice (price data api)
" + " zKillboard (price history api)
" + " EVE Ref (reference data api)
" + " Hoboleaks (data export)
" + " Silk icons (icons)
" + "
" + "Libraries
" + " Glazed Lists (table sorting and filtering)
" + " Super CSV (csv export)
" + " eve-esi (esi endpoints)
" + " LGoodDatePicker (date input)
" + " JFreeChart (charts)
" + " JUnit (unit testing)
" + " slf4J (logging)
" + " logback (logging)
" + " SQLite (database)
" + " FlatLaf (look and feel and native mac os x support)
" + " Pricing (parsing price data api)
" + " Routing (routing tool)
" + " Graph (routing tool)
" + " Translations (i18n)
" + " EvalEx (formula columns)
" + " Picocli (CLI)
" + "
" + "

" ); JScrollPane jInfoScroll = new JScrollPane(jInfo, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); JLabel jPartner = new JLabel(); jPartner.setIcon(Images.MISC_PARTNER.getIcon()); jClose = new JButton(DialoguesAbout.get().close()); jClose.setActionCommand(AboutAction.CLOSE.name()); jClose.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jIcon) .addComponent(jProgram) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jInfoScroll) .addComponent(jPartner, 300, 300, 300) .addComponent(jClose, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jIcon) .addComponent(jProgram) ) .addComponent(jInfoScroll, 300, 300, 300) .addComponent(jPartner, 50, 50, 50) .addComponent(jClose, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } private String getPartyParrot() { URL url = Images.class.getResource(Images.MISC_PARTYPARROT.getFilename()); if (url != null) { return url.toString(); } return ""; } private JEditorPane createEditorPane(final String text) { return createEditorPane(true, text); } private JEditorPane createEditorPane(final boolean addBorder, final String text) { JEditorPane jEditorPane = new JEditorPane("text/html", "
" + text + "
" ); jEditorPane.setEditable(false); jEditorPane.setFocusable(false); jEditorPane.setOpaque(false); jEditorPane.setBackground(Colors.COMPONENT_TRANSPARENT.getColor()); jEditorPane.setFont(jPanel.getFont()); jEditorPane.addHyperlinkListener(DesktopUtil.getHyperlinkListener(getDialog())); if (addBorder) { jEditorPane.setBorder(BorderFactory.createEmptyBorder(11, 11, 11, 11)); } return jEditorPane; } @Override public JComponent getDefaultFocus() { return jClose; } @Override protected JButton getDefaultButton() { return jClose; } @Override protected void windowShown() {} @Override protected void save() { } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (AboutAction.CLOSE.name().equals(e.getActionCommand())) { setVisible(false); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/account/AccountImportDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.account; import java.awt.CardLayout; import java.awt.Color; import java.awt.Font; import java.awt.LayoutManager; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; import java.awt.event.WindowFocusListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Base64; import java.util.EnumMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.ApiType; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.settings.Colors; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.CopyHandler; import net.nikr.eve.jeveasset.gui.shared.components.JCustomFileChooser; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JLabelMultiline; import net.nikr.eve.jeveasset.gui.shared.components.JLabelMultilineHtml; import net.nikr.eve.jeveasset.gui.shared.components.JWorking; import net.nikr.eve.jeveasset.i18n.DialoguesAccount; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.io.esi.EsiAuth; import net.nikr.eve.jeveasset.io.esi.EsiCallbackURL; import net.nikr.eve.jeveasset.io.esi.EsiOwnerGetter; import net.nikr.eve.jeveasset.io.esi.EsiScopes; import net.nikr.eve.jeveasset.io.shared.AccountAdder; import net.nikr.eve.jeveasset.io.shared.AccountAdderAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AccountImportDialog extends JDialogCentered { private static final Logger LOG = LoggerFactory.getLogger(AccountImportDialog.class); private enum AccountImportAction { ADD_KEY_CANCEL, SHARE_TO_CLIPBOARD, SHARE_TO_FILE, SHARE_FROM_CLIPBOARD, SHARE_FROM_FILE, NEXT, PREVIOUS } private enum AccountImportCard { ADD_ESI, SHARE_EXPORT, SHARE_IMPORT, AUTHCODE, BROWSER, VALIDATE, DONE, EXIT } private final AccountManagerDialog apiManager; private enum Result { FAIL_API_FAIL, FAIL_INVALID, FAIL_NOT_ENOUGH_PRIVILEGES, FAIL_WRONG_ENTRY, FAIL_CANCEL, OK_EXIST, //OK OK_EXIST_LIMITED_ACCESS, //OK OK_LIMITED_ACCESS, //OK OK_ACCOUNT_VALID //OK } private enum Share { IMPORT, EXPORT } //EsiPanel private JDropDownButton jScopes; private JRadioButton jCharacter; private JRadioButton jCorporation; private JLabel jCharacterLabel; private JLabel jCorporationLabel; private JCheckBox jWorkaround; //AuthCodePanel private JTextField jAuthCode; //ExportPanel private JTextArea jExport; private JButton jExportClipboard; private JButton jExportFile; //ImportPanel private JTextArea jImport; private JButton jImportClipboard; private JButton jImportFile; //Done private JLabel jResultHeader; private JLabelMultilineHtml jResultText; //Main private final JButton jNext; private final JButton jPrevious; private final CardLayout cardLayout; private final JPanel jContent; private final ListenerClass listener = new ListenerClass(); private final EsiAuth esiAuth = new EsiAuth(); private final JCustomFileChooser jFileChooser; private EsiOwner esiOwner; private EsiOwner editEsiOwner; private AccountImportCard currentCard; private ApiType apiType; private Share share; private AddTask addTask; private final Map scopesMap = new EnumMap<>(EsiScopes.class); public AccountImportDialog(final AccountManagerDialog apiManager, final Program program) { super(program, DialoguesAccount.get().dialogueNameAccountImport(), apiManager.getDialog()); this.apiManager = apiManager; this.getDialog().addWindowFocusListener(listener); jFileChooser = new JCustomFileChooser("txt"); jFileChooser.setMultiSelectionEnabled(false); jFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); cardLayout = new CardLayout(); jContent = new JPanel(cardLayout); jContent.add(new ImportPanel(), AccountImportCard.SHARE_IMPORT.name()); jContent.add(new EsiPanel(), AccountImportCard.ADD_ESI.name()); jContent.add(new AuthCodePanel(), AccountImportCard.AUTHCODE.name()); jContent.add(new BrowserPanel(), AccountImportCard.BROWSER.name()); jContent.add(new ValidatePanel(), AccountImportCard.VALIDATE.name()); jContent.add(new ExportPanel(), AccountImportCard.SHARE_EXPORT.name()); jContent.add(new DonePanel(), AccountImportCard.DONE.name()); jPrevious = new JButton(DialoguesAccount.get().previousArrow()); jPrevious.setActionCommand(AccountImportAction.PREVIOUS.name()); jPrevious.addActionListener(listener); jNext = new JButton(DialoguesAccount.get().nextArrow()); jNext.setActionCommand(AccountImportAction.NEXT.name()); jNext.addActionListener(listener); JButton jCancel = new JButton(DialoguesAccount.get().cancel()); jCancel.setActionCommand(AccountImportAction.ADD_KEY_CANCEL.name()); jCancel.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jContent) .addGroup(layout.createSequentialGroup() .addComponent(jPrevious, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jNext, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addGap(20) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jContent) .addGroup(layout.createParallelGroup() .addComponent(jPrevious, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jNext, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } private String getAuthCode() { return jAuthCode.getText().trim(); } private void focus() { if (currentCard == AccountImportCard.AUTHCODE) { jAuthCode.requestFocusInWindow(); } else if (jNext.isEnabled()) { jNext.requestFocusInWindow(); } else if (jPrevious.isEnabled()) { jNext.requestFocusInWindow(); } } @Override protected JComponent getDefaultFocus() { return jNext; } @Override protected JButton getDefaultButton() { return jNext; } @Override protected void windowShown() { } @Override protected void save() { } public void add() { show(null, AccountImportCard.ADD_ESI, null); } public void shareExport() { show(Share.EXPORT, AccountImportCard.ADD_ESI, null); } public void shareImport() { show(Share.IMPORT, AccountImportCard.SHARE_IMPORT, null); } public void editEsi(final EsiOwner editEsiOwner) { show(null, AccountImportCard.ADD_ESI, editEsiOwner); } private void show(Share share, AccountImportCard accountImportCard, final EsiOwner editEsiOwner) { currentCard = accountImportCard; this.share = share; this.editEsiOwner = editEsiOwner; if (editEsiOwner != null) { //Edit ESI jCharacter.setVisible(false); jCorporation.setVisible(false); if (editEsiOwner.isCorporation()) { jCorporationLabel.setVisible(true); jCharacterLabel.setVisible(false); jCorporation.setSelected(true); } else { jCharacterLabel.setVisible(true); jCorporationLabel.setVisible(false); jCharacter.setSelected(true); } } else { //Add jImport.setText(""); jCharacter.setVisible(true); jCorporation.setVisible(true); jCharacterLabel.setVisible(false); jCorporationLabel.setVisible(false); jCharacter.setSelected(true); } updateTab(); super.setVisible(true); } @Override public void setVisible(final boolean b) { if (b) { add(); } else { super.setVisible(false); } } private Set getScopes() { Set scopes = new HashSet<>(); for (Map.Entry entry : scopesMap.entrySet()) { if (entry.getValue().isSelected()) { scopes.add(entry.getKey().getScope()); } } return scopes; } private void startImport() { if (share == Share.IMPORT) { esiOwner = EsiOwner.create(); try { String code = new String(Base64.getUrlDecoder().decode(jImport.getText().trim()), "UTF-8"); String[] codes = code.split(" "); esiOwner.setAuth(EsiCallbackURL.valueOf(codes[0]), codes[1], null); } catch (UnsupportedEncodingException | IllegalArgumentException | ArrayIndexOutOfBoundsException ex) { LOG.error("Failed to import jEveAssets ESI Key", ex); //Will fail the update, so, we just ignore it here } addTask = new ImportTask(); addTask.addPropertyChangeListener(listener); addTask.execute(); } else if (apiType == ApiType.ESI) { if (editEsiOwner == null) { //Add esiOwner = EsiOwner.create(); } else { //Edit esiOwner = new EsiOwner(editEsiOwner); } addTask = new EsiTask(); addTask.addPropertyChangeListener(listener); addTask.execute(); } } private void showEsiTap() { cardLayout.show(jContent, AccountImportCard.ADD_ESI.name()); jPrevious.setEnabled(false); jWorkaround.setSelected(false); jNext.setEnabled(true); jNext.setText(DialoguesAccount.get().nextArrow()); getDialog().setIconImage(Images.MISC_ESI.getImage()); if (share == Share.EXPORT) { getDialog().setTitle(DialoguesAccount.get().dialogueNameAccountExport()); } else { getDialog().setTitle(DialoguesAccount.get().dialogueNameAccountImport()); } esiAuth.cancelImport(); updateScopes(); focus(); } private void showImportTap() { cardLayout.show(jContent, AccountImportCard.SHARE_IMPORT.name()); jPrevious.setEnabled(false); jNext.setEnabled(true); jNext.setText(DialoguesAccount.get().nextArrow()); getDialog().setIconImage(Images.MISC_ESI.getImage()); getDialog().setTitle(DialoguesAccount.get().dialogueNameAccountImport()); } private void showExportTap() { cardLayout.show(jContent, AccountImportCard.SHARE_EXPORT.name()); jPrevious.setEnabled(true); jNext.setEnabled(true); jNext.setText(DialoguesAccount.get().ok()); try { String value = esiOwner.getCallbackURL().name() + " " + esiOwner.getRefreshToken(); String code = new String(Base64.getUrlEncoder().encode(value.getBytes(StandardCharsets.UTF_8)), "UTF-8").replace("=", ""); jExport.setText(code); jExport.setFocusable(true); jExportClipboard.setEnabled(true); jExportFile.setEnabled(true); } catch (UnsupportedEncodingException ex) { jExport.setText(DialoguesAccount.get().shareExportFail()); jExport.setFocusable(false); jExportClipboard.setEnabled(false); jExportFile.setEnabled(false); } } private void showAuthCodeTab() { cardLayout.show(jContent, AccountImportCard.AUTHCODE.name()); jAuthCode.setText(""); jPrevious.setEnabled(true); jNext.setEnabled(true); jNext.setText(DialoguesAccount.get().nextArrow()); } private void showBrowserTab() { cardLayout.show(jContent, AccountImportCard.BROWSER.name()); jPrevious.setEnabled(true); jNext.setEnabled(false); jNext.setText(DialoguesAccount.get().nextArrow()); startImport(); } private void showValidateTab() { cardLayout.show(jContent, AccountImportCard.VALIDATE.name()); jPrevious.setEnabled(true); jNext.setEnabled(false); jNext.setText(DialoguesAccount.get().nextArrow()); } private void showDoneTab() { jPrevious.setEnabled(true); if (share == Share.EXPORT) { jNext.setText(DialoguesAccount.get().nextArrow()); } else { jNext.setText(DialoguesAccount.get().ok()); } cardLayout.show(jContent, AccountImportCard.DONE.name()); } private void done() { if (apiType == ApiType.ESI && share != Share.EXPORT) { List existingEsiOwners = getExistingEsiOwners(); if (!existingEsiOwners.isEmpty()) { //Update for (EsiOwner owner : existingEsiOwners) { owner.updateAuth(esiOwner); } } else { if (editEsiOwner != null) { //Add & Edit program.getProfileManager().getEsiOwners().remove(editEsiOwner); } program.getProfileManager().getEsiOwners().add(esiOwner); } apiManager.forceUpdate(); apiManager.updateTable(); } this.setVisible(false); } private void updateTab() { switch (currentCard) { case ADD_ESI: apiType = ApiType.ESI; showEsiTap(); break; case AUTHCODE: showAuthCodeTab(); break; case BROWSER: showBrowserTab(); break; case VALIDATE: if (apiType == ApiType.ESI) { //Move to front getDialog().setAlwaysOnTop(true); getDialog().setAlwaysOnTop(false); } showValidateTab(); break; case DONE: showDoneTab(); break; case SHARE_IMPORT: apiType = ApiType.ESI; showImportTap(); break; case SHARE_EXPORT: showExportTap(); break; case EXIT: done(); break; } } private void updateScopes() { scopesMap.clear(); jScopes.removeAll(); for (EsiScopes scope : EsiScopes.values()) { if (scope.isPublicScope()) { continue; } if (jCharacter.isSelected() && !scope.isCharacterScope()) { continue; } if (jCorporation.isSelected() && !scope.isCorporationScope()) { continue; } JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem(scope.toString()); jCheckBoxMenuItem.setSelected(true); jCheckBoxMenuItem.setEnabled(!scope.isForced()); jCheckBoxMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { boolean enabled = false; for (Map.Entry entry : scopesMap.entrySet()) { if (entry.getValue().isSelected() && !entry.getKey().isForced()) { enabled = true; break; } } jNext.setEnabled(enabled); } }); jScopes.add(jCheckBoxMenuItem, true); scopesMap.put(scope, jCheckBoxMenuItem); } } private List getExistingEsiOwners() { List esiOwners = new ArrayList<>(); for (EsiOwner owner : program.getProfileManager().getEsiOwners()) { if (Objects.equals(owner.getOwnerID(), esiOwner.getOwnerID())) { esiOwners.add(owner); } } return esiOwners; } private class ListenerClass implements ActionListener, PropertyChangeListener, WindowFocusListener { @Override public void actionPerformed(final ActionEvent e) { if (AccountImportAction.ADD_KEY_CANCEL.name().equals(e.getActionCommand())) { if (addTask != null) { addTask.cancel(true); } esiAuth.cancelImport(); setVisible(false); } else if (AccountImportAction.PREVIOUS.name().equals(e.getActionCommand())) { switch (currentCard) { case ADD_ESI: //Previous: None currentCard = AccountImportCard.ADD_ESI; break; case AUTHCODE: //Previous: Add if (share == Share.IMPORT) { currentCard = AccountImportCard.SHARE_IMPORT; } else if (apiType == ApiType.ESI) { currentCard = AccountImportCard.ADD_ESI; } if (addTask != null) { addTask.cancel(true); } break; case BROWSER: //Previous: Add if (share == Share.IMPORT) { currentCard = AccountImportCard.SHARE_IMPORT; } else if (apiType == ApiType.ESI) { currentCard = AccountImportCard.ADD_ESI; } if (addTask != null) { addTask.cancel(true); } break; case VALIDATE: //Previous: Add if (share == Share.IMPORT) { currentCard = AccountImportCard.SHARE_IMPORT; } else if (apiType == ApiType.ESI) { currentCard = AccountImportCard.ADD_ESI; } if (addTask != null) { addTask.cancel(true); } break; case DONE: //Previous: Add if (share == Share.IMPORT) { currentCard = AccountImportCard.SHARE_IMPORT; } else if (apiType == ApiType.ESI) { currentCard = AccountImportCard.ADD_ESI; } break; case SHARE_EXPORT: if (jResultHeader.getText().isEmpty()) { currentCard = AccountImportCard.ADD_ESI; } else { currentCard = AccountImportCard.DONE; } break; case EXIT: //Previous: Exit currentCard = AccountImportCard.EXIT; break; } updateTab(); } else if (AccountImportAction.NEXT.name().equals(e.getActionCommand())) { switch (currentCard) { case ADD_ESI: //Next: Validate Set scopes = getScopes(); if (esiAuth.isServerStarted() && !jWorkaround.isSelected()) { //Localhost esiAuth.openWebpage(EsiCallbackURL.LOCALHOST, scopes, getDialog()); currentCard = AccountImportCard.BROWSER; } else { esiAuth.openWebpage(EsiCallbackURL.EVE_NIKR_NET, scopes, getDialog()); currentCard = AccountImportCard.AUTHCODE; } break; case SHARE_IMPORT: //Next: Browser currentCard = AccountImportCard.VALIDATE; startImport(); break; case AUTHCODE: //Next Validate currentCard = AccountImportCard.VALIDATE; startImport(); break; case BROWSER: //Next Validate currentCard = AccountImportCard.VALIDATE; break; case VALIDATE: //Next Done currentCard = AccountImportCard.DONE; break; case DONE: //Next Exit if (share == Share.EXPORT) { currentCard = AccountImportCard.SHARE_EXPORT; } else { currentCard = AccountImportCard.EXIT; } break; case SHARE_EXPORT: currentCard = AccountImportCard.EXIT; break; case EXIT: //Next Exit currentCard = AccountImportCard.EXIT; break; } updateTab(); } else if (AccountImportAction.SHARE_TO_CLIPBOARD.name().equals(e.getActionCommand())) { CopyHandler.toClipboard(jExport.getText()); } else if (AccountImportAction.SHARE_TO_FILE.name().equals(e.getActionCommand())) { File file = jFileChooser.getSelectedFile(); if (file != null) { jFileChooser.setSelectedFile(new File("")); jFileChooser.setCurrentDirectory(file.getParentFile()); } int showSaveDialog = jFileChooser.showSaveDialog(getDialog()); if (showSaveDialog == JCustomFileChooser.APPROVE_OPTION) { BufferedWriter writer = null; try { writer = new BufferedWriter(new FileWriter(jFileChooser.getSelectedFile())); writer.write(jExport.getText()); writer.close(); } catch (IOException ex) { JOptionPane.showMessageDialog(getDialog(), GuiShared.get().textSaveFailMsg(), GuiShared.get().textSaveFailTitle(), JOptionPane.WARNING_MESSAGE); } finally { if (writer != null) { try { writer.close(); } catch (IOException ex) { //Ohh well we tried our best } } } } } else if (AccountImportAction.SHARE_FROM_CLIPBOARD.name().equals(e.getActionCommand())) { String s = CopyHandler.fromClipboard(); if (s != null) { jImport.setText(s); } } else if (AccountImportAction.SHARE_FROM_FILE.name().equals(e.getActionCommand())) { File file = jFileChooser.getSelectedFile(); if (file != null) { jFileChooser.setSelectedFile(new File("")); jFileChooser.setCurrentDirectory(file.getParentFile()); } int showSaveDialog = jFileChooser.showOpenDialog(getDialog()); if (showSaveDialog == JCustomFileChooser.APPROVE_OPTION) { BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(jFileChooser.getSelectedFile())); String line; StringBuilder builder = new StringBuilder(); while ((line = reader.readLine()) != null) { builder.append(line); builder.append("\r\n"); } jImport.setText(builder.toString()); } catch (IOException ex) { JOptionPane.showMessageDialog(getDialog(), GuiShared.get().textLoadFailMsg(), GuiShared.get().textLoadFailTitle(), JOptionPane.WARNING_MESSAGE); } finally { try { if (reader != null) { reader.close(); } } catch (IOException ex) { //Ohh well we tried our best } } } } } @Override public void propertyChange(final PropertyChangeEvent evt) { Object o = evt.getSource(); if (o instanceof AddTask) { AddTask addTask = (AddTask) o; if (addTask.done) { addTask.done = false; switch (addTask.result) { case FAIL_API_FAIL: currentCard = AccountImportCard.DONE; jNext.setEnabled(false); jResultHeader.setText(DialoguesAccount.get().failApiError()); jResultText.setText(DialoguesAccount.get().failApiErrorText(addTask.error)); break; case FAIL_INVALID: currentCard = AccountImportCard.DONE; jNext.setEnabled(false); jResultHeader.setText(DialoguesAccount.get().failNotValid()); jResultText.setText(DialoguesAccount.get().failNotValidText()); break; case FAIL_NOT_ENOUGH_PRIVILEGES: currentCard = AccountImportCard.DONE; jNext.setEnabled(false); jResultHeader.setText(DialoguesAccount.get().failNotEnoughPrivileges()); jResultText.setText(DialoguesAccount.get().failNotEnoughPrivilegesText()); break; case FAIL_WRONG_ENTRY: currentCard = AccountImportCard.DONE; jNext.setEnabled(false); jResultHeader.setText(DialoguesAccount.get().failWrongEntry()); jResultText.setText(DialoguesAccount.get().failWrongEntryText()); break; case FAIL_CANCEL: switch(apiType) { case ESI: currentCard = AccountImportCard.ADD_ESI; break; } break; case OK_EXIST: currentCard = AccountImportCard.DONE; jNext.setEnabled(true); jResultHeader.setText(DialoguesAccount.get().okUpdate()); jResultText.setText(DialoguesAccount.get().okUpdateText()); break; case OK_EXIST_LIMITED_ACCESS: currentCard = AccountImportCard.DONE; jNext.setEnabled(true); jResultHeader.setText(DialoguesAccount.get().okUpdate()); jResultText.setText(DialoguesAccount.get().okUpdateLimitedText()); break; case OK_LIMITED_ACCESS: currentCard = AccountImportCard.DONE; jNext.setEnabled(true); jResultHeader.setText(DialoguesAccount.get().okLimited()); if (share == Share.EXPORT) { jResultText.setText(DialoguesAccount.get().okLimitedExportText()); } else { jResultText.setText(DialoguesAccount.get().okLimitedText()); } break; case OK_ACCOUNT_VALID: jNext.setEnabled(true); if (share == Share.EXPORT) { currentCard = AccountImportCard.SHARE_EXPORT; jResultHeader.setText(""); jResultText.setText(""); } else { currentCard = AccountImportCard.DONE; jResultHeader.setText(DialoguesAccount.get().okValid()); jResultText.setText(DialoguesAccount.get().okValidText()); } break; } updateTab(); } } } @Override public void windowGainedFocus(final WindowEvent e) { focus(); } @Override public void windowLostFocus(final WindowEvent e) { } } private class EsiPanel extends JCardPanel { public EsiPanel() { JLabel jAuthLabel = new JLabel(DialoguesAccount.get().authorize()); JLabel jType = new JLabel(DialoguesAccount.get().accountType()); ButtonGroup type = new ButtonGroup(); jCharacterLabel = new JLabel(DialoguesAccount.get().character()); jCharacter = new JRadioButton(DialoguesAccount.get().character()); jCharacter.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateScopes(); } }); type.add(jCharacter); jCorporationLabel = new JLabel(DialoguesAccount.get().corporation()); jCorporation = new JRadioButton(DialoguesAccount.get().corporation()); jCorporation.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateScopes(); } }); type.add(jCorporation); jScopes = new JDropDownButton(DialoguesAccount.get().scopes(), Images.MISC_ESI.getIcon(), JDropDownButton.LEFT, JDropDownButton.TOP); JLabel jWorkaroundLabel = new JLabel(DialoguesAccount.get().workaroundLabel()); jWorkaround = new JCheckBox(DialoguesAccount.get().workaroundCheckbox()); JLabelMultiline jHelp = new JLabelMultiline(DialoguesAccount.get().esiHelpText()); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(jHelp) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jAuthLabel) .addComponent(jType) .addComponent(jWorkaroundLabel) ) .addGroup(layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addComponent(jCharacter) .addComponent(jCorporation) .addComponent(jCharacterLabel) .addComponent(jCorporationLabel) ) .addComponent(jScopes, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jWorkaround) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jHelp, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(jType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCharacter, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCorporation, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCharacterLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCorporationLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(jAuthLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jScopes, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(jWorkaroundLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jWorkaround, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } } private class AuthCodePanel extends JCardPanel { public AuthCodePanel() { JLabel jAuthCodeLabel = new JLabel(DialoguesAccount.get().authCode()); jAuthCode = new JTextField(); JLabelMultiline jHelp = new JLabelMultiline(DialoguesAccount.get().authCodeHelpText()); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(jHelp) .addGroup(layout.createSequentialGroup() .addComponent(jAuthCodeLabel) .addComponent(jAuthCode, 150, 150, Integer.MAX_VALUE) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jHelp, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(jAuthCodeLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jAuthCode, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(10, 10, Integer.MAX_VALUE) ); } } private class BrowserPanel extends JCardPanel { public BrowserPanel() { JLabelMultiline jHelp = new JLabelMultiline(DialoguesAccount.get().browseHelpText()); layout.setHorizontalGroup( layout.createSequentialGroup() .addGap(10, 10, Integer.MAX_VALUE) .addComponent(jHelp) .addGap(10, 10, Integer.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGap(10, 10, Integer.MAX_VALUE) .addComponent(jHelp) .addGap(10, 10, Integer.MAX_VALUE) ); } } private class ValidatePanel extends JCardPanel { public ValidatePanel() { JLabel jHelp = new JLabel(DialoguesAccount.get().validatingMessage()); JWorking jWorking = new JWorking(); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addGroup(layout.createSequentialGroup() .addGap(10, 10, Integer.MAX_VALUE) .addComponent(jWorking) .addGap(10, 10, Integer.MAX_VALUE) ) .addGroup(layout.createSequentialGroup() .addGap(10, 10, Integer.MAX_VALUE) .addComponent(jHelp) .addGap(10, 10, Integer.MAX_VALUE) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGap(10, 10, Integer.MAX_VALUE) .addComponent(jWorking) .addComponent(jHelp) .addGap(10, 10, Integer.MAX_VALUE) ); } } private class DonePanel extends JCardPanel { public DonePanel() { jResultHeader = new JLabel(); jResultHeader.setFont(new Font(this.getFont().getName(), Font.BOLD, this.getFont().getSize())); jResultText = new JLabelMultilineHtml(getDialog()); jResultText.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); JScrollPane jScroll = new JScrollPane(jResultText, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); jScroll.setBorder(BorderFactory.createLineBorder(this.getBackground().darker(), 1)); layout.setHorizontalGroup( layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addGap(5) .addComponent(jResultHeader) ) .addComponent(jScroll, 400, 400, 400) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jResultHeader, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jScroll, 98, 98, 98) ); } } private class ImportPanel extends JCardPanel { public ImportPanel() { JLabelMultiline jHelp = new JLabelMultiline(DialoguesAccount.get().shareImportHelpText()); jImportClipboard = new JButton(DialoguesAccount.get().shareImportClipboard() , Images.EDIT_PASTE.getIcon()); jImportClipboard.setActionCommand(AccountImportAction.SHARE_FROM_CLIPBOARD.name()); jImportClipboard.addActionListener(listener); jImportFile = new JButton(DialoguesAccount.get().shareImportFile(), Images.FILTER_LOAD.getIcon()); jImportFile.setActionCommand(AccountImportAction.SHARE_FROM_FILE.name()); jImportFile.addActionListener(listener); jImport = new JTextArea(); jImport.setFont(getFont()); jImport.setEditable(true); jImport.setFocusable(true); jImport.setOpaque(true); jImport.setLineWrap(true); jImport.setWrapStyleWord(false); JScrollPane jScroll = new JScrollPane(jImport, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); jScroll.setBorder(BorderFactory.createLineBorder(this.getBackground().darker(), 1)); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(jHelp) .addGroup(layout.createSequentialGroup() .addComponent(jScroll) .addGroup(layout.createParallelGroup() .addComponent(jImportClipboard, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jImportFile, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jHelp, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addGroup(layout.createParallelGroup() .addComponent(jScroll) .addGroup(layout.createSequentialGroup() .addComponent(jImportClipboard, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jImportFile, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ) ); } } private class ExportPanel extends JCardPanel { public ExportPanel() { JLabel jHelp = new JLabel(DialoguesAccount.get().shareExportHelp() ); jExportClipboard = new JButton(DialoguesAccount.get().shareExportClipboard(), Images.EDIT_COPY.getIcon()); jExportClipboard.setActionCommand(AccountImportAction.SHARE_TO_CLIPBOARD.name()); jExportClipboard.addActionListener(listener); jExportFile = new JButton(DialoguesAccount.get().shareExportFile(), Images.FILTER_SAVE.getIcon()); jExportFile.setActionCommand(AccountImportAction.SHARE_TO_FILE.name()); jExportFile.addActionListener(listener); jExport = new JTextArea(); jExport.setFont(getFont()); jExport.setEditable(false); jExport.setFocusable(true); jExport.setOpaque(false); jExport.setBackground(Colors.COMPONENT_TRANSPARENT.getColor()); jExport.setLineWrap(true); jExport.setWrapStyleWord(false); JScrollPane jScroll = new JScrollPane(jExport, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); jScroll.setBorder(BorderFactory.createLineBorder(this.getBackground().darker(), 1)); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(jHelp) .addGroup(layout.createSequentialGroup() .addComponent(jScroll) .addGroup(layout.createParallelGroup() .addComponent(jExportClipboard, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jExportFile, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jHelp) .addGroup(layout.createParallelGroup() .addComponent(jScroll) .addGroup(layout.createSequentialGroup() .addComponent(jExportClipboard, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jExportFile, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ) ); } } private abstract class JCardPanel extends JPanel { protected GroupLayout layout; public JCardPanel() { layout = new GroupLayout(this); setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(false); } @Override public final Font getFont() { return super.getFont(); } @Override public final Color getBackground() { return super.getBackground(); } @Override public final void setLayout(LayoutManager mgr) { super.setLayout(mgr); } } class ImportTask extends AddTask { private final EsiOwnerGetter esiOwnerGetter = new EsiOwnerGetter(esiOwner, true); @Override public boolean exist() { if (editEsiOwner != null) { return false; } for (EsiOwner owner : program.getProfileManager().getEsiOwners()) { if (Objects.equals(owner.getOwnerID(), esiOwner.getOwnerID())) { return true; } } return false; } @Override public void load() { esiOwnerGetter.start(); } @Override public AccountAdder getAccountAdder() { return esiOwnerGetter; } } class EsiTask extends AddTask { private final EsiOwnerGetter esiOwnerGetter = new EsiOwnerGetter(esiOwner, true); private AccountAdder accountAdder; @Override public boolean exist() { if (editEsiOwner != null) { return false; } if (share == Share.EXPORT) { return false; } for (EsiOwner owner : program.getProfileManager().getEsiOwners()) { if (Objects.equals(owner.getOwnerID(), esiOwner.getOwnerID())) { return true; } } return false; } @Override public void load() { boolean ok = esiAuth.finishFlow(esiOwner, getAuthCode()); if (!ok) { accountAdder = new AccountAdderAdapter() { @Override public boolean hasError() { return true; } @Override public boolean isInvalid() { return true; } }; return; } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { currentCard = AccountImportCard.VALIDATE; updateTab(); } }); accountAdder = esiOwnerGetter; esiOwnerGetter.start(); } @Override public AccountAdder getAccountAdder() { return accountAdder; } } abstract static class AddTask extends SwingWorker { private Result result = null; private boolean done = false; private String error = ""; public abstract boolean exist(); public abstract void load(); public abstract AccountAdder getAccountAdder(); @Override public final Void doInBackground() { setProgress(0); load(); if (getAccountAdder().hasError() || getAccountAdder().isPrivilegesInvalid()) { //Failed to add new account String s = getAccountAdder().getError(); if (getAccountAdder().isInvalid()) { //invalid account result = Result.FAIL_INVALID; } else if (getAccountAdder().isPrivilegesInvalid()) { // Not enough privileges result = Result.FAIL_NOT_ENOUGH_PRIVILEGES; } else if (getAccountAdder().isWrongEntry()) { // Editing account to a different character/corporation result = Result.FAIL_WRONG_ENTRY; } else { //String error error = s; result = Result.FAIL_API_FAIL; } } else { //Successfully added new account if (exist()) { //account already exist if (getAccountAdder().isPrivilegesLimited()) { result = Result.OK_EXIST_LIMITED_ACCESS; //limited privileges } else { result = Result.OK_EXIST; } } else if (getAccountAdder().isPrivilegesLimited()) { //limited privileges result = Result.OK_LIMITED_ACCESS; } else { //All okay result = Result.OK_ACCOUNT_VALID; } } return null; } @Override public final void done() { try { get(); } catch (CancellationException ex) { result = Result.FAIL_CANCEL; } catch (InterruptedException | ExecutionException ex) { LOG.error(ex.getMessage(), ex); throw new RuntimeException(ex); } done = true; setProgress(100); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/account/AccountManagerDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.account; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.GroupLayout.Alignment; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.gui.dialogs.account.AccountSeparatorTableCell.AccountCellAction; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow.LockWorkerAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JSeparatorTable; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.DialoguesAccount; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.io.local.profile.ProfileDatabase; import net.troja.eve.esi.ApiClientBuilder; import net.troja.eve.esi.auth.OAuth; public class AccountManagerDialog extends JDialogCentered { private enum AccountManagerAction { ADD, REVALIDATE, SHARE_EXPORT, SHARE_IMPORT, CLOSE, COLLAPSE, EXPAND, CHECK_ALL, UNCHECK_ALL, CHECK_SELECTED, UNCHECK_SELECTED } //GUI private final AccountImportDialog accountImportDialog; private final JSeparatorTable jTable; private final JButton jAdd; private final JButton jRevalidate; private final JButton jExpand; private final JButton jCollapse; private final JDropDownButton jAssets; private final JButton jClose; private final EventList eventList; private final DefaultEventTableModel tableModel; private final SeparatorList separatorList; private final DefaultEventSelectionModel selectionModel; private final JLockWindow jLockWindow; private final JLockWindow jRevalidateLock; private final Map ownersShownCache = new HashMap<>(); private boolean updated = false; public AccountManagerDialog(final Program program) { super(program, DialoguesAccount.get().dialogueNameAccountManagement(), Images.DIALOG_ACCOUNTS.getImage()); accountImportDialog = new AccountImportDialog(this, program); jLockWindow = new JLockWindow(program.getMainWindow().getFrame()); jRevalidateLock = new JLockWindow(getDialog()); ListenerClass listener = new ListenerClass(); eventList = EventListManager.create(); eventList.getReadWriteLock().readLock().lock(); separatorList = new SeparatorList<>(eventList, new SeparatorListComparator(), 1, 3); eventList.getReadWriteLock().readLock().unlock(); tableModel = EventModels.createTableModel(separatorList, TableFormatFactory.accountTableFormat()); jTable = new JAccountTable(program, tableModel, separatorList); jTable.getTableHeader().setReorderingAllowed(false); jTable.setSeparatorRenderer(new AccountSeparatorTableCell(this, listener, jTable, separatorList)); jTable.setSeparatorEditor(new AccountSeparatorTableCell(this, listener, jTable, separatorList)); JScrollPane jTableScroll = new JScrollPane(jTable); jTableScroll.getVerticalScrollBar().setUnitIncrement(19); selectionModel = EventModels.createSelectionModel(separatorList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Buttons jAdd = new JButton(DialoguesAccount.get().add()); jAdd.setActionCommand(AccountManagerAction.ADD.name()); jAdd.addActionListener(listener); jRevalidate = new JButton(DialoguesAccount.get().revalidate()); jRevalidate.setActionCommand(AccountManagerAction.REVALIDATE.name()); jRevalidate.addActionListener(listener); JDropDownButton jShare = new JDropDownButton(DialoguesAccount.get().share()); JMenuItem jExport = new JMenuItem(DialoguesAccount.get().shareExport(), Images.MISC_ESI.getIcon()); jExport.setActionCommand(AccountManagerAction.SHARE_EXPORT.name()); jExport.addActionListener(listener); jShare.add(jExport); JMenuItem jImport = new JMenuItem(DialoguesAccount.get().shareImport(), Images.TOOL_ASSETS.getIcon()); jImport.setActionCommand(AccountManagerAction.SHARE_IMPORT.name()); jImport.addActionListener(listener); jShare.add(jImport); jCollapse = new JButton(DialoguesAccount.get().collapse()); jCollapse.setActionCommand(AccountManagerAction.COLLAPSE.name()); jCollapse.addActionListener(listener); jExpand = new JButton(DialoguesAccount.get().expand()); jExpand.setActionCommand(AccountManagerAction.EXPAND.name()); jExpand.addActionListener(listener); jAssets = new JDropDownButton(DialoguesAccount.get().showAssets()); JMenuItem menuItem; menuItem = new JMenuItem(DialoguesAccount.get().checkAll()); menuItem.setActionCommand(AccountManagerAction.CHECK_ALL.name()); menuItem.addActionListener(listener); jAssets.add(menuItem); menuItem = new JMenuItem(DialoguesAccount.get().uncheckAll()); menuItem.setActionCommand(AccountManagerAction.UNCHECK_ALL.name()); menuItem.addActionListener(listener); jAssets.add(menuItem); jAssets.addSeparator(); menuItem = new JMenuItem(DialoguesAccount.get().checkSelected()); menuItem.setActionCommand(AccountManagerAction.CHECK_SELECTED.name()); menuItem.addActionListener(listener); jAssets.add(menuItem); menuItem = new JMenuItem(DialoguesAccount.get().uncheckSelected()); menuItem.setActionCommand(AccountManagerAction.UNCHECK_SELECTED.name()); menuItem.addActionListener(listener); jAssets.add(menuItem); //Done Button jClose = new JButton(DialoguesAccount.get().close()); jClose.setActionCommand(AccountManagerAction.CLOSE.name()); jClose.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup() .addGroup(layout.createParallelGroup(Alignment.TRAILING) .addComponent(jTableScroll, 750, 750, Short.MAX_VALUE) .addComponent(jClose, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) .addGroup(layout.createSequentialGroup() .addComponent(jAdd, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jRevalidate, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jShare, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCollapse, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jExpand, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addGap(0, 0, Short.MAX_VALUE) .addComponent(jAssets, Program.getButtonsWidth() + 20, Program.getButtonsWidth() + 20, Program.getButtonsWidth() + 20) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jAdd, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRevalidate, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jShare, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCollapse, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jExpand, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jAssets, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jTableScroll, 450, 450, Short.MAX_VALUE) .addComponent(jClose, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); // Pack then take the dialog dimensions to use as the minimum dimension. getDialog().pack(); Dimension d = new Dimension(getDialog().getWidth() + 10, getDialog().getHeight() + 10); // Use 10 pixel buffer to offset the resize 'bug'. getDialog().setMinimumSize(d); getDialog().setResizable(true); } public void forceUpdate() { updated = true; } public void updateTable() { //Collect owners List ownerTypes = new ArrayList<>(); //ESI ownerTypes.addAll(program.getProfileManager().getEsiOwners()); //Update rows (Add all rows) try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(ownerTypes); } finally { eventList.getReadWriteLock().writeLock().unlock(); } //Revalidate boolean invalid = false; for (EsiOwner owner : program.getProfileManager().getEsiOwners()) { if (owner.isInvalid()) { invalid = true; break; //search done } } jRevalidate.setEnabled(invalid); if (!ownerTypes.isEmpty()) { jTable.setRowSelectionInterval(1, 1); jAssets.setEnabled(true); jCollapse.setEnabled(true); jExpand.setEnabled(true); } else { jAssets.setEnabled(false); jCollapse.setEnabled(false); jExpand.setEnabled(false); } } private void checkAssets(final boolean selected, final boolean check) { if (selected) { //Set selected to check value int[] selectedRows = jTable.getSelectedRows(); for (int i = 0; i < selectedRows.length; i++) { Object o = tableModel.getElementAt(selectedRows[i]); if (o instanceof OwnerType) { OwnerType owner = (OwnerType) o; if (!owner.getOwnerName().equals(DialoguesAccount.get().noOwners())) { owner.setShowOwner(check); } } } } else { //Set all the check value for (OwnerType owner : program.getOwnerTypes()) { if (!owner.getOwnerName().equals(DialoguesAccount.get().noOwners())) { owner.setShowOwner(check); } } } for (int row = 0; row < jTable.getRowCount(); row++) { tableModel.fireTableCellUpdated(row, 0); } } @Override protected JComponent getDefaultFocus() { return jAdd; } @Override protected JButton getDefaultButton() { return jClose; } @Override protected void windowShown() { if (program.getOwnerTypes().isEmpty()) { accountImportDialog.add(); } } @Override protected void save() { super.setVisible(false); if (!updated) { Map ownersShownNow = new HashMap<>(); for (OwnerType ownerType : program.getProfileManager().getOwnerTypes()) { ownersShownNow.put(ownerType, ownerType.isShowOwner()); } updated = !ownersShownNow.equals(ownersShownCache); } if (updated) { jLockWindow.show(GuiShared.get().updating(), new LockWorkerAdaptor() { @Override public void task() { program.saveTable(ProfileDatabase.Table.OWNERS); program.updateEventLists(); } }); } } @Override public void setVisible(final boolean b) { if (b) { updated = false; ownersShownCache.clear(); for (OwnerType ownerType : program.getProfileManager().getOwnerTypes()) { ownersShownCache.put(ownerType, ownerType.isShowOwner()); } updateTable(); super.setVisible(b); } else { save(); } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (AccountManagerAction.ADD.name().equals(e.getActionCommand())) { accountImportDialog.add(); } else if (AccountManagerAction.SHARE_EXPORT.name().equals(e.getActionCommand())) { accountImportDialog.shareExport(); } else if (AccountManagerAction.SHARE_IMPORT.name().equals(e.getActionCommand())) { accountImportDialog.shareImport(); } else if (AccountManagerAction.COLLAPSE.name().equals(e.getActionCommand())) { jTable.expandSeparators(false); } else if (AccountManagerAction.EXPAND.name().equals(e.getActionCommand())) { jTable.expandSeparators(true); } else if (AccountManagerAction.CLOSE.name().equals(e.getActionCommand())) { save(); } else if (AccountCellAction.EDIT.name().equals(e.getActionCommand())) { int index = jTable.getSelectedRow(); Object o = tableModel.getElementAt(index); if (o instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) o; Object object = separator.first(); if (object instanceof EsiOwner) { EsiOwner esiOwner = (EsiOwner) object; accountImportDialog.editEsi(esiOwner); } } } else if (AccountCellAction.DELETE.name().equals(e.getActionCommand())) { int index = jTable.getSelectedRow(); Object o = tableModel.getElementAt(index); if (o instanceof SeparatorList.Separator) { int nReturn = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame() , DialoguesAccount.get().deleteAccountQuestion() , DialoguesAccount.get().deleteAccount() , JOptionPane.YES_NO_OPTION , JOptionPane.PLAIN_MESSAGE); if (nReturn == JOptionPane.YES_OPTION) { SeparatorList.Separator separator = (SeparatorList.Separator) o; Object object = separator.first(); if (object instanceof EsiOwner) { EsiOwner esiOwner = (EsiOwner) object; program.getProfileManager().getEsiOwners().remove(esiOwner); forceUpdate(); updateTable(); } } } } else if (AccountManagerAction.REVALIDATE.name().equals(e.getActionCommand())) { jRevalidateLock.show(GuiShared.get().updating(), new LockWorkerAdaptor() { private int done = 0; private int total = 0; @Override public void task() { for (EsiOwner owner : program.getProfileManager().getEsiOwners()) { if (owner.isInvalid()) { total++; OAuth oAuth = (OAuth) owner.getApiClient().getAuthentication(ApiClientBuilder.AUTHENTICATION); String accessToken = oAuth.getAccessToken(); if (accessToken != null) { owner.setInvalid(false); done++; } } } } @Override public void gui() { if (done > 0) { forceUpdate(); updateTable(); } } @Override public void hidden() { if (total > 0) { if (done == total) { //All JOptionPane.showMessageDialog(getDialog(), DialoguesAccount.get().revalidateMsgAll(total), DialoguesAccount.get().revalidate(), JOptionPane.PLAIN_MESSAGE); } else if (done == 0) { //None JOptionPane.showMessageDialog(getDialog(), DialoguesAccount.get().revalidateMsgNone(total), DialoguesAccount.get().revalidate(), JOptionPane.PLAIN_MESSAGE); } else { //Some JOptionPane.showMessageDialog(getDialog(), DialoguesAccount.get().revalidateMsgSome(total, done, total-done), DialoguesAccount.get().revalidate(), JOptionPane.PLAIN_MESSAGE); } } } }); } else if (AccountManagerAction.CHECK_ALL.name().equals(e.getActionCommand())) { checkAssets(false, true); } else if (AccountManagerAction.UNCHECK_ALL.name().equals(e.getActionCommand())) { checkAssets(false, false); } else if (AccountManagerAction.CHECK_SELECTED.name().equals(e.getActionCommand())) { checkAssets(true, true); } else if (AccountManagerAction.UNCHECK_SELECTED.name().equals(e.getActionCommand())) { checkAssets(true, false); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/account/AccountSeparatorTableCell.java ================================================ /* Glazed Lists (c) 2003-2006 */ /* http://publicobject.com/glazedlists/ publicobject.com,*/ /* O'Dell Engineering Ltd.*/ package net.nikr.eve.jeveasset.gui.dialogs.account; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.SeparatorList.Separator; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import javax.swing.BorderFactory; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Colors; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.table.SeparatorTableCell; import net.nikr.eve.jeveasset.i18n.DialoguesAccount; /** * * @author Jesse Wilson */ public class AccountSeparatorTableCell extends SeparatorTableCell { public enum AccountCellAction { ACCOUNT_NAME, EDIT, DELETE, } private final JTextField jAccountName; private final JLabel jAccountType; private final JButton jEdit; private final JButton jDelete; private final JLabel jInvalidLabel; private final JLabel jExpiredLabel; private final JLabel jSeparatorLabel; private final Color defaultColor; private final AccountManagerDialog accountManagerDialog; public AccountSeparatorTableCell(final AccountManagerDialog accountManagerDialog, final ActionListener actionListener, final JTable jTable, final SeparatorList separatorList) { super(jTable, separatorList); this.accountManagerDialog = accountManagerDialog; defaultColor = jPanel.getBackground(); ListenerClass listener = new ListenerClass(); addCellEditorListener(listener); jSeparatorLabel = new JLabel(); jSeparatorLabel.setBackground(jTable.getBackground()); jSeparatorLabel.setOpaque(true); jSeparatorLabel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, jTable.getGridColor())); jAccountType = new JLabel(); jEdit = new JButton(DialoguesAccount.get().edit()); jEdit.setOpaque(false); jEdit.setActionCommand(AccountCellAction.EDIT.name()); jEdit.addActionListener(actionListener); jDelete = new JButton(DialoguesAccount.get().delete()); jDelete.setOpaque(false); jDelete.setActionCommand(AccountCellAction.DELETE.name()); jDelete.addActionListener(actionListener); jAccountName = new JTextField(); jAccountName.setBorder(null); jAccountName.setOpaque(false); jAccountName.setBackground(Colors.COMPONENT_TRANSPARENT.getColor()); jAccountName.setActionCommand(AccountCellAction.ACCOUNT_NAME.name()); jAccountName.addActionListener(listener); jAccountName.addKeyListener(listener); jAccountName.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { jAccountName.selectAll(); } @Override public void focusLost(FocusEvent e) { } }); jInvalidLabel = new JLabel(DialoguesAccount.get().accountInvalid()); jExpiredLabel = new JLabel(DialoguesAccount.get().accountExpired()); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(jSeparatorLabel, 0, 0, Integer.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addComponent(jExpand) .addGap(1) .addComponent(jEdit, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jDelete, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addGap(5) .addComponent(jAccountType) .addGap(5) .addComponent(jAccountName, 120, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addGap(10) .addComponent(jExpiredLabel) .addComponent(jInvalidLabel) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jSeparatorLabel, jTable.getRowHeight(), jTable.getRowHeight(), jTable.getRowHeight()) .addGap(1) .addGroup(layout.createParallelGroup() .addComponent(jExpand, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jAccountType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jEdit, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDelete, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jAccountName, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jInvalidLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jExpiredLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(2) ); } @Override protected void configure(final Separator separator) { OwnerType owner = (OwnerType) separator.first(); if (owner == null) { // handle 'late' rendering calls after this separator is invalid return; } jSeparatorLabel.setVisible(currentRow != 0); switch (owner.getAccountAPI()) { case ESI: jAccountType.setIcon(Images.MISC_ESI.getIcon()); break; } jAccountName.setText(owner.getAccountName()); //Expired jExpiredLabel.setVisible(owner.isExpired()); //Invalid jInvalidLabel.setVisible(owner.isInvalid()); //Invalid / Expired if (owner.isInvalid() || owner.isExpired()) { ColorSettings.config(jPanel, ColorEntry.GLOBAL_ENTRY_INVALID); } else { jPanel.setBackground(defaultColor); } } private void setAccountName(OwnerType owner) { if (owner == null) { return; } if (jAccountName.getText().isEmpty()) { owner.setResetAccountName(); } else { owner.setAccountName(jAccountName.getText()); } accountManagerDialog.forceUpdate(); } private class ListenerClass implements ActionListener, CellEditorListener, KeyListener { private boolean update = true; @Override public void actionPerformed(final ActionEvent e) { if (AccountCellAction.ACCOUNT_NAME.name().equals(e.getActionCommand())) { stopCellEditing(); expandSeparator(true); int index = jTable.getSelectedRow() + 1; if (jTable.getRowCount() >= index) { jTable.setRowSelectionInterval(index, index); } } } @Override public void editingStopped(ChangeEvent e) { saveAccountName(); } @Override public void editingCanceled(ChangeEvent e) { saveAccountName(); } @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { update = false; stopCellEditing(); } } @Override public void keyReleased(KeyEvent e) { } private void saveAccountName() { if (!update) { update = true; return; } OwnerType owner = (OwnerType) currentSeparator.first(); if (owner == null) { // handle 'late' rendering calls after this separator is invalid return; } setAccountName(owner); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/account/AccountTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.account; import java.util.Comparator; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.ExpirerDate; import net.nikr.eve.jeveasset.gui.shared.table.containers.YesNo; import net.nikr.eve.jeveasset.i18n.DialoguesAccount; public enum AccountTableFormat implements EnumTableColumn { SHOW_ASSETS(Boolean.class) { @Override public String getColumnName() { return ""; } @Override public Object getColumnValue(final OwnerType from) { return from.isShowOwner() && !from.getOwnerName().equals(DialoguesAccount.get().noOwners()); } @Override public boolean isColumnEditable(final Object baseObject) { if (baseObject instanceof OwnerType) { OwnerType owner = (OwnerType) baseObject; return !owner.getOwnerName().equals(DialoguesAccount.get().noOwners()); } return true; } @Override public boolean setColumnValue(final Object baseObject, final Object editedValue) { if ((editedValue instanceof Boolean) && (baseObject instanceof OwnerType)) { OwnerType owner = (OwnerType) baseObject; boolean before = owner.isShowOwner(); boolean after = (Boolean) editedValue; owner.setShowOwner(after); return before != after; } return false; } }, NAME(String.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatName(); } @Override public Object getColumnValue(final OwnerType from) { return from.getOwnerName(); } }, CORPORATION(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatCorporation(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isCorporation()); } }, ASSET_LIST(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatAssetList(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isAssetList()); } }, ACCOUNT_BALANCE(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatAccountBalance(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isAccountBalance()); } }, INDUSTRY_JOBS(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatIndustryJobs(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isIndustryJobs()); } }, MARKET_ORDERS(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatMarketOrders(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isMarketOrders()); } }, TRANSACTIONS(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatTransactions(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isTransactions()); } }, JOURNAL(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatJournal(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isJournal()); } }, CONTRACTS(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatContracts(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isContracts()); } }, LOCATIONS(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatLocations(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isLocations()); } }, STRUCTURES(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatStructures(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isStructures()); } }, MARKET_STRUCTURES(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatMarketStructures(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isMarketStructures()); } }, BLUEPRINTS(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatBlueprints(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isBlueprints()); } }, DIVISIONS(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatDivisions(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isDivisions()); } }, SHIP(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatShip(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isShip()); } }, PLANETARY_INTERACTION(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatPlanetaryInteraction(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isPlanetaryInteraction()); } }, OPEN_WINDOWS(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatOpenWindows(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isOpenWindows()); } }, AUTOPILOT(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatAutopilot(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isAutopilot()); } }, SKILLS(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatSkills(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isSkills()); } }, MINING(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatMining(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isMining()); } }, CLONES(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatClones(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isClones()); } }, IMPLANTS(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatImplants(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isImplants()); } }, LOYALTY_POINTS(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatLoyaltyPoints(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isLoyaltyPoints()); } }, NPC_STANDING(YesNo.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatNpcStanding(); } @Override public Object getColumnValue(final OwnerType from) { return YesNo.get(from.isNpcStanding()); } }, EXPIRES(ExpirerDate.class) { @Override public String getColumnName() { return DialoguesAccount.get().tableFormatExpires(); } @Override public Object getColumnValue(final OwnerType from) { return new ExpirerDate(from.getExpire()); } }; private final Class type; private final Comparator comparator; private AccountTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/account/JAccountTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.account; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.gui.shared.table.JSeparatorTable; import net.nikr.eve.jeveasset.i18n.DialoguesAccount; public class JAccountTable extends JSeparatorTable { private final DefaultEventTableModel tableModel; public JAccountTable(final Program program, final DefaultEventTableModel tableModel, SeparatorList separatorList) { super(program, tableModel, separatorList); this.tableModel = tableModel; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); Object object = tableModel.getElementAt(row); //No Owners if (object instanceof OwnerType) { OwnerType owner = (OwnerType) object; if (owner.getOwnerName().equals(DialoguesAccount.get().noOwners())) { component.setEnabled(false); return component; } else { component.setEnabled(true); return component; } } return component; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/account/SeparatorListComparator.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.account; import java.util.Comparator; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; public class SeparatorListComparator implements Comparator { @Override public int compare(final OwnerType o1, final OwnerType o2) { return o1.getComparator().compareTo(o2.getComparator()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/profile/JValidatedInputDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.profile; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.GroupLayout.Alignment; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.text.PlainDocument; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.shared.DocumentFactory; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.i18n.DialoguesProfiles; public class JValidatedInputDialog extends JDialogCentered { private enum InputDialogAction { OK, CANCEL } private final JTextArea jMessage; private final JTextField jName; private final JButton jOK; private boolean failed = false; public JValidatedInputDialog(final Program program, final JDialogCentered jDialogCentered) { super(program, "", jDialogCentered.getDialog()); ListenerClass listener = new ListenerClass(); jMessage = new JTextArea(); jMessage.setFocusable(false); jMessage.setEditable(false); jMessage.setBackground(getDialog().getBackground()); jMessage.setFont(getDialog().getFont()); jName = new JTextField(); jOK = new JButton(DialoguesProfiles.get().ok()); jOK.setActionCommand(InputDialogAction.OK.name()); jOK.addActionListener(listener); JButton jCancel = new JButton(DialoguesProfiles.get().cancel()); jCancel.setActionCommand(InputDialogAction.CANCEL.name()); jCancel.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(jMessage, 250, 250, 250) .addComponent(jName, 250, 250, 250) .addGroup(Alignment.TRAILING, layout.createSequentialGroup() .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jMessage) .addComponent(jName, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } public String show(final String title, final String message, final String defaultValue, final int restrictions) { if (title != null) { this.getDialog().setTitle(title); } else { this.getDialog().setTitle(""); } if (message != null) { jMessage.setText(message); } else { jMessage.setText(""); } switch (restrictions) { case WORDS_ONLY: jName.setDocument(DocumentFactory.getWordPlainDocument()); break; case INTEGERS_ONLY: jName.setDocument(DocumentFactory.getIntegerPlainDocument()); break; case NUMBERS_ONLY: jName.setDocument(DocumentFactory.getDoublePlainDocument()); break; case NO_RESTRICTIONS: jName.setDocument(new PlainDocument()); break; default: jName.setDocument(new PlainDocument()); break; } if (defaultValue != null) { jName.setText(defaultValue); } else { jName.setText(""); } jName.selectAll(); this.setVisible(true); if (failed) { return null; } return jName.getText(); } @Override protected JComponent getDefaultFocus() { return jName; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { } @Override protected void save() { } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (InputDialogAction.OK.name().equals(e.getActionCommand())) { failed = false; setVisible(false); } if (InputDialogAction.CANCEL.name().equals(e.getActionCommand())) { failed = true; setVisible(false); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/profile/ProfileDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.profile; import java.awt.Component; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.Collections; import java.util.List; import javax.swing.*; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.profile.Profile; import net.nikr.eve.jeveasset.data.profile.Profile.ProfileType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow.LockWorkerAdaptor; import net.nikr.eve.jeveasset.i18n.DialoguesProfiles; public class ProfileDialog extends JDialogCentered { private enum ProfileDialogAction { NEW, LOAD, RENAME, DELETE, DEFAULT, CLOSE } private final JList jProfiles; private final JButton jNew; private final JButton jLoad; private final JButton jRename; private final JButton jDelete; private final JButton jDefault; private final JButton jClose; private final JLockWindow jLockWindow; private final JValidatedInputDialog jValidatedInputDialog; public ProfileDialog(final Program program) { super(program, DialoguesProfiles.get().profiles(), Images.DIALOG_PROFILES.getImage()); jLockWindow = new JLockWindow(getDialog()); jValidatedInputDialog = new JValidatedInputDialog(program, this); ListenerClass listener = new ListenerClass(); jProfiles = new JList<>(); jProfiles.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); jProfiles.setVisibleRowCount(-1); jProfiles.setCellRenderer(new JProfileListRenderer(jProfiles.getCellRenderer())); jProfiles.addMouseListener(listener); JScrollPane jProfilesScrollPane = new JScrollPane(jProfiles); jLoad = new JButton(DialoguesProfiles.get().load()); jLoad.setActionCommand(ProfileDialogAction.LOAD.name()); jLoad.addActionListener(listener); jNew = new JButton(DialoguesProfiles.get().newP()); jNew.setActionCommand(ProfileDialogAction.NEW.name()); jNew.addActionListener(listener); jRename = new JButton(DialoguesProfiles.get().rename()); jRename.setActionCommand(ProfileDialogAction.RENAME.name()); jRename.addActionListener(listener); jDelete = new JButton(DialoguesProfiles.get().delete()); jDelete.setActionCommand(ProfileDialogAction.DELETE.name()); jDelete.addActionListener(listener); jDefault = new JButton(DialoguesProfiles.get().defaultP()); jDefault.setActionCommand(ProfileDialogAction.DEFAULT.name()); jDefault.addActionListener(listener); jClose = new JButton(DialoguesProfiles.get().close()); jClose.setActionCommand(ProfileDialogAction.CLOSE.name()); jClose.addActionListener(listener); layout.setHorizontalGroup( layout.createSequentialGroup() .addComponent(jProfilesScrollPane, 150, 150, 150) .addGroup(layout.createParallelGroup() .addComponent(jLoad, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jDefault, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jNew, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jRename, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jDelete, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jClose, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createParallelGroup() .addComponent(jProfilesScrollPane) .addGroup(layout.createSequentialGroup() .addComponent(jLoad, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDefault, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGap(25) .addComponent(jNew, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRename, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDelete, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGap(45) .addComponent(jClose, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } private void updateProfiles() { DefaultListModel listModel = new DefaultListModel<>(); List profiles = program.getProfileManager().getProfiles(); Collections.sort(profiles); for (Profile profile : profiles) { listModel.addElement(profile); } jProfiles.setModel(listModel); if (!profiles.isEmpty()) { jProfiles.setSelectedValue(program.getProfileManager().getActiveProfile(), true); } } private void startLoadProfile() { Profile profile = jProfiles.getSelectedValue(); if (profile.isActiveProfile()) { JOptionPane.showMessageDialog(this.getDialog(), DialoguesProfiles.get().profileLoaded(), DialoguesProfiles.get().loadProfile(), JOptionPane.INFORMATION_MESSAGE); } else { jLockWindow.show(DialoguesProfiles.get().loadingProfile(), new LoadProfile(profile)); } } private void loadProfileWork(final Profile profile) { if (profile != null && !profile.isActiveProfile()) { //Clear active profile flag (from all profiles) for (Profile profileLoop : program.getProfileManager().getProfiles()) { profileLoop.setActiveProfile(false); } //Clear accounts program.getProfileManager().clear(); //Clear data program.updateEventLists(); //Set active profile program.getProfileManager().setActiveProfile(profile); profile.setActiveProfile(true); //Load new profile program.getProfileManager().loadActiveProfile(); //Update data program.updateEventLists(); } } private void loadProfileGui() { //Update GUI (this dialog) updateProfiles(); jProfiles.updateUI(); //Update window title program.getMainWindow().updateTitle(); //Warn on profile load error program.getProfileManager().showProfileLoadErrorWarning(this.getDialog()); //Ask to clear filters - if needed if (!program.getAssetsTab().isFiltersEmpty()) { int value = JOptionPane.showConfirmDialog(this.getDialog(), DialoguesProfiles.get().clearFilter(), DialoguesProfiles.get().profileLoadedMsg(), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (value == JOptionPane.YES_OPTION) { program.getAssetsTab().clearFilters(); } } } @Override protected JComponent getDefaultFocus() { return jClose; } @Override protected JButton getDefaultButton() { return jClose; } @Override protected void windowShown() { updateProfiles(); } @Override protected void save() { } private class ListenerClass implements ActionListener, MouseListener { @Override public void actionPerformed(final ActionEvent e) { if (ProfileDialogAction.NEW.name().equals(e.getActionCommand())) { String s = jValidatedInputDialog.show( DialoguesProfiles.get().newProfile(), DialoguesProfiles.get().typeName(), "", JDialogCentered.WORDS_ONLY); if (s == null || s.isEmpty()) { return; //Cancel or invalid name } if (program.getProfileManager().containsProfileName(s)) { JOptionPane.showMessageDialog(getDialog(), DialoguesProfiles.get().nameAlreadyExists(), DialoguesProfiles.get().newProfile(), JOptionPane.INFORMATION_MESSAGE); return; //Existing name } //Create new profile jLockWindow.show(DialoguesProfiles.get().creatingProfile(), new NewProfile(s)); } else if (ProfileDialogAction.LOAD.name().equals(e.getActionCommand())) { startLoadProfile(); } else if (ProfileDialogAction.RENAME.name().equals(e.getActionCommand())) { Profile profile = jProfiles.getSelectedValue(); if (profile == null) { return; //nothing selected } String s = jValidatedInputDialog.show(DialoguesProfiles.get().renameProfile(), DialoguesProfiles.get().enterNewName(), profile.getName(), JDialogCentered.WORDS_ONLY); if (s == null || s.isEmpty()) { return; //Cancel or invalid name } if (program.getProfileManager().containsProfileName(s)) { JOptionPane.showMessageDialog(getDialog(), DialoguesProfiles.get().nameAlreadyExists(), DialoguesProfiles.get().renameProfile(), JOptionPane.INFORMATION_MESSAGE); return; //Existing name } //Rename profile profile.setName(s); program.getMainWindow().updateTitle(); jProfiles.updateUI(); } else if (ProfileDialogAction.DELETE.name().equals(e.getActionCommand())) { Profile profile = jProfiles.getSelectedValue(); if (profile == null) { return; //Nothing selected } if (profile.isActiveProfile()) { JOptionPane.showMessageDialog(getDialog(), DialoguesProfiles.get().cannotDeleteActive(), DialoguesProfiles.get().deleteProfile(), JOptionPane.INFORMATION_MESSAGE); return; //Can not delete the active profile } if (profile.isDefaultProfile()) { JOptionPane.showMessageDialog(getDialog(), DialoguesProfiles.get().cannotDeleteDefault(), DialoguesProfiles.get().deleteProfile(), JOptionPane.INFORMATION_MESSAGE); return; //Can not delete the default profile } int value = JOptionPane.showConfirmDialog(getDialog(), DialoguesProfiles.get().deleteProfileConfirm(profile.getName()), DialoguesProfiles.get().deleteProfile(), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (value != JOptionPane.YES_OPTION) { return; //Cancel } //Delete profile program.getProfileManager().getProfiles().remove(profile); profile.delete(); updateProfiles(); program.getMainWindow().updateTitle(); jProfiles.updateUI(); } else if (ProfileDialogAction.DEFAULT.name().equals(e.getActionCommand())) { Profile profile = jProfiles.getSelectedValue(); if (profile == null || profile.isDefaultProfile()) { return; //Cancel or already default } //Clear default profile for (Profile profileLoop : program.getProfileManager().getProfiles()) { profileLoop.setDefaultProfile(false); } //Set default profile profile.setDefaultProfile(true); jProfiles.updateUI(); } else if (ProfileDialogAction.CLOSE.name().equals(e.getActionCommand())) { setVisible(false); } } @Override public void mouseClicked(final MouseEvent e) { if (e.getClickCount() == 2 && getDialog().isEnabled()) { startLoadProfile(); } } @Override public void mousePressed(final MouseEvent e) { } @Override public void mouseReleased(final MouseEvent e) { } @Override public void mouseEntered(final MouseEvent e) { } @Override public void mouseExited(final MouseEvent e) { } } public class JProfileListRenderer implements ListCellRenderer { private final ListCellRenderer renderer; public JProfileListRenderer(ListCellRenderer renderer) { this.renderer = renderer; } @Override public Component getListCellRendererComponent(JList list, Profile value, int index, boolean isSelected, boolean cellHasFocus) { Component component = renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value.isActiveProfile()) { Font font = component.getFont(); component.setFont(new Font(font.getName(), font.getStyle() + Font.BOLD, font.getSize())); } return component; } } private class NewProfile extends LockWorkerAdaptor { private final String profileName; public NewProfile(final String profileName) { this.profileName = profileName; } @Override public void task() { Profile profile = new Profile(profileName, false, false, ProfileType.SQLITE); program.getProfileManager().getProfiles().add(profile); profile.save(); loadProfileWork(profile); } @Override public void hidden() { loadProfileGui(); } } private class LoadProfile extends LockWorkerAdaptor { private final Profile profile; public LoadProfile(final Profile profile) { this.profile = profile; } @Override public void task() { loadProfileWork(profile); } @Override public void hidden() { loadProfileGui(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/AssetsToolSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.GroupLayout; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class AssetsToolSettingsPanel extends JSettingsPanel { private static enum ContractsOwnerFormat { ISSUER_CHARACTER() { @Override protected String getName() { return DialoguesSettings.get().contractAssetsCharacter(); } }, ISSUER_CORPORATION() { @Override protected String getName() { return DialoguesSettings.get().contractAssetsCorporation(); } }, ISSUER_BOTH() { @Override protected String getName() { return DialoguesSettings.get().contractAssetsBoth(); } }; @Override public String toString() { return getName(); } protected abstract String getName(); } private final JCheckBox jSellOrders; private final JCheckBox jBuyOrders; private final JCheckBox jSellContracts; private final JCheckBox jBuyContracts; private final JComboBox jContractsOwner; private final JCheckBox jManufacturing; private final JCheckBox jCopying; private final JCheckBox jJumpClones; private final JCheckBox jPluggedInImplants; private final JCheckBox jContainerItemID; public AssetsToolSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().assets(), Images.TOOL_ASSETS.getIcon()); jSellOrders = new JCheckBox(DialoguesSettings.get().includeSellOrders()); jBuyOrders = new JCheckBox(DialoguesSettings.get().includeBuyOrders()); jSellContracts = new JCheckBox(DialoguesSettings.get().includeSellContracts()); jBuyContracts = new JCheckBox(DialoguesSettings.get().includeBuyContracts()); JLabel jContractsOwnerLabel = new JLabel(DialoguesSettings.get().contractAssetsLabel()); JLabel jContractsOwnerWarn = new JLabel(DialoguesSettings.get().contractAssetsLabelWarn()); jContractsOwner = new JComboBox<>(ContractsOwnerFormat.values()); jContractsOwner.setPrototypeDisplayValue(ContractsOwnerFormat.ISSUER_BOTH); jContractsOwner.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jContractsOwnerWarn.setVisible(jContractsOwner.getItemAt(jContractsOwner.getSelectedIndex()) == ContractsOwnerFormat.ISSUER_BOTH); } }); jManufacturing = new JCheckBox(DialoguesSettings.get().includeManufacturing()); jCopying = new JCheckBox(DialoguesSettings.get().includeCopying()); jJumpClones = new JCheckBox(DialoguesSettings.get().includeJumpClones()); jPluggedInImplants = new JCheckBox(DialoguesSettings.get().includePluggedInImplants()); jContainerItemID = new JCheckBox(DialoguesSettings.get().showContainerItemID()); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jSellOrders) .addComponent(jBuyOrders) .addComponent(jSellContracts) .addComponent(jBuyContracts) .addComponent(jManufacturing) .addComponent(jCopying) .addComponent(jJumpClones) .addComponent(jPluggedInImplants) ) .addGap(0, 0, 100) .addGroup(layout.createParallelGroup() .addComponent(jContractsOwnerLabel) .addComponent(jContractsOwner, 200, 200, 200) .addComponent(jContractsOwnerWarn) ) ) .addComponent(jContainerItemID) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jSellOrders, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jBuyOrders, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGap(0) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jSellContracts, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jContractsOwnerLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(0) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jBuyContracts, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jContractsOwner, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(0) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jContractsOwnerWarn, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jManufacturing, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ) ) .addGap(0) .addComponent(jCopying, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jJumpClones, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jPluggedInImplants, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jContainerItemID, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } @Override public UpdateType save() { ContractsOwnerFormat contractsOwnerFormat = jContractsOwner.getItemAt(jContractsOwner.getSelectedIndex()); boolean fullUpdate = jSellOrders.isSelected() != Settings.get().isIncludeSellOrders() || jBuyOrders.isSelected() != Settings.get().isIncludeBuyOrders() || jSellContracts.isSelected() != Settings.get().isIncludeSellContracts() || jBuyContracts.isSelected() != Settings.get().isIncludeBuyContracts() || jManufacturing.isSelected() != Settings.get().isIncludeManufacturing() || jCopying.isSelected() != Settings.get().isIncludeCopying() || jJumpClones.isSelected() != Settings.get().isIncludeJumpClones() || jPluggedInImplants.isSelected() != Settings.get().isIncludePluggedInImplants() || ((jSellContracts.isSelected() || jBuyContracts.isSelected()) && ((contractsOwnerFormat == ContractsOwnerFormat.ISSUER_CHARACTER && (Settings.get().isAssetsContractsOwnerCorporation() || Settings.get().isAssetsContractsOwnerBoth())) || (contractsOwnerFormat == ContractsOwnerFormat.ISSUER_CORPORATION && !Settings.get().isAssetsContractsOwnerCorporation()) || (contractsOwnerFormat == ContractsOwnerFormat.ISSUER_BOTH && !Settings.get().isAssetsContractsOwnerBoth()))) ; boolean updateContainers = jContainerItemID.isSelected() != Settings.get().isContainersShowItemID(); Settings.get().setIncludeSellOrders(jSellOrders.isSelected()); Settings.get().setIncludeBuyOrders(jBuyOrders.isSelected()); Settings.get().setIncludeSellContracts(jSellContracts.isSelected()); Settings.get().setIncludeBuyContracts(jBuyContracts.isSelected()); Settings.get().setIncludeManufacturing(jManufacturing.isSelected()); Settings.get().setIncludeCopying(jCopying.isSelected()); Settings.get().setIncludeJumpClones(jJumpClones.isSelected()); Settings.get().setIncludePluggedInImplants(jPluggedInImplants.isSelected()); Settings.get().setContainersShowItemID(jContainerItemID.isSelected()); Settings.get().setAssetsContractsOwnerCorporation(contractsOwnerFormat == ContractsOwnerFormat.ISSUER_CORPORATION); Settings.get().setAssetsContractsOwnerBoth(contractsOwnerFormat == ContractsOwnerFormat.ISSUER_BOTH); if (fullUpdate) { return UpdateType.FULL_UPDATE; } else if (updateContainers) { return UpdateType.UPDATE_ASSET_TABLES; } else { return UpdateType.NONE; } } @Override public void load() { jSellOrders.setSelected(Settings.get().isIncludeSellOrders()); jBuyOrders.setSelected(Settings.get().isIncludeBuyOrders()); jSellContracts.setSelected(Settings.get().isIncludeSellContracts()); jBuyContracts.setSelected(Settings.get().isIncludeBuyContracts()); jManufacturing.setSelected(Settings.get().isIncludeManufacturing()); jCopying.setSelected(Settings.get().isIncludeCopying()); jJumpClones.setSelected(Settings.get().isIncludeJumpClones()); jPluggedInImplants.setSelected(Settings.get().isIncludePluggedInImplants()); jContainerItemID.setSelected(Settings.get().isContainersShowItemID()); if (Settings.get().isAssetsContractsOwnerCorporation()) { jContractsOwner.setSelectedItem(ContractsOwnerFormat.ISSUER_CORPORATION); } else if (Settings.get().isAssetsContractsOwnerBoth()) { jContractsOwner.setSelectedItem(ContractsOwnerFormat.ISSUER_BOTH); } else { jContractsOwner.setSelectedItem(ContractsOwnerFormat.ISSUER_CHARACTER); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/ColorSeparatorTableCell.java ================================================ /* Glazed Lists (c) 2003-2006 */ /* http://publicobject.com/glazedlists/ publicobject.com,*/ /* O'Dell Engineering Ltd.*/ package net.nikr.eve.jeveasset.gui.dialogs.settings; import ca.odell.glazedlists.SeparatorList; import javax.swing.*; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorSettings.ColorRow; import net.nikr.eve.jeveasset.gui.shared.table.SeparatorTableCell; /** * * @author Jesse Wilson */ public class ColorSeparatorTableCell extends SeparatorTableCell { private final JLabel jGroup; public ColorSeparatorTableCell(final JTable jTable, final SeparatorList separatorList) { super(jTable, separatorList); jGroup = new JLabel(); layout.setHorizontalGroup( layout.createSequentialGroup() .addComponent(jExpand) .addComponent(jGroup) ); layout.setVerticalGroup( layout.createParallelGroup() .addComponent(jExpand, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jGroup, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } @Override protected void configure(final SeparatorList.Separator separator) { ColorRow colorRow = (ColorRow) separator.first(); if (colorRow == null) { // handle 'late' rendering calls after this separator is invalid return; } jGroup.setText(colorRow.getColorEntry().getGroup().getName()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/ColorSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.TextFilterator; import ca.odell.glazedlists.matchers.MatcherEditor; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TextComponentMatcherEditor; import java.awt.Color; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JOptionPane; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UIManager.LookAndFeelInfo; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorSettings.ColorRow; import net.nikr.eve.jeveasset.data.settings.ColorSettings.PredefinedLookAndFeel; import net.nikr.eve.jeveasset.data.settings.ColorTheme.ColorThemeTypes; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.JSimpleColorPicker; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class ColorSettingsPanel extends JSettingsPanel { private final JCheckBoxMenuItem jChartColor; private final JTextField jFilter; //Table private final JColorTable jTable; private final DefaultEventTableModel tableModel; private final EventList eventList; private final DefaultEventSelectionModel selectionModel; private ColorThemeTypes colorThemeTypes; private List colors; private String lookAndFeelClass; private boolean updateLock = false; private final List jThemeMenuItems = new ArrayList<>(); private final List jLafMenuItems = new ArrayList<>(); public ColorSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().colors(), Images.SETTINGS_COLORS.getIcon()); JSimpleColorPicker jSimpleColorPicker = new JSimpleColorPicker(settingsDialog.getDialog()); //Backend eventList = EventListManager.create(); //Filter jFilter = new JTextField(); MatcherEditor matcherEditor = new TextComponentMatcherEditor<>(jFilter, new ColorRowTextFilterator()); eventList.getReadWriteLock().readLock().lock(); FilterList filterList = new FilterList<>(eventList, matcherEditor); eventList.getReadWriteLock().readLock().unlock(); //Separator SeparatorList separatorList = new SeparatorList<>(filterList, new ColorRowSeparatorComparator(), 1, Integer.MAX_VALUE); //Table Model tableModel = EventModels.createTableModel(separatorList, TableFormatFactory.colorsTableFormat()); //Table jTable = new JColorTable(program, tableModel, separatorList); jTable.setSeparatorRenderer(new ColorSeparatorTableCell(jTable, separatorList)); jTable.setSeparatorEditor(new ColorSeparatorTableCell(jTable, separatorList)); jTable.setCellSelectionEnabled(true); jTable.setRowSelectionAllowed(true); jTable.setColumnSelectionAllowed(true); jTable.addMouseListener(new MouseAdapter() { int lastShownRow = -1; int lastShownColumn = -1; boolean ignore = false; @Override public void mousePressed(MouseEvent e) { int row = jTable.rowAtPoint(e.getPoint()); int column = jTable.columnAtPoint(e.getPoint()); if (column == lastShownColumn && row == lastShownRow) { ignore = true; } } @Override public void mouseClicked(MouseEvent e) { if (ignore) { ignore = false; lastShownRow = -1; lastShownColumn = -1; return; //Ignore same cell click } int row = jTable.rowAtPoint(e.getPoint()); int column = jTable.columnAtPoint(e.getPoint()); Object object = tableModel.getElementAt(row); if (!(object instanceof ColorRow)) { return; //Ignore Separator } ColorRow colorRow = (ColorRow) object; String columnName = (String) jTable.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); Rectangle cellRect = jTable.getCellRect(row, column, false); Point table = jTable.getLocationOnScreen(); Point point = new Point(table.x + cellRect.x + cellRect.width, table.y + cellRect.y + cellRect.height); if (columnName.equals(ColorsTableFormat.BACKGROUND.getColumnName())) { if (!colorRow.getColorEntry().isBackgroundEditable()) { return; } jTable.startEditCell(row, column); jSimpleColorPicker.show(colorRow.getBackground(), colorRow.getDefaultBackground(), colorRow.getColorEntry().isBackgroundNullable(), point, new JSimpleColorPicker.ColorListenere() { @Override public void colorChanged(Color color) { colorRow.setBackground(color); jTable.stopEditCell(); } @Override public void cancelled() { update(row, column); jTable.stopEditCell(); } }); } if (columnName.equals(ColorsTableFormat.FOREGROUND.getColumnName())) { if (!colorRow.getColorEntry().isForegroundEditable()) { return; } jTable.startEditCell(row, column); jSimpleColorPicker.show(colorRow.getForeground(), colorRow.getDefaultForeground(), colorRow.getColorEntry().isForegroundNullable(), point, new JSimpleColorPicker.ColorListenere() { @Override public void colorChanged(Color color) { colorRow.setForeground(color); jTable.stopEditCell(); } @Override public void cancelled() { update(row, column); jTable.stopEditCell(); } }); } } private void update(int row, int column) { lastShownRow = row; lastShownColumn = column; tableModel.fireTableCellUpdated(row, 3); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { //In case we click outside the table lastShownRow = -1; lastShownColumn = -1; } }); } }); //Selection Model selectionModel = EventModels.createSelectionModel(separatorList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); JScrollPane jTableScroll = new JScrollPane(jTable); JFixedToolBar jToolBar = new JFixedToolBar(); JDropDownButton jSetting = new JDropDownButton(Images.DIALOG_SETTINGS.getIcon()); jToolBar.addButtonIcon(jSetting); jChartColor = new JCheckBoxMenuItem (DialoguesSettings.get().chartColors()); jSetting.add(jChartColor); jToolBar.addSeparator(); JDropDownButton jLookAndFeel = new JDropDownButton(DialoguesSettings.get().lookAndFeel(), Images.FILTER_LOAD.getIcon()); jToolBar.addButton(jLookAndFeel); ButtonGroup lafButtonGroup = new ButtonGroup(); //Predefined LookAndFeels for (PredefinedLookAndFeel predefinedLookAndFeel : PredefinedLookAndFeel.values()) { JLookAndFeelMenuItem jMenuItem = new JLookAndFeelMenuItem(predefinedLookAndFeel.getLookAndFeelInfo(), jLookAndFeel, settingsDialog); jMenuItem.setSelected(predefinedLookAndFeel.isSelected()); jLookAndFeel.add(jMenuItem); lafButtonGroup.add(jMenuItem); jLafMenuItems.add(jMenuItem); } //Installed LookAndFeels for (LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) { if (laf.getClassName().equals(UIManager.getSystemLookAndFeelClassName())) { continue; //Skip system LaF } JLookAndFeelMenuItem jMenuItem = new JLookAndFeelMenuItem(laf, jLookAndFeel, settingsDialog); jLookAndFeel.add(jMenuItem); lafButtonGroup.add(jMenuItem); jLafMenuItems.add(jMenuItem); } JDropDownButton jTheme = new JDropDownButton(DialoguesSettings.get().theme(), Images.FILTER_LOAD.getIcon()); jToolBar.addButton(jTheme); ButtonGroup buttonGroup = new ButtonGroup(); for (ColorThemeTypes theme : ColorThemeTypes.values()) { JThemeMenuItem jMenuItem = new JThemeMenuItem(theme); jTheme.add(jMenuItem); buttonGroup.add(jMenuItem); jThemeMenuItems.add(jMenuItem); } JButton jCollapse = new JButton(DialoguesSettings.get().collapse(), Images.MISC_COLLAPSED.getIcon()); jCollapse.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jTable.expandSeparators(false); } }); jToolBar.addButton(jCollapse); JButton jExpand = new JButton(DialoguesSettings.get().expand(), Images.MISC_EXPANDED.getIcon()); jExpand.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jTable.expandSeparators(true); } }); jToolBar.addButton(jExpand); JFixedToolBar jToolBarSearch = new JFixedToolBar(); jToolBarSearch.add(jFilter); JButton jClear = new JButton(Images.TAB_CLOSE.getIcon()); jClear.setContentAreaFilled(false); jClear.setFocusPainted(false); jClear.setPressedIcon(Images.TAB_CLOSE_ACTIVE.getIcon()); jClear.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jFilter.setText(""); } }); jToolBarSearch.add(jClear); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jToolBar, jToolBar.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jToolBarSearch, jToolBarSearch.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jTableScroll, 375, 375, Integer.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jToolBar ,GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jToolBarSearch, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jTableScroll, 250, 250, Integer.MAX_VALUE) ); } @Override public UpdateType save() { boolean lookAndfeelChanged = !Settings.get().getColorSettings().getLookAndFeelClass().equals(lookAndFeelClass); Settings.get().getColorSettings().setColorTheme(colorThemeTypes.getInstance(), true); //Later overwritten by table values, but, set uneditable values Settings.get().getColorSettings().setLookAndFeelClass(lookAndFeelClass); try { eventList.getReadWriteLock().readLock().lock(); for (ColorRow row : eventList) { Settings.get().getColorSettings().set(row); } } finally { eventList.getReadWriteLock().readLock().unlock(); } boolean easyChartColors = jChartColor.isSelected(); boolean repaint = !Settings.get().getColorSettings().get().equals(colors) || Settings.get().isEasyChartColors() != easyChartColors; Settings.get().setEasyChartColors(easyChartColors); colors = Settings.get().getColorSettings().get(); //Copy to check for changes on save if (lookAndfeelChanged && !UIManager.getLookAndFeel().getClass().getName().equals(lookAndFeelClass)) { JOptionPane.showMessageDialog(parent, DialoguesSettings.get().lookAndFeelMsg(), DialoguesSettings.get().lookAndFeelTitle(), JOptionPane.PLAIN_MESSAGE); } return repaint ? UpdateType.FULL_REPAINT : UpdateType.NONE; } @Override public void load() { updateLock = true; colors = Settings.get().getColorSettings().get(); //Copy to check for changes on save updateTable(Settings.get().getColorSettings().get()); //This copy will be edited colorThemeTypes = Settings.get().getColorSettings().getColorTheme().getType(); jChartColor.setSelected(Settings.get().isEasyChartColors()); select(colorThemeTypes); lookAndFeelClass = Settings.get().getColorSettings().getLookAndFeelClass(); select(lookAndFeelClass); updateLock = false; } private void updateLookAndFeelClass(String lookAndFeelClass) { this.lookAndFeelClass = lookAndFeelClass; } private void updateTheme(ColorThemeTypes colorTheme) { List rows = EventListManager.safeList(eventList); boolean overwrite; if (changed(rows)) { int value = JOptionPane.showConfirmDialog(parent, DialoguesSettings.get().overwriteMsg(), DialoguesSettings.get().overwriteTitle(), JOptionPane.YES_NO_CANCEL_OPTION); if (value == JOptionPane.CANCEL_OPTION) { updateLock = true; select(colorThemeTypes); updateLock = false; return; } overwrite = value == JOptionPane.YES_OPTION; } else { overwrite = true; } colorThemeTypes = colorTheme; updateTable(colorThemeTypes.getInstance().get(overwrite, rows)); } public boolean changed(List old) { for (ColorRow colorRow : old) { if (!colorRow.isBackgroundDefault() || !colorRow.isForegroundDefault()) { return true; } } return false; } private void select(ColorThemeTypes colorTheme) { for (JThemeMenuItem jThemeMenuItem : jThemeMenuItems) { if (jThemeMenuItem.getTheme().equals(colorTheme)) { jThemeMenuItem.setSelected(true); break; } } } private void select(String lookAndFeelClass) { for (JLookAndFeelMenuItem jLookAndFeelMenuItem : jLafMenuItems) { if (jLookAndFeelMenuItem.getLookAndFeelClass().equals(lookAndFeelClass)) { jLookAndFeelMenuItem.setSelected(true); break; } } } private void updateTable(List rows) { jTable.lock(); jTable.saveExpandedState(); try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(rows); } finally { eventList.getReadWriteLock().writeLock().unlock(); } jTable.loadExpandedState(); jTable.unlock(); } public static class ColorRowSeparatorComparator implements Comparator { @Override public int compare(final ColorRow o1, final ColorRow o2) { return o1.getColorEntry().getGroup().compareTo(o2.getColorEntry().getGroup()); } } class ColorRowTextFilterator implements TextFilterator { @Override public void getFilterStrings(List baseList, ColorRow element) { baseList.add(element.getColorEntry().getDescription()); baseList.add(element.getColorEntry().getGroup().getName()); } } private final class JThemeMenuItem extends JRadioButtonMenuItem { private final ColorThemeTypes theme; public JThemeMenuItem(ColorThemeTypes theme) { super(theme.toString()); this.theme = theme; addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (updateLock) { return; } updateTheme(theme); } }); } public ColorThemeTypes getTheme() { return theme; } } private final class JLookAndFeelMenuItem extends JRadioButtonMenuItem { private final String lookAndFeelClass; public JLookAndFeelMenuItem(LookAndFeelInfo lookAndFeel, JDropDownButton jDropDownButton, final SettingsDialog settingsDialog) { super(lookAndFeel.getName()); this.lookAndFeelClass = lookAndFeel.getClassName(); addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (updateLock) { return; } updateLookAndFeelClass(lookAndFeelClass); } }); LookAndFeelPreview.install(lookAndFeelClass, jDropDownButton, this, settingsDialog); } public String getLookAndFeelClass() { return lookAndFeelClass; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/ColorsTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.Color; import java.util.Comparator; import net.nikr.eve.jeveasset.data.settings.ColorSettings.ColorRow; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public enum ColorsTableFormat implements EnumTableColumn { NAME(String.class) { @Override public String getColumnName() { return DialoguesSettings.get().columnName(); } @Override public Object getColumnValue(final ColorRow from) { return from.getColorEntry().getDescription(); } }, BACKGROUND(Color.class) { @Override public String getColumnName() { return DialoguesSettings.get().columnBackground(); } @Override public Object getColumnValue(final ColorRow from) { return from.getBackground(); } }, FOREGROUND(Color.class) { @Override public String getColumnName() { return DialoguesSettings.get().columnForeground(); } @Override public Object getColumnValue(final ColorRow from) { return from.getForeground(); } }, PREVIEW(String.class) { @Override public String getColumnName() { return DialoguesSettings.get().columnPreview(); } @Override public Object getColumnValue(final ColorRow from) { return DialoguesSettings.get().testText(); } }, SELECTED(String.class) { @Override public String getColumnName() { return DialoguesSettings.get().columnSelected(); } @Override public Object getColumnValue(final ColorRow from) { return DialoguesSettings.get().testSelectedText(); } }; private final Class type; private final Comparator comparator; private ColorsTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/ContractToolSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import javax.swing.GroupLayout; import javax.swing.JCheckBox; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JLabelMultiline; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class ContractToolSettingsPanel extends JSettingsPanel { private final JCheckBox jSaveHistory; public ContractToolSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().contracts(), Images.TOOL_CONTRACTS.getIcon()); jSaveHistory = new JCheckBox(DialoguesSettings.get().contractsSaveHistory()); JLabelMultiline jSaveHistoryWarning = new JLabelMultiline(DialoguesSettings.get().saveHistoryWarning(), 2); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jSaveHistory) .addComponent(jSaveHistoryWarning, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jSaveHistory, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSaveHistoryWarning, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ); } @Override public UpdateType save() { Settings.get().setContractHistory(jSaveHistory.isSelected()); return UpdateType.NONE; } @Override public void load() { jSaveHistory.setSelected(Settings.get().isContractHistory()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/ExperimentalSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import javax.swing.GroupLayout; import javax.swing.JCheckBox; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; public class ExperimentalSettingsPanel extends JSettingsPanel { private final JCheckBox jCellValueCache; public ExperimentalSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, "Experimental", Images.JOBS_INVENTION_SUCCESS.getIcon()); jCellValueCache = new JCheckBox("Filter cell value cache"); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jCellValueCache) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jCellValueCache, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } @Override public UpdateType save() { Settings.get().setCellValueCache(jCellValueCache.isSelected()); return UpdateType.NONE; } @Override public void load() { jCellValueCache.setSelected(Settings.get().isColumnValueCache()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/GeneralSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import com.sun.jna.Platform; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JRadioButton; import javax.swing.JTextField; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.ToolLoader; import net.nikr.eve.jeveasset.data.settings.ExportSettings.DecimalSeparator; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.Settings.TransactionProfitPrice; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.DocumentFactory; import net.nikr.eve.jeveasset.gui.shared.components.JIntegerField; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class GeneralSettingsPanel extends JSettingsPanel { private final JRadioButton jLoadToolsBackground; private final JRadioButton jLoadToolsOpen; private final JRadioButton jLoadToolsStartup; private final JCheckBox jEnterFilters; private final JCheckBox jHighlightSelectedRow; private final JCheckBox jFocusEveOnline; private final JTextField jMaxOrderAge; private final JTextField jTransactionProfitMargin; private final JComboBox jTransactionProfitPrice; private final JComboBox jDecimalSeparator; public GeneralSettingsPanel(final Program program, final SettingsDialog optionsDialog) { super(program, optionsDialog, DialoguesSettings.get().general(), Images.DIALOG_SETTINGS.getIcon()); ButtonGroup tools = new ButtonGroup(); jLoadToolsBackground = new JRadioButton(DialoguesSettings.get().loadToolsBackground()); tools.add(jLoadToolsBackground); jLoadToolsOpen = new JRadioButton(DialoguesSettings.get().loadToolsOpen()); tools.add(jLoadToolsOpen); jLoadToolsStartup = new JRadioButton(DialoguesSettings.get().loadToolsStartup()); tools.add(jLoadToolsStartup); jEnterFilters = new JCheckBox(DialoguesSettings.get().enterFilter()); jHighlightSelectedRow = new JCheckBox(DialoguesSettings.get().highlightSelectedRow()); jFocusEveOnline = new JCheckBox(DialoguesSettings.get().focusEveOnline()); JLabel jDecimalSeparatorLabel = new JLabel(DialoguesSettings.get().copyDecimalSeparator()); jDecimalSeparator = new JComboBox<>(DecimalSeparator.values()); JLabel jFocusEveOnlineLinuxHelp = new JLabel(DialoguesSettings.get().focusEveOnlineLinuxHelp()); jFocusEveOnlineLinuxHelp.setVisible(Platform.isLinux()); JLabel jFocusEveOnlineLinuxHelp2 = new JLabel(DialoguesSettings.get().focusEveOnlineLinuxHelp2()); jFocusEveOnlineLinuxHelp2.setVisible(Platform.isLinux()); JTextField jFocusEveOnlineLinuxCmd = new JTextField(DialoguesSettings.get().focusEveOnlineLinuxCmd()); jFocusEveOnlineLinuxCmd.addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { jFocusEveOnlineLinuxCmd.selectAll(); } }); jFocusEveOnlineLinuxCmd.setEditable(false); jFocusEveOnlineLinuxCmd.setVisible(Platform.isLinux()); JLabel jTransactionProfitLabel = new JLabel(DialoguesSettings.get().transactionsProfit()); JLabel jMaxOrderAgeLabel = new JLabel(DialoguesSettings.get().includeDays()); jMaxOrderAge = new JIntegerField("0", DocumentFactory.ValueFlag.POSITIVE_AND_ZERO); JLabel jDaysLabel = new JLabel(DialoguesSettings.get().days()); JLabel jTransactionProfitPriceLabel = new JLabel(DialoguesSettings.get().transactionsPrice()); jTransactionProfitPrice = new JComboBox<>(TransactionProfitPrice.values()); jTransactionProfitPrice.setPrototypeDisplayValue(TransactionProfitPrice.LASTEST); JLabel jTransactionProfitMarginLabel = new JLabel(DialoguesSettings.get().transactionsMargin()); jTransactionProfitMargin = new JIntegerField("0", DocumentFactory.ValueFlag.POSITIVE_AND_ZERO); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jLoadToolsBackground) .addComponent(jLoadToolsOpen) .addComponent(jLoadToolsStartup) .addComponent(jEnterFilters) .addComponent(jHighlightSelectedRow) .addComponent(jFocusEveOnline) .addGroup(layout.createSequentialGroup() .addGap(25) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jFocusEveOnlineLinuxHelp) .addComponent(jFocusEveOnlineLinuxHelp2) .addComponent(jFocusEveOnlineLinuxCmd) ) ) .addComponent(jTransactionProfitLabel) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jDecimalSeparatorLabel) .addGroup(layout.createSequentialGroup() .addGap(25) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jTransactionProfitPriceLabel) .addComponent(jMaxOrderAgeLabel) .addComponent(jTransactionProfitMarginLabel) ) ) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jMaxOrderAge) .addComponent(jTransactionProfitPrice) .addComponent(jTransactionProfitMargin) .addComponent(jDecimalSeparator) ) .addComponent(jDaysLabel) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jLoadToolsBackground, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jLoadToolsOpen, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jLoadToolsStartup, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGap(10) .addComponent(jEnterFilters, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jHighlightSelectedRow, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFocusEveOnline, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFocusEveOnlineLinuxHelp, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFocusEveOnlineLinuxHelp2, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFocusEveOnlineLinuxCmd, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGap(10) .addGroup(layout.createParallelGroup() .addComponent(jDecimalSeparatorLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDecimalSeparator, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jTransactionProfitLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup() .addComponent(jMaxOrderAgeLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jMaxOrderAge, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDaysLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jTransactionProfitPriceLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jTransactionProfitPrice, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jTransactionProfitMarginLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jTransactionProfitMargin, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } @Override public UpdateType save() { int maximumPurchaseAge; try { maximumPurchaseAge = Integer.valueOf(jMaxOrderAge.getText()); } catch (NumberFormatException ex) { maximumPurchaseAge = 0; } TransactionProfitPrice transactionProfitPrice = jTransactionProfitPrice.getItemAt(jTransactionProfitPrice.getSelectedIndex()); int transactionProfitMargin; try { transactionProfitMargin = Integer.valueOf(jTransactionProfitMargin.getText()); } catch (NumberFormatException ex) { transactionProfitMargin = 0; } DecimalSeparator copyDecimalSeparator = jDecimalSeparator.getItemAt(jDecimalSeparator.getSelectedIndex()); boolean update = maximumPurchaseAge != Settings.get().getMaximumPurchaseAge() || transactionProfitPrice != Settings.get().getTransactionProfitPrice() || transactionProfitMargin != Settings.get().getTransactionProfitMargin(); boolean repaint = jHighlightSelectedRow.isSelected() != Settings.get().isHighlightSelectedRows(); boolean loadToolsBackground = jLoadToolsBackground.isSelected(); Settings.get().setLoadToolsBackground(jLoadToolsBackground.isSelected()); Settings.get().setLoadToolsStartup(jLoadToolsStartup.isSelected()); Settings.get().setFilterOnEnter(jEnterFilters.isSelected()); Settings.get().setHighlightSelectedRows(jHighlightSelectedRow.isSelected()); Settings.get().setFocusEveOnlineOnEsiUiCalls(jFocusEveOnline.isSelected()); Settings.get().setMaximumPurchaseAge(maximumPurchaseAge); Settings.get().setTransactionProfitPrice(transactionProfitPrice); Settings.get().setTransactionProfitMargin(transactionProfitMargin); Settings.get().getCopySettings().setCopyDecimalSeparator(copyDecimalSeparator); if (loadToolsBackground) { ToolLoader.startBackgroundToolLoading(program); } else { ToolLoader.stopBackgroundToolLoading(); } if (update) { return UpdateType.FULL_UPDATE; } else if (repaint) { return UpdateType.FULL_REPAINT; } else { return UpdateType.NONE; } } @Override public void load() { jLoadToolsOpen.setSelected(true); jLoadToolsBackground.setSelected(Settings.get().isLoadToolsBackground()); jLoadToolsStartup.setSelected(Settings.get().isLoadToolsStartup()); jEnterFilters.setSelected(Settings.get().isFilterOnEnter()); jHighlightSelectedRow.setSelected(Settings.get().isHighlightSelectedRows()); jFocusEveOnline.setSelected(Settings.get().isFocusEveOnlineOnEsiUiCalls()); jMaxOrderAge.setText(String.valueOf(Settings.get().getMaximumPurchaseAge())); jTransactionProfitPrice.setSelectedItem(Settings.get().getTransactionProfitPrice()); jTransactionProfitMargin.setText(String.valueOf(Settings.get().getTransactionProfitMargin())); jDecimalSeparator.setSelectedItem(Settings.get().getCopySettings().getCopyDecimalSeparator()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/IndustryJobsToolSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import javax.swing.GroupLayout; import javax.swing.JCheckBox; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JLabelMultiline; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class IndustryJobsToolSettingsPanel extends JSettingsPanel { private final JCheckBox jSaveHistory; public IndustryJobsToolSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().industryJobs(), Images.TOOL_INDUSTRY_JOBS.getIcon()); jSaveHistory = new JCheckBox(DialoguesSettings.get().industryJobsSaveHistory()); JLabelMultiline jSaveHistoryWarning = new JLabelMultiline(DialoguesSettings.get().saveHistoryWarning(), 2); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jSaveHistory) .addComponent(jSaveHistoryWarning, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jSaveHistory, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSaveHistoryWarning, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ); } @Override public UpdateType save() { Settings.get().setIndustryJobsHistory(jSaveHistory.isSelected()); return UpdateType.NONE; } @Override public void load() { jSaveHistory.setSelected(Settings.get().isIndustryJobsHistory()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/JColorTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.BorderFactory; import javax.swing.GroupLayout; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.ColorSettings.ColorRow; import net.nikr.eve.jeveasset.data.settings.Colors; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.ColorUtil; import net.nikr.eve.jeveasset.gui.shared.table.JSeparatorTable; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class JColorTable extends JSeparatorTable { private final DefaultEventTableModel tableModel; private final MyComboBox jForeground; private final MyComboBox jBackground; private final JLabel jPreview; private final JLabel jSelected; private final JNullableLabel jNotEditable; private int mouseRow = -1; private int mouseColumn = -1; private int editRow = -1; private int editColumn = -1; public JColorTable(final Program program, final DefaultEventTableModel tableModel, SeparatorList separatorList) { super(program, tableModel, separatorList); this.tableModel = tableModel; this.getTableHeader().setDefaultRenderer(new IconTableCellRenderer(this)); this.setDefaultRenderer(Color.class, new ColorCellRenderer()); this.getTableHeader().setReorderingAllowed(false); this.getTableHeader().setResizingAllowed(false); this.addMouseListener(new MouseAdapter() { @Override public void mouseExited(MouseEvent e) { //Repaint Rectangle oldCell = getCellRect(mouseRow, mouseColumn, true); repaint(oldCell); //Reset mouseRow = -1; mouseColumn = -1; } }); this.addMouseMotionListener(new MouseAdapter() { @Override public void mouseMoved(MouseEvent e) { boolean update = false; int oldRow = mouseRow; int newRow = rowAtPoint(e.getPoint()); if (newRow != mouseRow) { mouseRow = newRow; update = true; } int oldColumn = mouseColumn; int newColumn = columnAtPoint(e.getPoint()); if (newColumn != mouseColumn) { mouseColumn = newColumn; update = true; } if (update) { Rectangle oldCell = getCellRect(oldRow, oldColumn, true); Rectangle newCell = getCellRect(newRow, newColumn, true); repaint(oldCell); repaint(newCell); } } }); jForeground = new MyComboBox(); jBackground = new MyComboBox(); jNotEditable = new JNullableLabel(); jNotEditable.setBackground(null); jPreview = new JLabel(DialoguesSettings.get().testText()); jPreview.setOpaque(true); jPreview.setHorizontalAlignment(JLabel.CENTER); jSelected = new JLabel(DialoguesSettings.get().testSelectedText()); jSelected.setOpaque(true); jSelected.setHorizontalAlignment(JLabel.CENTER); } public void startEditCell(int editRow, int editColumn) { this.editRow = editRow; this.editColumn = editColumn; } public void stopEditCell() { //Repaint Rectangle oldCell = getCellRect(editRow, editColumn, true); repaint(oldCell); //Reset editRow = -1; editColumn = -1; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); //boolean isSelected = isCellSelected(row, column); Object object = tableModel.getElementAt(row); if (!(object instanceof ColorRow)) { return component; } ColorRow colorRow = (ColorRow) object; String columnName = (String) this.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); boolean mouseCell = row == mouseRow && column == mouseColumn; boolean editCell = row == editRow && column == editColumn; if (columnName.equals(ColorsTableFormat.BACKGROUND.getColumnName())) { if (colorRow.getColorEntry().isBackgroundEditable()) { jBackground.config(colorRow.getBackground(), colorRow.isBackgroundDefault(), mouseCell, editCell); return jBackground.getjPanel(); } else { return jNotEditable; } } if (columnName.equals(ColorsTableFormat.FOREGROUND.getColumnName())) { if (colorRow.getColorEntry().isForegroundEditable()) { jForeground.config(colorRow.getForeground(), colorRow.isForegroundDefault(), mouseCell, editCell); return jForeground.getjPanel(); } else { return jNotEditable; } } Color background = colorRow.getBackground(); Color foreground = colorRow.getForeground(); if (columnName.equals(ColorsTableFormat.PREVIEW.getColumnName())) { jPreview.setBackground(this.getBackground()); jPreview.setForeground(this.getForeground()); ColorSettings.configCell(jPreview, foreground, background, false); return jPreview; } if (columnName.equals(ColorsTableFormat.SELECTED.getColumnName())) { ColorSettings.configCell(jSelected, foreground, background, true); return jSelected; } return component; } public static class ColorCellRenderer extends DefaultTableCellRenderer { @Override public void setValue(final Object value) { setText(""); } } private static class IconTableCellRenderer implements TableCellRenderer { private final JTable jTable; private TableCellRenderer tableCellRenderer; public IconTableCellRenderer(JTable jTable) { this.jTable = jTable; this.tableCellRenderer = jTable.getTableHeader().getDefaultRenderer(); if (tableCellRenderer.getClass().getName().contains("XPDefaultRenderer")) { installWorkaround(); } } private void installWorkaround() { jTable.getTableHeader().addPropertyChangeListener("UI", new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { /** * Workaround for: https://github.com/GoldenGnu/jeveassets/issues/279 (JDK-6429812) * On TableHeader UI update: * Create decoupled DefaultTableCellHeaderRenderer to replace the now defunct wrapped renderer */ IconTableCellRenderer.this.tableCellRenderer = new JTableHeader() { @Override public TableCellRenderer createDefaultRenderer() { return super.createDefaultRenderer(); } }.createDefaultRenderer(); } }); } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component component = tableCellRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); String columnName = (String) jTable.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); if (component instanceof JLabel) { JLabel jLabel = (JLabel) component; if (columnName.equals(ColorsTableFormat.NAME.getColumnName())) { jLabel.setHorizontalAlignment(JLabel.LEFT); } if (columnName.equals(ColorsTableFormat.BACKGROUND.getColumnName())) { jLabel.setText(""); jLabel.setIcon(Images.SETTINGS_COLOR_BACKGROUND.getIcon()); jLabel.setHorizontalAlignment(JLabel.CENTER); } if (columnName.equals(ColorsTableFormat.FOREGROUND.getColumnName())) { jLabel.setText(""); jLabel.setIcon(Images.SETTINGS_COLOR_FOREGROUND.getIcon()); jLabel.setHorizontalAlignment(JLabel.CENTER); } if (columnName.equals(ColorsTableFormat.PREVIEW.getColumnName())) { jLabel.setText(""); jLabel.setIcon(Images.EDIT_SHOW.getIcon()); jLabel.setHorizontalAlignment(JLabel.CENTER); } if (columnName.equals(ColorsTableFormat.SELECTED.getColumnName())) { jLabel.setText(""); jLabel.setIcon(Images.EDIT_SHOW.getIcon()); jLabel.setHorizontalAlignment(JLabel.CENTER); } } return component; } } private class MyComboBox { private final static double FACTOR = 0.9; private final JPanel jPanel; private final JNullableLabel jDefault; private final JLabel jPickerIcon; public MyComboBox() { jPanel = new JPanel(); GroupLayout layout = new GroupLayout(jPanel); jPanel.setLayout(layout); layout.setAutoCreateGaps(false); layout.setAutoCreateContainerGaps(false); jDefault = new JNullableLabel(); jDefault.setHorizontalAlignment(JLabel.CENTER); jDefault.setVerticalAlignment(JLabel.CENTER); jDefault.setOpaque(true); jPickerIcon = new JLabel(Images.SETTINGS_COLOR_PICKER.getIcon()); jPickerIcon.setHorizontalTextPosition(JLabel.CENTER); jPickerIcon.setHorizontalAlignment(JLabel.CENTER); jPickerIcon.setVerticalAlignment(JLabel.CENTER); jPickerIcon.setOpaque(true); layout.setHorizontalGroup( layout.createSequentialGroup() .addComponent(jDefault, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jPickerIcon, 16, 16, 16) ); layout.setVerticalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jDefault, 0, 0, Integer.MAX_VALUE) .addComponent(jPickerIcon, 0, 0, Integer.MAX_VALUE) ); } public JComponent getjPanel() { return jPanel; } public void config(Color color, boolean isDefault, boolean mouseCell, boolean editCell) { jDefault.setBackground(color); if (color == null) { color = Colors.TABLE_SELECTION_FOREGROUND.getColor(); } boolean isBrightColor = ColorUtil.isBrightColor(color); if (editCell) { jPanel.setBorder(BorderFactory.createLineBorder(getSelectionBackground().darker(), 1)); jDefault.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, ColorUtil.brighter(getSelectionBackground().darker(), FACTOR))); } else if (mouseCell) { jPanel.setBorder(BorderFactory.createLineBorder(getSelectionBackground(), 1)); jDefault.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, ColorUtil.brighter(getSelectionBackground(), FACTOR))); } else { jPanel.setBorder(BorderFactory.createLineBorder(jPickerIcon.getBackground(), 1)); if (isBrightColor) { jDefault.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, color.darker())); } else { jDefault.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, ColorUtil.brighter(color, FACTOR))); } } if (isDefault) { jDefault.setIcon(null); } else { if (isBrightColor) { jDefault.setIcon(Images.SETTINGS_COLOR_CHECK_BLACK_ALPHA.getIcon()); } else { jDefault.setIcon(Images.SETTINGS_COLOR_CHECK_WHITE_ALPHA.getIcon()); } } } } private static class JNullableLabel extends JLabel { boolean paintBackground = false; @Override public void setBackground(Color bg) { super.setBackground(bg); if (bg == null) { paintBackground = true; this.setOpaque(false); } else { paintBackground = false; this.setOpaque(true); } } @Override public void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g; if (paintBackground) { boolean firstDark = true; boolean dark; for (int y = 0; y < getSize().getHeight() + 4; y = y + 4) { if (firstDark) { firstDark = false; dark = true; } else { firstDark = true; dark = false; } for (int x = 0; x < getSize().getWidth() + 4; x = x + 4) { if (dark) { g2d.setColor(Color.GRAY); dark = false; } else { g2d.setColor(Color.LIGHT_GRAY); dark = true; } g2d.fillRect(x, y, 4, 4); } } } super.paintComponent(g); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/JSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.Window; import javax.swing.GroupLayout; import javax.swing.Icon; import javax.swing.JPanel; import javax.swing.tree.DefaultMutableTreeNode; import net.nikr.eve.jeveasset.Program; public abstract class JSettingsPanel { public static enum UpdateType { NONE, FULL_UPDATE, UPDATE_OVERVIEW, UPDATE_TAGS, UPDATE_ASSET_TABLES, FULL_REPAINT, REPAINT_MARKET_ORDERS_TABLE, REPAINT_STOCKPILE_TABLE, } protected Program program; protected String title; protected JPanel jPanel; protected GroupLayout layout; protected Window parent; protected DefaultMutableTreeNode treeNode; private final Icon icon; public JSettingsPanel(final Program program, final SettingsDialog settingsDialog, final String title, final Icon icon) { this.program = program; this.title = title; this.parent = settingsDialog.getDialog(); this.icon = icon; jPanel = new JPanel(); layout = new GroupLayout(jPanel); jPanel.setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(true); } public abstract UpdateType save(); public abstract void load(); public JPanel getPanel() { return jPanel; } public String getTitle() { return title; } public DefaultMutableTreeNode getTreeNode() { return treeNode; } public void setTreeNode(DefaultMutableTreeNode treeNode) { this.treeNode = treeNode; } public Icon getIcon() { return icon; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/JUserListPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.*; import java.util.Map.Entry; import javax.swing.*; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.gui.shared.JOptionInput; import net.nikr.eve.jeveasset.gui.shared.components.JLabelMultiline; import net.nikr.eve.jeveasset.gui.shared.components.ListComboBoxModel; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public abstract class JUserListPanel> extends JSettingsPanel { private enum UserListAction { DELETE, EDIT } private final JComboBox> jItems; private final JButton jEdit; private final JButton jDelete; private Map> items; private List> listItems; private final String type; public JUserListPanel(final Program program, final SettingsDialog optionsDialog, final Icon icon, final String title, final String type, final String help) { super(program, optionsDialog, title, icon); this.type = type; ListenerClass listener = new ListenerClass(); jItems = new JComboBox<>(); jEdit = new JButton(DialoguesSettings.get().editItem()); jEdit.setActionCommand(UserListAction.EDIT.name()); jEdit.addActionListener(listener); jDelete = new JButton(DialoguesSettings.get().deleteItem()); jDelete.setActionCommand(UserListAction.DELETE.name()); jDelete.addActionListener(listener); JLabelMultiline jHelp = new JLabelMultiline(help); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jItems) .addGroup(layout.createSequentialGroup() .addComponent(jEdit, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jDelete, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) .addComponent(jHelp, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jItems, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup() .addComponent(jEdit, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDelete, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jHelp, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ); } protected abstract Map> getItems(); protected abstract void setItems(Map> items); protected abstract V valueOf(String value); protected abstract UserItem newUserItem(UserItem userItem); protected abstract void updateEventList(List keys); private void setEnabledAll(final boolean b) { jItems.setEnabled(b); jEdit.setEnabled(b); jDelete.setEnabled(b); } //Work on live data AKA getItems() - no need to re-cache (never cancel) or update GUI (never shown) public boolean contains(final List> userItems) { for (UserItem userItem : userItems) { if (getItems().containsKey(userItem.getKey())) { return true; } } return false; } //Work on live data AKA getItems() - no need to re-cache (never cancel) or update GUI (never shown) public boolean containsKey(final Set key) { for (K k : key) { if (getItems().containsKey(k)) { return true; } } return false; } public void edit(final UserItem userItem) { edit(Collections.singletonList(userItem), true, null); } public boolean edit(final List> userItems) { return edit(userItems, true, null); } private boolean edit(final UserItem userItem, final boolean save) { return edit(Collections.singletonList(userItem), save, null); } private boolean edit(final List> userItems, final boolean save, final String oldValue) { if (save) { load(); } String name; String formattedValue = oldValue; if (userItems.size() == 1) { name = userItems.get(0).getName(); if (oldValue == null) { formattedValue = userItems.get(0).getValueFormatted(); } } else { name = DialoguesSettings.get().items(userItems.size()); } if (formattedValue == null) { formattedValue = "0"; } String value = (String) JOptionInput.showInputDialog(program.getMainWindow().getFrame(), name, DialoguesSettings.get().editTypeTitle(type), JOptionPane.PLAIN_MESSAGE, null, null, formattedValue); if (value == null) { return false; //Cancel } V v = valueOf(value); if (v != null) { //Update value List containedKeys = new ArrayList<>(); for (UserItem userItem : userItems) { UserItem userItemExisting = items.get(userItem.getKey()); if (userItemExisting == null) { //Add new userItemExisting = userItem; items.put(userItem.getKey(), userItem); } containedKeys.add(userItem.getKey()); //Update Value userItemExisting.setValue(v); } //Update GUI updateGUI(); if (save) { //Save (if not in settings dialog) Settings.lock("Custom Price/Name (Edit)"); //Lock for Custom Price/Name (Edit) UpdateType updateType = save(); Settings.unlock("Custom Price/Name (Edit)"); //Unlock for Custom Price/Name (Edit) if (updateType == UpdateType.FULL_UPDATE) { //FIXME - - - > Price/Name: Update Price/Name (no need to update all date - just need to update the data in tags column) updateEventList(containedKeys); } program.saveSettings("Custom Price/Name (Edit)"); //Save Custom Price/Name (Edit) } return true; } else { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), DialoguesSettings.get().inputNotValid(), DialoguesSettings.get().badInput(), JOptionPane.PLAIN_MESSAGE); return edit(userItems, save, value); } } public void delete(final List> userItems) { delete(userItems, true); } private void delete(final UserItem userItem, final boolean save) { delete(Collections.singletonList(userItem), save); } private void delete(final List> userItems, final boolean save) { if (save) { load(); } int count = 0; String name = ""; //Never used List containedKeys = new ArrayList<>(); for (UserItem userItem : userItems) { if (items.containsKey(userItem.getKey())) { count++; name = userItem.getName(); containedKeys.add(userItem.getKey()); } } if (count > 1) { name = DialoguesSettings.get().items(count); } if (name.isEmpty()) { //this should never happen! return; } int value = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), name, DialoguesSettings.get().deleteTypeTitle(type), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (value == JOptionPane.OK_OPTION) { items.keySet().removeAll(containedKeys); updateGUI(); if (save) { //Save (if not in settings dialog) Settings.lock("Custom Price/Name (Delete)"); //Lock for Custom Price/Name (Delete) UpdateType updateType = save(); Settings.unlock("Custom Price/Name (Delete)"); //Unlock for Custom Price/Name (Delete) if (updateType == UpdateType.FULL_UPDATE) { updateEventList(containedKeys); } program.saveSettings("Custom Price/Name (Delete)"); //Save Custom Price/Name (Delete) } } } private void updateGUI() { if (items.isEmpty()) { setEnabledAll(false); jItems.setModel(new ListComboBoxModel<>()); jItems.getModel().setSelectedItem(DialoguesSettings.get().itemEmpty()); listItems = new ArrayList<>(); //Clear list } else { setEnabledAll(true); listItems = new ArrayList<>(new TreeSet<>(items.values())); jItems.setModel(new ListComboBoxModel<>(listItems)); } } @Override public UpdateType save() { boolean update = !getItems().equals(items); //Update Settings setItems(items); //Update this int selected = jItems.getSelectedIndex(); if (update) { load(); } if (selected >= 0) { jItems.setSelectedIndex(selected); } //Update table if needed return update ? UpdateType.FULL_UPDATE : UpdateType.NONE; } @Override public void load() { items = new HashMap<>(); for (Entry> entry : getItems().entrySet()) { UserItem userItem = newUserItem(entry.getValue()); items.put(entry.getKey(), userItem); } updateGUI(); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (UserListAction.DELETE.name().equals(e.getActionCommand())) { int index = jItems.getSelectedIndex(); if (index >= 0) { delete(listItems.get(index), false); } } if (UserListAction.EDIT.name().equals(e.getActionCommand())) { int index = jItems.getSelectedIndex(); if (index >= 0) { edit(listItems.get(index), false); } } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/JournalToolSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import javax.swing.GroupLayout; import javax.swing.JCheckBox; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JLabelMultiline; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class JournalToolSettingsPanel extends JSettingsPanel { private final JCheckBox jSaveHistory; public JournalToolSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().journal(), Images.TOOL_JOURNAL.getIcon()); jSaveHistory = new JCheckBox(DialoguesSettings.get().journalSaveHistory()); JLabelMultiline jSaveHistoryWarning = new JLabelMultiline(DialoguesSettings.get().saveHistoryWarning(), 2); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jSaveHistory) .addComponent(jSaveHistoryWarning, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jSaveHistory, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSaveHistoryWarning, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ); } @Override public UpdateType save() { Settings.get().setJournalHistory(jSaveHistory.isSelected()); return UpdateType.NONE; } @Override public void load() { jSaveHistory.setSelected(Settings.get().isJournalHistory()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/JumpsSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import javax.swing.BorderFactory; import javax.swing.GroupLayout; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.RouteFinder.RouteFinderFilter; import net.nikr.eve.jeveasset.data.settings.RouteAvoidSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuUI.EveGatecampCheck; import net.nikr.eve.jeveasset.gui.tabs.routing.JAvoid; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class JumpsSettingsPanel extends JSettingsPanel { private final JAvoid jAvoid; private final JComboBox jOpenOptions; private final JComboBox jRouteOptions; private final RouteAvoidSettings avoidSettings = new RouteAvoidSettings(); public JumpsSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().jumps(), Images.TOOL_ROUTING.getIcon()); jAvoid = new JAvoid(program, avoidSettings, false, null); jAvoid.updateSystemDialog(RouteFinderFilter.JUMPS.getGraph().getNodes()); JPanel jEveGatecampCheck = new JPanel(); jEveGatecampCheck.setBorder(BorderFactory.createTitledBorder(DialoguesSettings.get().eveGatecampCheck())); GroupLayout eveGatecampCheckLayout = new GroupLayout(jEveGatecampCheck); jEveGatecampCheck.setLayout(eveGatecampCheckLayout); eveGatecampCheckLayout.setAutoCreateGaps(true); eveGatecampCheckLayout.setAutoCreateContainerGaps(true); JLabel jOpenOptionsLabel = new JLabel(DialoguesSettings.get().eveGatecampCheckOpenOptions()); jOpenOptions = new JComboBox<>(EveGatecampCheck.EVE_GATECAMP_CHECK_OPEN_OPTIONS); JLabel jRouteOptionsLabel = new JLabel(DialoguesSettings.get().eveGatecampCheckRouteOptions()); jRouteOptions = new JComboBox<>(EveGatecampCheck.EVE_GATECAMP_CHECK_ROUTE_OPTIONS); eveGatecampCheckLayout.setHorizontalGroup( eveGatecampCheckLayout.createSequentialGroup() .addComponent(jOpenOptionsLabel) .addComponent(jOpenOptions) .addComponent(jRouteOptionsLabel) .addComponent(jRouteOptions) ); eveGatecampCheckLayout.setVerticalGroup( eveGatecampCheckLayout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jOpenOptionsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOpenOptions, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRouteOptionsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRouteOptions, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jAvoid.getSecurityPanel()) .addComponent(jAvoid.getAvoidPanel()) .addComponent(jAvoid.getAvoidPanel()) .addComponent(jEveGatecampCheck) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jAvoid.getSecurityPanel()) .addComponent(jAvoid.getAvoidPanel()) .addComponent(jEveGatecampCheck) ); } @Override public UpdateType save() { RouteAvoidSettings current = Settings.get().getJumpsAvoidSettings(); if (!current.equals(avoidSettings)) { current.update(avoidSettings); RouteFinderFilter.JUMPS.update(); jAvoid.updateSystemDialog(RouteFinderFilter.JUMPS.getGraph().getNodes()); return UpdateType.FULL_UPDATE; } EveGatecampCheck.setOpenOption(jOpenOptions.getSelectedItem()); EveGatecampCheck.setRouteOption(jRouteOptions.getSelectedItem()); return UpdateType.NONE; } @Override public void load() { jAvoid.setData(Settings.get().getJumpsAvoidSettings()); jOpenOptions.setSelectedItem(EveGatecampCheck.getOpenOption()); jRouteOptions.setSelectedItem(EveGatecampCheck.getRouteOption()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/LookAndFeelPreview.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.awt.image.BufferedImage; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JTextField; import javax.swing.LookAndFeel; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LookAndFeelPreview { private static final Logger LOG = LoggerFactory.getLogger(LookAndFeelPreview.class); public static void install(String lookAndFeelClass, JDropDownButton jDropDownButton, JComponent jComponent, SettingsDialog settingsDialog) { LookAndFeelPreviewListener listener = new LookAndFeelPreviewListener(lookAndFeelClass, jDropDownButton, jComponent, settingsDialog); } private LookAndFeelPreview() { } private static class LookAndFeelPreviewListener implements PopupMenuListener, MouseListener, WindowListener { private static PreviewMock previewWindowMock; private final String lookAndFeelClass; private final JComponent jComponent; private final SettingsDialog settingsDialog; private BufferedImage bufferedImage; public LookAndFeelPreviewListener(String lookAndFeelClass, JDropDownButton jDropDownButton, JComponent jComponent, SettingsDialog settingsDialog) { this.lookAndFeelClass = lookAndFeelClass; this.jComponent = jComponent; this.settingsDialog = settingsDialog; jComponent.addMouseListener(this); jDropDownButton.getPopupMenu().addPopupMenuListener(this); settingsDialog.getDialog().addWindowListener(this); if (previewWindowMock == null) { previewWindowMock = new PreviewMock(); settingsDialog.getDialog().setGlassPane(previewWindowMock); } } @Override public void mouseEntered(MouseEvent e) { show(); } @Override public void mouseExited(MouseEvent e) { hide(); } @Override public void mouseClicked(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { hide(); } @Override public void popupMenuCanceled(PopupMenuEvent e) { hide(); } @Override public void windowOpened(WindowEvent e) { if (bufferedImage == null) { try { LookAndFeel currentLAF = UIManager.getLookAndFeel(); UIManager.setLookAndFeel(lookAndFeelClass); PreviewComponent previewComponent = new PreviewComponent(); SwingUtilities.updateComponentTreeUI(previewComponent.getOuter()); settingsDialog.addCard(previewComponent.getOuter(), lookAndFeelClass); settingsDialog.getDialog().revalidate(); bufferedImage = createImage(previewComponent.getInner()); settingsDialog.removeCard(previewComponent.getOuter()); UIManager.setLookAndFeel(currentLAF); SwingUtilities.updateComponentTreeUI(previewComponent.getOuter()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { LOG.error(ex.getMessage(), ex); } } } @Override public void windowClosing(WindowEvent e) {} @Override public void windowClosed(WindowEvent e) {} @Override public void windowIconified(WindowEvent e) {} @Override public void windowDeiconified(WindowEvent e) {} @Override public void windowActivated(WindowEvent e) {} @Override public void windowDeactivated(WindowEvent e) { } private void show() { previewWindowMock.config(bufferedImage, jComponent); previewWindowMock.setVisible(true); } private void hide() { previewWindowMock.setVisible(false); } } public static BufferedImage createImage(Component comp) { int w = comp.getWidth(); int h = comp.getHeight(); BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); Graphics2D g = bi.createGraphics(); comp.paint(g); return bi; } private static class PreviewComponent { private static final int WIDTH = 100; private static final int SIZE = (WIDTH * 2) + 30; private final JPanel jInner; private final JPanel jOuter; private PreviewComponent() { jInner = new JPanel(); GroupLayout innerLayout = new GroupLayout(jInner); jInner.setLayout(innerLayout); innerLayout.setAutoCreateGaps(true); innerLayout.setAutoCreateContainerGaps(true); String[] comboBoxValues = {"ComboBox"}; JComboBox jComboBox = new JComboBox<>(comboBoxValues); JTextField jTextField = new JTextField("TextField"); JButton jButton = new JButton("Button"); JLabel jLabel = new JLabel("Label"); JCheckBox jCheckBox = new JCheckBox("CheckBox"); jCheckBox.setSelected(true); JRadioButton jRadioButton = new JRadioButton("RadioButton"); jRadioButton.setSelected(true); int height = 22; height = Math.max(height, new JComboBox<>().getPreferredSize().height); height = Math.max(height, new JTextField().getPreferredSize().height); height = Math.max(height, new JButton().getPreferredSize().height); innerLayout.setHorizontalGroup( innerLayout.createSequentialGroup() .addGroup(innerLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jTextField, WIDTH, WIDTH, WIDTH) .addComponent(jLabel, WIDTH, WIDTH, WIDTH) .addComponent(jCheckBox, WIDTH, WIDTH, WIDTH) ) .addGroup(innerLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jComboBox, WIDTH, WIDTH, WIDTH) .addComponent(jButton, WIDTH, WIDTH, WIDTH) .addComponent(jRadioButton, WIDTH, WIDTH, WIDTH) ) ); innerLayout.setVerticalGroup( innerLayout.createSequentialGroup() .addGroup(innerLayout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jTextField, height, height, height) .addComponent(jComboBox, height, height, height) ) .addGroup(innerLayout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jLabel, height, height, height) .addComponent(jButton, height, height, height) ) .addGroup(innerLayout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jCheckBox, height, height, height) .addComponent(jRadioButton, height, height, height) ) ); jOuter = new JPanel(); GroupLayout outerLayout = new GroupLayout(jOuter); jOuter.setLayout(outerLayout); outerLayout.setAutoCreateGaps(false); outerLayout.setAutoCreateContainerGaps(false); outerLayout.setHorizontalGroup( outerLayout.createSequentialGroup() .addComponent(jInner, SIZE, SIZE, SIZE) ); outerLayout.setVerticalGroup( outerLayout.createSequentialGroup() .addComponent(jInner) .addGap(0, 0, Integer.MAX_VALUE) ); } public JPanel getInner() { return jInner; } public JPanel getOuter() { return jOuter; } } private static class PreviewMock extends JComponent { private static final int OFFSET = 2; private static final int BORDER = 2; private BufferedImage bufferedImage; private JComponent jComponent; private Point point; private PreviewMock() { } public void config(BufferedImage bufferedImage, JComponent jComponent) { this.bufferedImage = bufferedImage; this.jComponent = jComponent; point = SwingUtilities.convertPoint(jComponent, new Point(0, 0), this); } public BufferedImage getBufferedImage() { return bufferedImage; } @Override public void paint(Graphics g) { if (bufferedImage != null) { Graphics2D graphics2D = (Graphics2D) g; graphics2D.setColor(Color.BLACK); graphics2D.fillRect(point.x + jComponent.getWidth() + OFFSET, point.y, bufferedImage.getWidth() + BORDER * 2, bufferedImage.getHeight() + BORDER * 2); graphics2D.drawImage(bufferedImage, point.x + jComponent.getWidth() + OFFSET + BORDER, point.y + BORDER, null); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/ManufacturingSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.TextFilterator; import ca.odell.glazedlists.swing.AutoCompleteSupport; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import java.util.Objects; import javax.swing.GroupLayout; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JSpinner; import javax.swing.SpinnerNumberModel; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingFacility; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingRigs; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingSecurity; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.InstantToolTip; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class ManufacturingSettingsPanel extends JSettingsPanel { private final JComboBox jSystems; private final JComboBox jMe; private final JComboBox jFacility; private final JComboBox jRigs; private final JComboBox jSecurity; private final SpinnerNumberModel taxModel; private final JLabel jSystemWarning; //Data private final AutoCompleteSupport systemsAutoComplete; private final EventList systemsEventList; public ManufacturingSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().manufacturing(), Images.SETTINGS_MANUFACTURING.getIcon()); systemsEventList = EventListManager.create(); SystemIndex system = null; List systems = new ArrayList<>(); for (MyLocation location : StaticData.get().getLocations()) { if (location.isSystem()) { SystemIndex systemIndex = new SystemIndex(location); systems.add(systemIndex); if (system == null || system.toString().length() < systemIndex.toString().length()) { system = systemIndex; } } } updateSystemList(systems); systemsEventList.getReadWriteLock().readLock().lock(); SortedList systemsSortedList = new SortedList<>(systemsEventList); systemsEventList.getReadWriteLock().readLock().unlock(); JLabel jSystemsLabel = new JLabel(DialoguesSettings.get().manufacturingSystems()); jSystems = new JComboBox<>(); if (system != null) { jSystems.setPrototypeDisplayValue(system); } systemsAutoComplete = AutoCompleteSupport.install(jSystems, EventModels.createSwingThreadProxyList(systemsSortedList), new SystemIndexFilterator()); systemsAutoComplete.setStrict(true); jSystemWarning = new JLabel(Images.UPDATE_DONE_ERROR.getIcon()); jSystemWarning.setVisible(false); jSystemWarning.setToolTipText(DialoguesSettings.get().manufacturingSystemsWarning()); InstantToolTip.install(jSystemWarning); JLabel jManufacturingMeLabel = new JLabel(DialoguesSettings.get().manufacturingME()); Integer[] me = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; jMe = new JComboBox<>(me); jMe.setPrototypeDisplayValue(10); jMe.setMaximumRowCount(me.length); JLabel jFacilityLabel = new JLabel(DialoguesSettings.get().manufacturingFacility()); jFacility = new JComboBox<>(ManufacturingFacility.values()); jFacility.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ManufacturingFacility facility = jFacility.getItemAt(jFacility.getSelectedIndex()); if (facility == ManufacturingFacility.STATION) { jRigs.setSelectedIndex(0); jRigs.setEnabled(false); } else { jRigs.setEnabled(true); } } }); JLabel jRigsLabel = new JLabel(DialoguesSettings.get().manufacturingRigs()); jRigs = new JComboBox<>(ManufacturingRigs.values()); jRigs.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ManufacturingRigs rigs = jRigs.getItemAt(jRigs.getSelectedIndex()); if (rigs == ManufacturingRigs.NONE) { jSecurity.setSelectedIndex(0); jSecurity.setEnabled(false); } else { jSecurity.setEnabled(true); } } }); JLabel jSecurityLabel = new JLabel(DialoguesSettings.get().manufacturingSecurity()); jSecurity = new JComboBox<>(ManufacturingSecurity.values()); taxModel = new SpinnerNumberModel(0.25, 0, 10, 0.01); JLabel jTaxLabel = new JLabel(DialoguesSettings.get().manufacturingTax()); JSpinner jTax = new JSpinner(taxModel); JLabel jTaxPercentLabel = new JLabel(DialoguesSettings.get().manufacturingPercent()); layout.setHorizontalGroup( layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jSystemsLabel) .addComponent(jManufacturingMeLabel) .addComponent(jFacilityLabel) .addComponent(jRigsLabel) .addComponent(jSecurityLabel) .addComponent(jTaxLabel) ) .addGroup(layout.createParallelGroup() .addComponent(jSystems, 200, 200, 200) .addComponent(jMe, 200, 200, 200) .addComponent(jFacility, 200, 200, 200) .addComponent(jRigs, 200, 200, 200) .addComponent(jSecurity, 200, 200, 200) .addComponent(jTax, 200, 200, 200) ) .addGroup(layout.createParallelGroup() .addComponent(jSystemWarning) .addComponent(jTaxPercentLabel) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jSystemsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSystems, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSystemWarning, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jManufacturingMeLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jMe, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jFacilityLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFacility, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jRigsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRigs, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jSecurityLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSecurity, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jTaxLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jTax, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jTaxPercentLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } @Override public UpdateType save() { SystemIndex systemIndex = jSystems.getItemAt(jSystems.getSelectedIndex()); int materialEfficiency = jMe.getItemAt(jMe.getSelectedIndex()); ManufacturingFacility facility = jFacility.getItemAt(jFacility.getSelectedIndex()); ManufacturingRigs rigs = jRigs.getItemAt(jRigs.getSelectedIndex()); ManufacturingSecurity security = jSecurity.getItemAt(jSecurity.getSelectedIndex()); double tax = taxModel.getNumber().doubleValue(); //Eval if table need to be updated boolean update = !Objects.equals(systemIndex.getSystemID(), Settings.get().getManufacturingSettings().getSystemID()) || !Objects.equals(materialEfficiency, Settings.get().getManufacturingSettings().getMaterialEfficiency()) || !Objects.equals(facility, Settings.get().getManufacturingSettings().getFacility()) || !Objects.equals(rigs, Settings.get().getManufacturingSettings().getRigs()) || !Objects.equals(security, Settings.get().getManufacturingSettings().getSecurity()) || !Objects.equals(tax, Settings.get().getManufacturingSettings().getTax()) ; ManufacturingSettings manufacturingSettings = Settings.get().getManufacturingSettings(); manufacturingSettings.setSystemID(systemIndex.getSystemID()); manufacturingSettings.setMaterialEfficiency(materialEfficiency); manufacturingSettings.setFacility(facility); manufacturingSettings.setRigs(rigs); manufacturingSettings.setSecurity(security); manufacturingSettings.setTax(tax); //Update table if needed return update ? UpdateType.FULL_UPDATE : UpdateType.NONE; } @Override public void load() { ManufacturingSettings manufacturingSettings = Settings.get().getManufacturingSettings(); List systems = EventListManager.safeList(systemsEventList); updateSystemList(systems); int systemID = manufacturingSettings.getSystemID(); MyLocation system = ApiIdConverter.getLocation(systemID); if (!system.isEmpty()) { jSystems.setSelectedItem(new SystemIndex(system)); } jSystemWarning.setVisible(manufacturingSettings.isSystemsNeedsUpdating()); jMe.setSelectedItem(manufacturingSettings.getMaterialEfficiency()); jFacility.setSelectedItem(manufacturingSettings.getFacility()); jRigs.setSelectedItem(manufacturingSettings.getRigs()); jSecurity.setSelectedItem(manufacturingSettings.getSecurity()); taxModel.setValue(manufacturingSettings.getTax()); } private void updateSystemList(List systems) { try { systemsEventList.getReadWriteLock().writeLock().lock(); systemsEventList.clear(); systemsEventList.addAll(systems); } finally { systemsEventList.getReadWriteLock().writeLock().unlock(); } } public static class SystemIndex implements Comparable { private final MyLocation location; public SystemIndex(MyLocation location) { this.location = location; } public int getSystemID() { return (int) location.getLocationID(); } @Override public String toString() { Float index = Settings.get().getManufacturingSettings().getSystems().get((int) location.getLocationID()); if (index != null) { return location.getLocation() + " (" + Formatter.floatFormat(index * 100) + "%)"; } else { return location.getLocation(); } } @Override public int compareTo(SystemIndex o) { return this.toString().compareTo(o.toString()); } @Override public int hashCode() { int hash = 3; hash = 59 * hash + Objects.hashCode(this.location); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final SystemIndex other = (SystemIndex) obj; return Objects.equals(this.location, other.location); } } public static class SystemIndexFilterator implements TextFilterator { @Override public void getFilterStrings(final List baseList, final SystemIndex element) { baseList.add(element.toString()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/MarketOrdersToolSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import javax.swing.GroupLayout; import javax.swing.JCheckBox; import javax.swing.JLabel; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.MarketOrdersSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.DocumentFactory.ValueFlag; import net.nikr.eve.jeveasset.gui.shared.components.JIntegerField; import net.nikr.eve.jeveasset.gui.shared.components.JLabelMultiline; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class MarketOrdersToolSettingsPanel extends JSettingsPanel { private final JCheckBox jSaveHistory; private final JIntegerField jExpireWarnDays; private final JIntegerField jRemainingWarnPercent; public MarketOrdersToolSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().marketOrders(), Images.TOOL_MARKET_ORDERS.getIcon()); JLabelMultiline jSaveHistoryWarning = new JLabelMultiline(DialoguesSettings.get().saveHistoryWarning(), 2); JLabel jExpireWarnDaysLabel = new JLabel(DialoguesSettings.get().expireWarnDays()); JLabel jRemainingWarnPercentsLabel = new JLabel(DialoguesSettings.get().remainingWarnPercent()); jSaveHistory = new JCheckBox(DialoguesSettings.get().marketOrdersSaveHistory()); jExpireWarnDays = new JIntegerField("0", ValueFlag.POSITIVE_AND_ZERO); jExpireWarnDays.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) {} @Override public void focusLost(FocusEvent e) { try { //Max time of market orders is 90 days so anything over that doesn't make sense if(Integer.parseInt(jExpireWarnDays.getText()) > 90) { jExpireWarnDays.setText("90"); } } catch (NumberFormatException ex) { //No problem } } }); jRemainingWarnPercent = new JIntegerField("10", ValueFlag.POSITIVE_AND_ZERO); jRemainingWarnPercent.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) {} @Override public void focusLost(FocusEvent e) { try { //Max percent that makes sense is 100 so anything over that should be lowered to 100 if(Integer.parseInt(jRemainingWarnPercent.getText()) > 100) { jRemainingWarnPercent.setText("100"); } } catch (NumberFormatException ex) { //No problem } } }); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jSaveHistory) .addComponent(jSaveHistoryWarning, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jExpireWarnDaysLabel) .addComponent(jRemainingWarnPercentsLabel) ) .addGroup(layout.createParallelGroup() .addComponent(jExpireWarnDays) .addComponent(jRemainingWarnPercent) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jSaveHistory, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSaveHistoryWarning, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jExpireWarnDaysLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jExpireWarnDays, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jRemainingWarnPercentsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRemainingWarnPercent, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } @Override public UpdateType save() { int expireWarnDays; try { expireWarnDays = Integer.parseInt(jExpireWarnDays.getText()); } catch (NumberFormatException ex) { expireWarnDays = 0; } int remainingWarnPercent; try { remainingWarnPercent = Integer.parseInt(jRemainingWarnPercent.getText()); } catch (NumberFormatException ex) { remainingWarnPercent = 0; } boolean repaint = Settings.get().getMarketOrdersSettings().getExpireWarnDays() != expireWarnDays || Settings.get().getMarketOrdersSettings().getRemainingWarnPercent() != remainingWarnPercent; Settings.get().setMarketOrderHistory(jSaveHistory.isSelected()); Settings.get().getMarketOrdersSettings().setExpireWarnDays(expireWarnDays); Settings.get().getMarketOrdersSettings().setRemainingWarnPercent(remainingWarnPercent); return repaint ? UpdateType.REPAINT_MARKET_ORDERS_TABLE : UpdateType.NONE; } @Override public void load() { final MarketOrdersSettings marketOrdersSettings = Settings.get().getMarketOrdersSettings(); jSaveHistory.setSelected(Settings.get().isMarketOrderHistory()); jExpireWarnDays.setText(String.valueOf(marketOrdersSettings.getExpireWarnDays())); jRemainingWarnPercent.setText(String.valueOf(marketOrdersSettings.getRemainingWarnPercent())); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/MiningToolSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import javax.swing.GroupLayout; import javax.swing.JCheckBox; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JLabelMultiline; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class MiningToolSettingsPanel extends JSettingsPanel { private final JCheckBox jSaveHistory; public MiningToolSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().mining(), Images.TOOL_MINING.getIcon()); jSaveHistory = new JCheckBox(DialoguesSettings.get().miningSaveHistory()); JLabelMultiline jSaveHistoryWarning = new JLabelMultiline(DialoguesSettings.get().saveHistoryWarning(), 2); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jSaveHistory) .addComponent(jSaveHistoryWarning, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jSaveHistory, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSaveHistoryWarning, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ); } @Override public UpdateType save() { Settings.get().setMiningHistory(jSaveHistory.isSelected()); return UpdateType.NONE; } @Override public void load() { jSaveHistory.setSelected(Settings.get().isMiningHistory()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/OverviewToolSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import javax.swing.GroupLayout; import javax.swing.JCheckBox; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class OverviewToolSettingsPanel extends JSettingsPanel { private final JCheckBox jIgnoreContainers; public OverviewToolSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().overview(), Images.TOOL_OVERVIEW.getIcon()); jIgnoreContainers = new JCheckBox(DialoguesSettings.get().ignoreContainers()); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jIgnoreContainers) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jIgnoreContainers, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } @Override public UpdateType save() { boolean update = jIgnoreContainers.isSelected() != Settings.get().isIgnoreSecureContainers(); Settings.get().setIgnoreSecureContainers(jIgnoreContainers.isSelected()); return update ? UpdateType.UPDATE_OVERVIEW : UpdateType.NONE; } @Override public void load() { jIgnoreContainers.setSelected(Settings.get().isIgnoreSecureContainers()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/PriceDataSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.TextFilterator; import ca.odell.glazedlists.swing.AutoCompleteSupport; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.util.ArrayList; import java.util.List; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JRadioButton; import javax.swing.JTextField; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings.PriceMode; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings.PriceSource; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JLabelMultiline; import net.nikr.eve.jeveasset.gui.shared.components.ListComboBoxModel; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.DesktopUtil; import uk.me.candle.eve.pricing.impl.Janice.JaniceLocation; import uk.me.candle.eve.pricing.options.LocationType; import uk.me.candle.eve.pricing.options.NamedPriceLocation; import uk.me.candle.eve.pricing.options.impl.NamedLocation; public class PriceDataSettingsPanel extends JSettingsPanel { private enum PriceDataSettingsAction { SOURCE_SELECTED, LOCATION_SELECTED, JANICE_GET_API_KEY } private final JRadioButton jRadioRegions; private final JRadioButton jRadioSystems; private final JRadioButton jRadioStations; private final JCheckBox jBlueprintsTech1; private final JCheckBox jBlueprintsTech2; private final JCheckBox jManufacturingDefault; private final JComboBox jRegions; private final JComboBox jSystems; private final JComboBox jStations; private final JComboBox jPriceType; private final JComboBox jPriceReprocessedType; private final JComboBox jPriceManufacturingType; private final JComboBox jSource; private final JButton jJaniceGetApiKey; private final JTextField jJaniceApiKey; private final EventList stationsEventList = EventListManager.create(); private final List stations = new ArrayList<>(); private final AutoCompleteSupport regionsAutoComplete; private final AutoCompleteSupport systemsAutoComplete; private final AutoCompleteSupport stationsAutoComplete; public PriceDataSettingsPanel(final Program program, final SettingsDialog optionsDialog) { super(program, optionsDialog, DialoguesSettings.get().priceData(), Images.SETTINGS_PRICE_DATA.getIcon()); ListenerClass listener = new ListenerClass(); MyLocation system = null; MyLocation station = null; MyLocation region = null; EventList systemsEventList = EventListManager.create(); EventList regionsEventList = EventListManager.create(); try { systemsEventList.getReadWriteLock().writeLock().lock(); regionsEventList.getReadWriteLock().writeLock().lock(); for (MyLocation location : StaticData.get().getLocations()) { if (location.isStation() && !location.isCitadel() && !location.isUserLocation()) { //Ignore citadels and user locations and planets stations.add(location); if (station == null || station.getLocation().length() < location.getLocation().length()) { station = location; } } if (location.isSystem()) { systemsEventList.add(location); if (system == null || system.getLocation().length() < location.getLocation().length()) { system = location; } } //New-eden Regions - Ignore Wormhole and Abyssal if (location.isRegion() && location.getRegionID() >= 10000000 && location.getRegionID() <= 11000000) { regionsEventList.add(location); if (region == null || region.getLocation().length() < location.getLocation().length()) { region = location; } } } } finally { systemsEventList.getReadWriteLock().writeLock().unlock(); regionsEventList.getReadWriteLock().writeLock().unlock(); } systemsEventList.getReadWriteLock().readLock().lock(); SortedList systemsSortedList = new SortedList<>(systemsEventList); systemsEventList.getReadWriteLock().readLock().unlock(); stationsEventList.getReadWriteLock().readLock().lock(); SortedList stationsSortedList = new SortedList<>(stationsEventList); stationsEventList.getReadWriteLock().readLock().unlock(); ButtonGroup group = new ButtonGroup(); jRadioRegions = new JRadioButton(); jRadioRegions.setActionCommand(PriceDataSettingsAction.LOCATION_SELECTED.name()); jRadioRegions.addActionListener(listener); group.add(jRadioRegions); jRadioSystems = new JRadioButton(); jRadioSystems.setActionCommand(PriceDataSettingsAction.LOCATION_SELECTED.name()); jRadioSystems.addActionListener(listener); group.add(jRadioSystems); jRadioStations = new JRadioButton(); jRadioStations.setActionCommand(PriceDataSettingsAction.LOCATION_SELECTED.name()); jRadioStations.addActionListener(listener); group.add(jRadioStations); JLabel jRegionsLabel = new JLabel(DialoguesSettings.get().includeRegions()); jRegions = new JComboBox<>(); jRegions.setPrototypeDisplayValue(region); jRegions.getEditor().getEditorComponent().addFocusListener(listener); regionsAutoComplete = AutoCompleteSupport.install(jRegions, EventModels.createSwingThreadProxyList(regionsEventList), new LocationsFilterator()); regionsAutoComplete.setStrict(true); JLabel jSystemsLabel = new JLabel(DialoguesSettings.get().includeSystems()); jSystems = new JComboBox<>(); jSystems.setPrototypeDisplayValue(system); jSystems.getEditor().getEditorComponent().addFocusListener(listener); systemsAutoComplete = AutoCompleteSupport.install(jSystems, EventModels.createSwingThreadProxyList(systemsSortedList), new LocationsFilterator()); systemsAutoComplete.setStrict(true); JLabel jStationsLabel = new JLabel(DialoguesSettings.get().includeStations()); jStations = new JComboBox<>(); jStations.setPrototypeDisplayValue(station); jStations.getEditor().getEditorComponent().addFocusListener(listener); stationsAutoComplete = AutoCompleteSupport.install(jStations, EventModels.createSwingThreadProxyList(stationsSortedList), new LocationsFilterator()); stationsAutoComplete.setStrict(true); JLabel jPriceTypeLabel = new JLabel(DialoguesSettings.get().price()); jPriceType = new JComboBox<>(PriceMode.values()); JLabel jPriceReprocessedTypeLabel = new JLabel(DialoguesSettings.get().priceReprocessed()); jPriceReprocessedType = new JComboBox<>(PriceMode.values()); JLabel jPriceManufacturingTypeLabel = new JLabel(DialoguesSettings.get().priceManufacturing()); jPriceManufacturingType = new JComboBox<>(PriceMode.values()); JLabel jSourceLabel = new JLabel(DialoguesSettings.get().source()); jSource = new JComboBox<>(PriceSource.values()); jSource.setActionCommand(PriceDataSettingsAction.SOURCE_SELECTED.name()); jSource.addActionListener(listener); JLabel jBlueprintsLabel = new JLabel(DialoguesSettings.get().priceBase()); jBlueprintsTech1 = new JCheckBox(DialoguesSettings.get().priceTech1()); jBlueprintsTech2 = new JCheckBox(DialoguesSettings.get().priceTech2()); JLabel jManufacturingDefaultLabel = new JLabel(DialoguesSettings.get().priceManufacturing()); jManufacturingDefault = new JCheckBox(DialoguesSettings.get().manufacturingDefault()); JLabel jJaniceApiKeyLabel = new JLabel(DialoguesSettings.get().janiceApiKey()); jJaniceApiKey = new JTextField(); jJaniceGetApiKey = new JButton(Images.MISC_HELP.getIcon()); jJaniceGetApiKey.setActionCommand(PriceDataSettingsAction.JANICE_GET_API_KEY.name()); jJaniceGetApiKey.addActionListener(listener); JLabelMultiline jWarning = new JLabelMultiline(DialoguesSettings.get().changeSourceWarning(), 2); layout.setHorizontalGroup( layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jSourceLabel) .addComponent(jPriceTypeLabel) .addComponent(jPriceReprocessedTypeLabel) .addComponent(jPriceManufacturingTypeLabel) .addComponent(jBlueprintsLabel) .addComponent(jManufacturingDefaultLabel) .addComponent(jJaniceApiKeyLabel) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jRegionsLabel) .addComponent(jSystemsLabel) .addComponent(jStationsLabel) ) .addGap(0, 0, 100) .addGroup(layout.createParallelGroup() .addComponent(jRadioRegions, GroupLayout.Alignment.TRAILING) .addComponent(jRadioSystems, GroupLayout.Alignment.TRAILING) .addComponent(jRadioStations, GroupLayout.Alignment.TRAILING) ) ) ) .addGroup(layout.createParallelGroup() .addComponent(jSource, 200, 200, 200) .addComponent(jRegions, 200, 200, 200) .addComponent(jSystems, 200, 200, 200) .addComponent(jStations, 200, 200, 200) .addComponent(jPriceType, 200, 200, 200) .addComponent(jPriceReprocessedType, 200, 200, 200) .addComponent(jPriceManufacturingType, 200, 200, 200) .addComponent(jManufacturingDefault, 200, 200, 200) .addGroup(layout.createSequentialGroup() .addComponent(jJaniceApiKey, 169, 169, 169) .addGap(1) .addComponent(jJaniceGetApiKey, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) ) .addGroup(layout.createSequentialGroup() .addComponent(jBlueprintsTech1) .addComponent(jBlueprintsTech2) ) ) ) .addComponent(jWarning, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jSourceLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSource, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jRegionsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRadioRegions, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRegions, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jSystemsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRadioSystems, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSystems, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jStationsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRadioStations, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jStations, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jPriceTypeLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jPriceType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jPriceReprocessedTypeLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jPriceReprocessedType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jPriceManufacturingTypeLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jPriceManufacturingType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jJaniceApiKeyLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jJaniceApiKey, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jJaniceGetApiKey, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jManufacturingDefaultLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jManufacturingDefault, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jBlueprintsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jBlueprintsTech1, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jBlueprintsTech2, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jWarning, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ); } @Override public UpdateType save() { Long locationID; LocationType locationType = null; Object location = null; if (jRadioRegions.isSelected()) { locationType = LocationType.REGION; location = jRegions.getSelectedItem(); } else if (jRadioSystems.isSelected()) { locationType = LocationType.SYSTEM; location = jSystems.getSelectedItem(); } else if (jRadioStations.isSelected()) { locationType = LocationType.STATION; location = jStations.getSelectedItem(); } if (location instanceof NamedPriceLocation) { NamedPriceLocation priceLocation = (NamedPriceLocation) location; locationID = priceLocation.getLocationID(); } else { //XXX - Workaround for invalid locations: https://eve.nikr.net/jeveassets/bugs/#bugid631 locationID = Settings.get().getPriceDataSettings().getLocationID(); locationType = Settings.get().getPriceDataSettings().getLocationType(); } //Price Type PriceMode priceType = get(jPriceType, Settings.get().getPriceDataSettings().getPriceType()); //Price Reprocessed Type PriceMode priceReprocessedType = get(jPriceReprocessedType, Settings.get().getPriceDataSettings().getPriceReprocessedType()); //Price Manufacturing Type PriceMode priceManufacturingType = get(jPriceManufacturingType, Settings.get().getPriceDataSettings().getPriceManufacturingType()); //Janice String janiceKey = jJaniceApiKey.getText(); //Source PriceSource source = (PriceSource) jSource.getSelectedItem(); //Blueprints boolean blueprintsTech1 = jBlueprintsTech1.isSelected(); boolean blueprintsTech2 = jBlueprintsTech2.isSelected(); //Manufacturing Price for non-market items boolean manufacturingDefault = jManufacturingDefault.isSelected(); //Eval if table need to be updated boolean update = priceType != Settings.get().getPriceDataSettings().getPriceType() || priceReprocessedType != Settings.get().getPriceDataSettings().getPriceReprocessedType() || priceManufacturingType != Settings.get().getPriceDataSettings().getPriceManufacturingType() || blueprintsTech1 != Settings.get().isBlueprintBasePriceTech1() || blueprintsTech2 != Settings.get().isBlueprintBasePriceTech2() || manufacturingDefault != Settings.get().isManufacturingDefault(); //Update settings Settings.get().setPriceDataSettings(new PriceDataSettings(locationType, locationID, source, priceType, priceReprocessedType, priceManufacturingType, janiceKey)); Settings.get().setBlueprintBasePriceTech1(blueprintsTech1); Settings.get().setBlueprintBasePriceTech2(blueprintsTech2); Settings.get().setManufacturingDefault(manufacturingDefault); //Update table if needed return update ? UpdateType.FULL_UPDATE : UpdateType.NONE; } @Override public void load() { jSource.setSelectedItem(Settings.get().getPriceDataSettings().getSource()); jBlueprintsTech1.setSelected(Settings.get().isBlueprintBasePriceTech1()); jBlueprintsTech2.setSelected(Settings.get().isBlueprintBasePriceTech2()); jManufacturingDefault.setSelected(Settings.get().isManufacturingDefault()); jJaniceApiKey.setText(Settings.get().getPriceDataSettings().getJaniceKey()); } private void updateSource(final PriceSource source) { Long locationID = Settings.get().getPriceDataSettings().getLocationID(); LocationType locationType = Settings.get().getPriceDataSettings().getLocationType(); //Price Types set(jPriceType, Settings.get().getPriceDataSettings().getPriceType(), source); //Price Reprocessed Types set(jPriceReprocessedType, Settings.get().getPriceDataSettings().getPriceReprocessedType(), source); //Price Manufacturing Types set(jPriceManufacturingType, Settings.get().getPriceDataSettings().getPriceManufacturingType(), source); jJaniceApiKey.setEnabled(source == PriceSource.JANICE); jJaniceGetApiKey.setEnabled(source == PriceSource.JANICE); //Default jRadioRegions.setSelected(true); //REGIONS if (source.supportRegions()) { regionsAutoComplete.removeFirstItem(); jRegions.setEnabled(true); jRadioRegions.setEnabled(true); } else { jRegions.setEnabled(false); jRadioRegions.setEnabled(false); regionsAutoComplete.setFirstItem(new NamedLocation(DialoguesSettings.get().notConfigurable(), -1, -1)); } if (locationType == LocationType.REGION && jRadioRegions.isEnabled()) { if (locationID != null) { jRegions.setSelectedItem(StaticData.get().getLocation(locationID)); } jRadioRegions.setSelected(true); } else { jRegions.setSelectedIndex(0); } //SYSTEM if (source.supportSystems()) { systemsAutoComplete.removeFirstItem(); jRadioSystems.setEnabled(true); jSystems.setEnabled(true); } else { jRadioSystems.setEnabled(false); jSystems.setEnabled(false); systemsAutoComplete.setFirstItem(new NamedLocation(DialoguesSettings.get().notConfigurable(), -1, -1)); } if (locationType == LocationType.SYSTEM && jRadioSystems.isEnabled()) { if (locationID != null) { jSystems.setSelectedItem(StaticData.get().getLocation(locationID)); } jRadioSystems.setSelected(true); } else { jSystems.setSelectedIndex(0); } //STATION if (source.supportStations()) { List list; if (source == PriceSource.FUZZWORK) { list = new ArrayList<>(); list.add(ApiIdConverter.getLocation(60003760)); list.add(ApiIdConverter.getLocation(60008494)); list.add(ApiIdConverter.getLocation(60011866)); list.add(ApiIdConverter.getLocation(60004588)); list.add(ApiIdConverter.getLocation(60005686)); } else if (source == PriceSource.JANICE) { list = new ArrayList<>(); for (JaniceLocation janiceLocation : JaniceLocation.values()) { list.add(janiceLocation.getPriceLocation()); } locationType = LocationType.STATION; } else { list = stations; } try { stationsEventList.getReadWriteLock().writeLock().lock(); stationsEventList.clear(); stationsEventList.addAll(list); } finally { stationsEventList.getReadWriteLock().writeLock().unlock(); } stationsAutoComplete.removeFirstItem(); jRadioStations.setEnabled(true); jStations.setEnabled(true); } else { jRadioStations.setEnabled(false); jStations.setEnabled(false); stationsAutoComplete.setFirstItem(new NamedLocation(DialoguesSettings.get().notConfigurable(), -1, -1)); } if (locationType == LocationType.STATION && jRadioStations.isEnabled()) { if (locationID != null) { NamedPriceLocation location; if (source == PriceSource.JANICE) { location = JaniceLocation.getLocation(locationID); } else { location = StaticData.get().getLocation(locationID); } if (location != null && EventListManager.contains(stationsEventList, location)) { jStations.setSelectedItem(location); } } jRadioStations.setSelected(true); } else { jStations.setSelectedIndex(0); } } private void set(final JComboBox jComboBox, PriceMode priceMode, final PriceSource source) { jComboBox.setModel(new ListComboBoxModel<>(source.getSupportedPriceModes())); jComboBox.setSelectedItem(priceMode); if (source.getSupportedPriceModes().isEmpty()) { //Empty jComboBox.getModel().setSelectedItem(DialoguesSettings.get().notConfigurable()); jComboBox.setEnabled(false); } else { jComboBox.setEnabled(true); } } private PriceMode get(final JComboBox jComboBox, PriceMode defaultPriceMode) { Object object = jComboBox.getSelectedItem(); if (object instanceof PriceMode) { return (PriceMode) object; } else { return defaultPriceMode; } } private class ListenerClass implements ActionListener, FocusListener { @Override public void actionPerformed(final ActionEvent e) { if (PriceDataSettingsAction.SOURCE_SELECTED.name().equals(e.getActionCommand())) { PriceSource priceSource = (PriceSource) jSource.getSelectedItem(); updateSource(priceSource); } else if (PriceDataSettingsAction.LOCATION_SELECTED.name().equals(e.getActionCommand())) { if (jRadioRegions.isSelected()) { jRegions.requestFocusInWindow(); } else if (jRadioSystems.isSelected()) { jSystems.requestFocusInWindow(); } else if (jRadioStations.isSelected()) { jStations.requestFocusInWindow(); } } else if (PriceDataSettingsAction.JANICE_GET_API_KEY.name().equals(e.getActionCommand())) { int returnValue = JOptionPane.showConfirmDialog(parent, DialoguesSettings.get().janiceApiKeyMsg(), DialoguesSettings.get().janiceApiKeyTitle(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, Images.LINK_JANICE_32.getIcon()); if (returnValue == JOptionPane.OK_OPTION) { DesktopUtil.browse("https://discord.com/invite/7McHR3r", parent); } } } @Override public void focusGained(final FocusEvent e) { if (jRegions.getEditor().getEditorComponent().equals(e.getSource())) { jRadioRegions.setSelected(true); } if (jSystems.getEditor().getEditorComponent().equals(e.getSource())) { jRadioSystems.setSelected(true); } if (jStations.getEditor().getEditorComponent().equals(e.getSource())) { jRadioStations.setSelected(true); } } @Override public void focusLost(final FocusEvent e) { } } static class LocationsFilterator implements TextFilterator { @Override public void getFilterStrings(final List baseList, final NamedPriceLocation element) { baseList.add(element.getLocation()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/PriceHistoryToolSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.PriceHistoryDatabase; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class PriceHistoryToolSettingsPanel extends JSettingsPanel { private final JButton jClearBlacklist; public PriceHistoryToolSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().priceHistory(), Images.TOOL_PRICE_HISTORY.getIcon()); jClearBlacklist = new JButton(DialoguesSettings.get().clearBlacklist()); jClearBlacklist.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int returnValue = JOptionPane.showConfirmDialog(parent, DialoguesSettings.get().clearBlacklistMsg(), DialoguesSettings.get().clearBlacklistTitle(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, Images.LINK_ZKILLBOARD_32.getIcon()); if (returnValue == JOptionPane.OK_OPTION) { PriceHistoryDatabase.clearZBlacklist(); } } }); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jClearBlacklist) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jClearBlacklist, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } @Override public UpdateType save() { return UpdateType.NONE; } @Override public void load() { } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/ProxySettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.Proxy; import javax.swing.*; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ProxyData; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.ListComboBoxModel; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; /** * * @author Flaming Candle */ public class ProxySettingsPanel extends JSettingsPanel { private final JComboBox jProxyType; private final JTextField jProxyAddress; private final JSpinner jProxyPort; private final JCheckBox jEnableAuth; private final JTextField jProxyUsername; private final JPasswordField jProxyPassword; public ProxySettingsPanel(final Program program, final SettingsDialog optionsDialog) { super(program, optionsDialog, DialoguesSettings.get().proxy(), Images.SETTINGS_PROXY.getIcon()); JLabel jProxyTypeLabel = new JLabel(DialoguesSettings.get().type()); jProxyType = new JComboBox<>(new ListComboBoxModel<>(Proxy.Type.values())); jProxyType.setEnabled(true); jProxyType.setPreferredSize(new Dimension(200, (int) jProxyType.getPreferredSize().getHeight())); jProxyType.setSelectedItem(Proxy.Type.DIRECT); jProxyType.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { enableProxy(jProxyType.getSelectedItem() != Proxy.Type.DIRECT); } }); JLabel jProxyAddressLabel = new JLabel(DialoguesSettings.get().address()); jProxyAddress = new JTextField(); jProxyAddress.setEnabled(false); JLabel jProxyPortLabel = new JLabel(DialoguesSettings.get().port()); jProxyPort = new JSpinner(new SpinnerNumberModel(0, 0, 65536, 1)); jProxyPort.setEnabled(false); jEnableAuth = new JCheckBox(DialoguesSettings.get().auth()); jEnableAuth.setSelected(false); jEnableAuth.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jProxyUsername.setEnabled(jEnableAuth.isSelected()); jProxyPassword.setEnabled(jEnableAuth.isSelected()); } }); JLabel jProxyUsernameLabel = new JLabel(DialoguesSettings.get().username()); jProxyUsername = new JTextField(); jProxyUsername.setEnabled(false); JLabel jProxyPasswordLabel = new JLabel(DialoguesSettings.get().password()); jProxyPassword = new JPasswordField(); jProxyPassword.setEnabled(false); // note: the layout is defined in the super class. layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING).addGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jProxyTypeLabel) .addComponent(jProxyAddressLabel) .addComponent(jProxyPortLabel) .addComponent(jProxyUsernameLabel) .addComponent(jProxyPasswordLabel) ) .addGap(10) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jProxyType) .addComponent(jProxyAddress) .addComponent(jProxyPort) .addComponent(jEnableAuth) .addComponent(jProxyUsername) .addComponent(jProxyPassword) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(jProxyTypeLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jProxyType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(jProxyAddressLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jProxyAddress, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(jProxyPortLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jProxyPort, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(jEnableAuth, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(jProxyUsernameLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jProxyUsername, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(jProxyPasswordLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jProxyPassword, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } private void enableProxy(final boolean b) { jProxyAddress.setEnabled(b); jProxyPort.setEnabled(b); if (b) { jEnableAuth.setEnabled(true); jEnableAuth.setSelected(false); jProxyUsername.setEnabled(false); jProxyPassword.setEnabled(false); } else { jEnableAuth.setEnabled(false); jEnableAuth.setSelected(false); jProxyUsername.setEnabled(false); jProxyPassword.setEnabled(false); } } @Override public UpdateType save() { //Save proxy data if (jProxyType.getSelectedItem() != Proxy.Type.DIRECT) { String address = jProxyAddress.getText(); int port = (int) jProxyPort.getValue(); Proxy.Type type = (Proxy.Type) jProxyType.getSelectedItem(); String username; String password; if (jEnableAuth.isSelected()) { username = jProxyUsername.getText(); char[] passwordChars = jProxyPassword.getPassword(); password = String.valueOf(passwordChars); } else { username = null; password = null; } Settings.get().setProxyData(new ProxyData(address, type, port, username, password)); } else { Settings.get().setProxyData(new ProxyData()); } return UpdateType.NONE; } @Override public void load() { ProxyData proxyData = Settings.get().getProxyData(); if (proxyData.getType() == Proxy.Type.DIRECT) { jProxyType.setSelectedItem(Proxy.Type.DIRECT); jProxyAddress.setText(""); jProxyPort.setValue(0); jProxyUsername.setText(""); jProxyPassword.setText(""); enableProxy(false); } else { enableProxy(true); jProxyType.setSelectedItem(proxyData.getType()); jProxyAddress.setText(proxyData.getAddress()); jProxyPort.setValue(proxyData.getPort()); if (proxyData.isAuth()) { jEnableAuth.setSelected(true); jProxyUsername.setEnabled(true); jProxyUsername.setText(proxyData.getUsername()); jProxyPassword.setEnabled(true); jProxyPassword.setText(proxyData.getPassword()); } else { jEnableAuth.setSelected(false); jProxyUsername.setEnabled(false); jProxyUsername.setText(""); jProxyPassword.setEnabled(false); jProxyPassword.setText(""); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/ReprocessingSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.*; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ReprocessSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.DocumentFactory; import net.nikr.eve.jeveasset.gui.shared.components.JDoubleField; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class ReprocessingSettingsPanel extends JSettingsPanel { private static final int LEVEL0 = 0; private static final int LEVEL1 = 1; private static final int LEVEL2 = 2; private static final int LEVEL3 = 3; private static final int LEVEL4 = 4; private static final int LEVEL5 = 5; private final JRadioButton jStation50; private final JRadioButton jStationOther; private final JTextField jStation; private final JRadioButton[] jReprocessing; private final JRadioButton[] jReprocessingEfficiency; private final JRadioButton[] jOreProcessing; private final JRadioButton[] jScrapmetalProcessing; public ReprocessingSettingsPanel(final Program program, final SettingsDialog optionsDialog) { super(program, optionsDialog, DialoguesSettings.get().reprocessing(), Images.SETTINGS_REPROCESSING.getIcon()); ListenerClass listener = new ListenerClass(); JLabel jNotes = new JLabel(DialoguesSettings.get().reprocessingWarning()); JLabel jStationLabel = new JLabel(DialoguesSettings.get().stationEquipment()); jStation50 = new JRadioButton(DialoguesSettings.get().fiftyPercent()); jStation50.addActionListener(listener); jStationOther = new JRadioButton(); jStationOther.addActionListener(listener); jStation = new JDoubleField(DocumentFactory.ValueFlag.POSITIVE_AND_ZERO); jStation.addMouseListener(listener); jStation.setColumns(7); JLabel jStationPercentLabel = new JLabel(DialoguesSettings.get().percentSymbol()); ButtonGroup jStationButtonGroup = new ButtonGroup(); jStationButtonGroup.add(jStation50); jStationButtonGroup.add(jStationOther); JLabel jOre0 = new JLabel(DialoguesSettings.get().zero()); JLabel jOre1 = new JLabel(DialoguesSettings.get().one()); JLabel jOre2 = new JLabel(DialoguesSettings.get().two()); JLabel jOre3 = new JLabel(DialoguesSettings.get().three()); JLabel jOre4 = new JLabel(DialoguesSettings.get().four()); JLabel jOre5 = new JLabel(DialoguesSettings.get().five()); JLabel jReprocessingLabel= new JLabel(DialoguesSettings.get().reprocessingLevel()); jReprocessing = new JRadioButton[6]; jReprocessing[LEVEL0] = new JRadioButton(); jReprocessing[LEVEL0].addActionListener(listener); jReprocessing[LEVEL1] = new JRadioButton(); jReprocessing[LEVEL1].addActionListener(listener); jReprocessing[LEVEL2] = new JRadioButton(); jReprocessing[LEVEL2].addActionListener(listener); jReprocessing[LEVEL3] = new JRadioButton(); jReprocessing[LEVEL3].addActionListener(listener); jReprocessing[LEVEL4] = new JRadioButton(); jReprocessing[LEVEL4].addActionListener(listener); jReprocessing[LEVEL5] = new JRadioButton(); jReprocessing[LEVEL5].addActionListener(listener); ButtonGroup jReprocessingButtonGroup = new ButtonGroup(); jReprocessingButtonGroup.add(jReprocessing[LEVEL0]); jReprocessingButtonGroup.add(jReprocessing[LEVEL1]); jReprocessingButtonGroup.add(jReprocessing[LEVEL2]); jReprocessingButtonGroup.add(jReprocessing[LEVEL3]); jReprocessingButtonGroup.add(jReprocessing[LEVEL4]); jReprocessingButtonGroup.add(jReprocessing[LEVEL5]); JLabel jReprocessingEfficiencyLabel = new JLabel(DialoguesSettings.get().reprocessingEfficiencyLevel()); jReprocessingEfficiency = new JRadioButton[6]; jReprocessingEfficiency[LEVEL0] = new JRadioButton(); jReprocessingEfficiency[LEVEL0].addActionListener(listener); jReprocessingEfficiency[LEVEL1] = new JRadioButton(); jReprocessingEfficiency[LEVEL1].addActionListener(listener); jReprocessingEfficiency[LEVEL2] = new JRadioButton(); jReprocessingEfficiency[LEVEL2].addActionListener(listener); jReprocessingEfficiency[LEVEL3] = new JRadioButton(); jReprocessingEfficiency[LEVEL3].addActionListener(listener); jReprocessingEfficiency[LEVEL4] = new JRadioButton(); jReprocessingEfficiency[LEVEL4].addActionListener(listener); jReprocessingEfficiency[LEVEL5] = new JRadioButton(); jReprocessingEfficiency[LEVEL5].addActionListener(listener); ButtonGroup jReprocessingEfficiencyButtonGroup = new ButtonGroup(); jReprocessingEfficiencyButtonGroup.add(jReprocessingEfficiency[LEVEL0]); jReprocessingEfficiencyButtonGroup.add(jReprocessingEfficiency[LEVEL1]); jReprocessingEfficiencyButtonGroup.add(jReprocessingEfficiency[LEVEL2]); jReprocessingEfficiencyButtonGroup.add(jReprocessingEfficiency[LEVEL3]); jReprocessingEfficiencyButtonGroup.add(jReprocessingEfficiency[LEVEL4]); jReprocessingEfficiencyButtonGroup.add(jReprocessingEfficiency[LEVEL5]); JLabel jOreLabel = new JLabel(DialoguesSettings.get().oreProcessingLevel()); jOreProcessing = new JRadioButton[6]; jOreProcessing[LEVEL0] = new JRadioButton(); jOreProcessing[LEVEL1] = new JRadioButton(); jOreProcessing[LEVEL2] = new JRadioButton(); jOreProcessing[LEVEL3] = new JRadioButton(); jOreProcessing[LEVEL4] = new JRadioButton(); jOreProcessing[LEVEL5] = new JRadioButton(); ButtonGroup jOreButtonGroup = new ButtonGroup(); jOreButtonGroup.add(jOreProcessing[LEVEL0]); jOreButtonGroup.add(jOreProcessing[LEVEL1]); jOreButtonGroup.add(jOreProcessing[LEVEL2]); jOreButtonGroup.add(jOreProcessing[LEVEL3]); jOreButtonGroup.add(jOreProcessing[LEVEL4]); jOreButtonGroup.add(jOreProcessing[LEVEL5]); JLabel jScrap0 = new JLabel(DialoguesSettings.get().zero()); JLabel jScrap1 = new JLabel(DialoguesSettings.get().one()); JLabel jScrap2 = new JLabel(DialoguesSettings.get().two()); JLabel jScrap3 = new JLabel(DialoguesSettings.get().three()); JLabel jScrap4 = new JLabel(DialoguesSettings.get().four()); JLabel jScrap5 = new JLabel(DialoguesSettings.get().five()); JLabel jScrapmetalLabel = new JLabel(DialoguesSettings.get().scrapmetalProcessingLevel()); jScrapmetalProcessing = new JRadioButton[6]; jScrapmetalProcessing[LEVEL0] = new JRadioButton(); jScrapmetalProcessing[LEVEL1] = new JRadioButton(); jScrapmetalProcessing[LEVEL2] = new JRadioButton(); jScrapmetalProcessing[LEVEL3] = new JRadioButton(); jScrapmetalProcessing[LEVEL4] = new JRadioButton(); jScrapmetalProcessing[LEVEL5] = new JRadioButton(); ButtonGroup jScrapmetalButtonGroup = new ButtonGroup(); jScrapmetalButtonGroup.add(jScrapmetalProcessing[LEVEL0]); jScrapmetalButtonGroup.add(jScrapmetalProcessing[LEVEL1]); jScrapmetalButtonGroup.add(jScrapmetalProcessing[LEVEL2]); jScrapmetalButtonGroup.add(jScrapmetalProcessing[LEVEL3]); jScrapmetalButtonGroup.add(jScrapmetalProcessing[LEVEL4]); jScrapmetalButtonGroup.add(jScrapmetalProcessing[LEVEL5]); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jNotes) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jStationLabel) .addComponent(jReprocessingLabel) .addComponent(jReprocessingEfficiencyLabel) .addComponent(jOreLabel) .addComponent(jScrapmetalLabel) ) .addGap(5) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jStation50) .addComponent(jStationOther) .addComponent(jStation, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jStationPercentLabel) ) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jOre0) .addComponent(jReprocessing[LEVEL0]) .addComponent(jReprocessingEfficiency[LEVEL0]) .addComponent(jOreProcessing[LEVEL0]) .addComponent(jScrap0) .addComponent(jScrapmetalProcessing[LEVEL0]) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jOre1) .addComponent(jReprocessing[LEVEL1]) .addComponent(jReprocessingEfficiency[LEVEL1]) .addComponent(jOreProcessing[LEVEL1]) .addComponent(jScrap1) .addComponent(jScrapmetalProcessing[LEVEL1]) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jOre2) .addComponent(jReprocessing[LEVEL2]) .addComponent(jReprocessingEfficiency[LEVEL2]) .addComponent(jOreProcessing[LEVEL2]) .addComponent(jScrap2) .addComponent(jScrapmetalProcessing[LEVEL2]) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jOre3) .addComponent(jReprocessing[LEVEL3]) .addComponent(jReprocessingEfficiency[LEVEL3]) .addComponent(jOreProcessing[LEVEL3]) .addComponent(jScrap3) .addComponent(jScrapmetalProcessing[LEVEL3]) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jOre4) .addComponent(jReprocessing[LEVEL4]) .addComponent(jReprocessingEfficiency[LEVEL4]) .addComponent(jOreProcessing[LEVEL4]) .addComponent(jScrap4) .addComponent(jScrapmetalProcessing[LEVEL4]) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jOre5) .addComponent(jReprocessing[LEVEL5]) .addComponent(jReprocessingEfficiency[LEVEL5]) .addComponent(jOreProcessing[LEVEL5]) .addComponent(jScrap5) .addComponent(jScrapmetalProcessing[LEVEL5]) ) ) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jStationLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jStation50, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jStationOther, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jStation, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jStationPercentLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jOre0, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOre1, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOre2, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOre3, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOre4, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOre5, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(0) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jReprocessingLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jReprocessing[LEVEL0], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jReprocessing[LEVEL1], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jReprocessing[LEVEL2], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jReprocessing[LEVEL3], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jReprocessing[LEVEL4], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jReprocessing[LEVEL5], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jReprocessingEfficiencyLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jReprocessingEfficiency[LEVEL0], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jReprocessingEfficiency[LEVEL1], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jReprocessingEfficiency[LEVEL2], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jReprocessingEfficiency[LEVEL3], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jReprocessingEfficiency[LEVEL4], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jReprocessingEfficiency[LEVEL5], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jOreLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOreProcessing[LEVEL0], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOreProcessing[LEVEL1], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOreProcessing[LEVEL2], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOreProcessing[LEVEL3], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOreProcessing[LEVEL4], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOreProcessing[LEVEL5], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(Program.getButtonsHeight()) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jScrap0, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jScrap1, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jScrap2, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jScrap3, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jScrap4, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jScrap5, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(0) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jScrapmetalLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jScrapmetalProcessing[LEVEL0], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jScrapmetalProcessing[LEVEL1], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jScrapmetalProcessing[LEVEL2], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jScrapmetalProcessing[LEVEL3], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jScrapmetalProcessing[LEVEL4], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jScrapmetalProcessing[LEVEL5], Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(Program.getButtonsHeight()) .addComponent(jNotes, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } @Override public UpdateType save() { ReprocessSettings reprocessSettings = new ReprocessSettings(Double.parseDouble(jStation.getText()), getSelected(jReprocessing), getSelected(jReprocessingEfficiency), getSelected(jOreProcessing), getSelected(jScrapmetalProcessing)); boolean update = !Settings.get().getReprocessSettings().equals(reprocessSettings); Settings.get().setReprocessSettings(reprocessSettings); //Update table if needed return update ? UpdateType.FULL_UPDATE : UpdateType.NONE; } @Override public void load() { ReprocessSettings reprocessSettings = Settings.get().getReprocessSettings(); if (reprocessSettings.getStation() == 50) { jStation50.setSelected(true); } else { jStationOther.setSelected(true); } jStation.setText(String.valueOf(reprocessSettings.getStation())); jReprocessing[reprocessSettings.getReprocessingLevel()].setSelected(true); jReprocessingEfficiency[reprocessSettings.getReprocessingEfficiencyLevel()].setSelected(true); jOreProcessing[reprocessSettings.getOreProcessingLevel()].setSelected(true); jScrapmetalProcessing[reprocessSettings.getScrapmetalProcessingLevel()].setSelected(true); validateSkills(); validateStation(); } private int getSelected(final JRadioButton[] jRadioButtons) { for (int i = 0; i < jRadioButtons.length; i++) { if (jRadioButtons[i].isSelected()) { return i; } } return 0; } private void setEnabled(final JRadioButton[] jRadioButtons, final boolean enabled) { for (JRadioButton jRadioButton : jRadioButtons) { jRadioButton.setEnabled(enabled); } } private void validateSkills() { if (getSelected(jReprocessing) < 4) { setEnabled(jReprocessingEfficiency, false); jReprocessingEfficiency[LEVEL0].setSelected(true); } else { setEnabled(jReprocessingEfficiency, true); } if (getSelected(jReprocessingEfficiency) < 5) { setEnabled(jOreProcessing, false); jOreProcessing[LEVEL0].setSelected(true); } else { setEnabled(jOreProcessing, true); } } private void validateStation() { if (jStation50.isSelected()) { jStation.setText("50"); jStation.setEnabled(false); } if (jStationOther.isSelected()) { jStation.setEnabled(true); } } private class ListenerClass extends MouseAdapter implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { validateSkills(); validateStation(); if (e.getSource().equals(jStationOther)) { jStation.requestFocusInWindow(); jStation.selectAll(); } } @Override public void mouseClicked(MouseEvent e) { jStationOther.setSelected(true); jStation.setEnabled(true); jStation.requestFocusInWindow(); jStation.selectAll(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/SettingsDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.CardLayout; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.swing.GroupLayout; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JTree; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.dialogs.settings.JSettingsPanel.UpdateType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.tabs.orders.MarketOrdersTab; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileTab; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTab; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.io.shared.DesktopUtil; import net.nikr.eve.jeveasset.io.shared.DesktopUtil.HelpLink; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SettingsDialog extends JDialogCentered { private static final Logger LOG = LoggerFactory.getLogger(SettingsDialog.class); private enum SettingsDialogAction { OK, CANCEL, APPLY, HELP } private final JTree jTree; private final JPanel jContent; private final JButton jOK; private final Map settingsPanels; private final Map icons; private final DefaultMutableTreeNode rootNode; private final DefaultTreeModel treeModel; private final CardLayout cardLayout; private final UserPriceSettingsPanel userPriceSettingsPanel; private final UserNameSettingsPanel userNameSettingsPanel; private final UserLocationSettingsPanel locationSettingsPanel; private final JumpsSettingsPanel jumpsSettingsPanel; private boolean tabSelected = false; public SettingsDialog(final Program program) { super(program, DialoguesSettings.get().settings(Program.PROGRAM_NAME), Images.DIALOG_SETTINGS.getImage()); ListenerClass listener = new ListenerClass(); settingsPanels = new HashMap<>(); icons = new HashMap<>(); rootNode = new DefaultMutableTreeNode(DialoguesSettings.get().root()); treeModel = new DefaultTreeModel(rootNode); jTree = new JTree(treeModel); jTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); jTree.putClientProperty("JTree.lineStyle", "None"); jTree.setCellRenderer(new IconTreeCellRenderer(icons)); jTree.setExpandsSelectedPaths(true); jTree.setRootVisible(false); jTree.setShowsRootHandles(true); jTree.addTreeSelectionListener(listener); jTree.setVisibleRowCount(0); cardLayout = new CardLayout(); jContent = new JPanel(cardLayout); GeneralSettingsPanel generalSettingsPanel = new GeneralSettingsPanel(program, this); add(generalSettingsPanel); add(new ExperimentalSettingsPanel(program, this)); DefaultMutableTreeNode toolNode = addGroup(DialoguesSettings.get().tools(), Images.SETTINGS_TOOLS.getIcon()); add(toolNode, new ShowToolSettingsPanel(program, this)); add(toolNode, new AssetsToolSettingsPanel(program, this)); add(toolNode, new OverviewToolSettingsPanel(program, this)); add(toolNode, new StockpileToolSettingsPanel(program, this)); add(toolNode, new MarketOrdersToolSettingsPanel(program, this)); add(toolNode, new TransactionsToolSettingsPanel(program, this)); add(toolNode, new JournalToolSettingsPanel(program, this)); add(toolNode, new IndustryJobsToolSettingsPanel(program, this)); add(toolNode, new ContractToolSettingsPanel(program, this)); add(toolNode, new TrackerToolSettingsPanel(program, this)); add(toolNode, new PriceHistoryToolSettingsPanel(program, this)); add(toolNode, new MiningToolSettingsPanel(program, this)); DefaultMutableTreeNode valuesNode = addGroup(DialoguesSettings.get().values(), Images.EDIT_RENAME.getIcon()); userPriceSettingsPanel = new UserPriceSettingsPanel(program, this); add(valuesNode, userPriceSettingsPanel); userNameSettingsPanel = new UserNameSettingsPanel(program, this); add(valuesNode, userNameSettingsPanel); locationSettingsPanel = new UserLocationSettingsPanel(program, this); add(valuesNode, locationSettingsPanel); add(valuesNode, new TagsSettingsPanel(program, this)); jumpsSettingsPanel = new JumpsSettingsPanel(program, this); add(jumpsSettingsPanel); add(new ColorSettingsPanel(program, this)); add(new SoundsSettingsPanel(program, this)); add(new PriceDataSettingsPanel(program, this)); add(new ReprocessingSettingsPanel(program, this)); add(new ManufacturingSettingsPanel(program, this)); add(new ProxySettingsPanel(program, this)); add(new WindowSettingsPanel(program, this)); JScrollPane jTreeScroller = new JScrollPane(jTree); JSeparator jSeparator = new JSeparator(); JButton jHelp = new JButton(Images.MISC_HELP.getIcon()); jHelp.setActionCommand(SettingsDialogAction.HELP.name()); jHelp.addActionListener(listener); jOK = new JButton(DialoguesSettings.get().ok()); jOK.setActionCommand(SettingsDialogAction.OK.name()); jOK.addActionListener(listener); JButton jApply = new JButton(DialoguesSettings.get().apply()); jApply.setActionCommand(SettingsDialogAction.APPLY.name()); jApply.addActionListener(listener); JButton jCancel = new JButton(DialoguesSettings.get().cancel()); jCancel.setActionCommand(SettingsDialogAction.CANCEL.name()); jCancel.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addGroup(layout.createSequentialGroup() .addComponent(jTreeScroller, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jContent, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ) .addComponent(jSeparator) .addGroup(layout.createSequentialGroup() .addComponent(jHelp, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) .addGap(0, 0, Integer.MAX_VALUE) .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jApply, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jTreeScroller, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jContent, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ) .addComponent(jSeparator, 5, 5, 5) .addGroup(layout.createParallelGroup() .addComponent(jHelp, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jApply, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } private DefaultMutableTreeNode addGroup(final String name, final Icon icon) { SettingsGroup group = new SettingsGroup(program, this, name, icon); add(group); return group.getTreeNode(); } private void add(final JSettingsPanel jSettingsPanel) { add(null, jSettingsPanel); } protected void addCard(final JPanel jPanel, final String title) { jContent.add(jPanel, title); } protected void removeCard(final JPanel jPanel) { jContent.remove(jPanel); } private void add(final DefaultMutableTreeNode parentNode, final JSettingsPanel jSettingsPanel) { settingsPanels.put(jSettingsPanel.getTitle(), jSettingsPanel); icons.put(jSettingsPanel.getTitle(), jSettingsPanel.getIcon()); jContent.add(jSettingsPanel.getPanel(), jSettingsPanel.getTitle()); jTree.setVisibleRowCount(jTree.getVisibleRowCount() + 1); DefaultMutableTreeNode node = new DefaultMutableTreeNode(jSettingsPanel.getTitle()); if (parentNode == null) { treeModel.insertNodeInto(node, rootNode, rootNode.getChildCount()); } else { treeModel.insertNodeInto(node, parentNode, parentNode.getChildCount()); } jSettingsPanel.setTreeNode(node); } public UserNameSettingsPanel getUserNameSettingsPanel() { return userNameSettingsPanel; } public UserPriceSettingsPanel getUserPriceSettingsPanel() { return userPriceSettingsPanel; } public UserLocationSettingsPanel getUserLocationSettingsPanel() { return locationSettingsPanel; } public void showJumpsSettingsPanel() { setVisible(jumpsSettingsPanel); } private void expandAll(final TreePath parent, final boolean expand) { TreeNode node = (TreeNode) parent.getLastPathComponent(); if (node.getChildCount() >= 0) { for (Enumeration e = node.children(); e.hasMoreElements();) { TreeNode n = (TreeNode) e.nextElement(); TreePath path = parent.pathByAddingChild(n); expandAll(path, expand); } } if (expand) { jTree.expandPath(parent); } else { jTree.collapsePath(parent); } } @Override protected JComponent getDefaultFocus() { return jOK; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { } @Override protected void save() { save(true); } private void save(boolean hideWindow) { Set updates = new HashSet<>(); Settings.lock("Settings Dialog"); //Lock for Settings Dialog for (Map.Entry entry : settingsPanels.entrySet()) { UpdateType save = entry.getValue().save(); if (save != UpdateType.NONE) { LOG.info(entry.getKey() + " returned " + save.name()); } updates.add(save); } Settings.unlock("Settings Dialog"); //Unlock for Settings Dialog if (hideWindow) { setVisible(false); } if (updates.contains(UpdateType.FULL_UPDATE)) { if (hideWindow) { program.updateEventListsWithProgress(); } else { program.updateEventListsWithProgress(getDialog()); } } else { if (updates.contains(UpdateType.FULL_REPAINT)) { program.repaintTables(); } else { if (updates.contains(UpdateType.REPAINT_MARKET_ORDERS_TABLE)) { MarketOrdersTab marketOrdersTab = program.getMarketOrdersTab(false); if (marketOrdersTab != null) { marketOrdersTab.repaintTable(); } } if (updates.contains(UpdateType.REPAINT_STOCKPILE_TABLE)) { StockpileTab stockpileTab = program.getStockpileTab(false); if (stockpileTab != null) { stockpileTab.repaintTable(); } } } if (updates.contains(UpdateType.UPDATE_ASSET_TABLES)) { program.getAssetsTab().tableDataChanged(); TreeTab treeTab = program.getTreeTab(false); if (treeTab != null) { treeTab.tableDataChanged(); } } if (updates.contains(UpdateType.UPDATE_OVERVIEW)) { OverviewTab overviewTab = program.getOverviewTab(false); if (overviewTab != null) { overviewTab.updateData(); } } if (updates.contains(UpdateType.UPDATE_TAGS)) { program.updateTags(); } } program.saveSettings("Settings Dialog"); //Save Settings Dialog } public void setVisible(final JSettingsPanel c) { jTree.setSelectionPath(new TreePath(c.getTreeNode().getPath())); tabSelected = true; setVisible(true); } @Override public void setVisible(final boolean b) { if (b) { getDialog().pack(); //XXX - Workaround for LookAndFeelPreview being temperamental and resizing the dialog when generating the LAF previews for (Map.Entry entry : settingsPanels.entrySet()) { entry.getValue().load(); } expandAll(new TreePath((rootNode)), true); if (!tabSelected) { jTree.setSelectionRow(0); } } tabSelected = false; super.setVisible(b); } private class ListenerClass implements ActionListener, TreeSelectionListener { @Override public void actionPerformed(final ActionEvent e) { if (SettingsDialogAction.OK.name().equals(e.getActionCommand())) { save(true); } else if (SettingsDialogAction.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); } else if (SettingsDialogAction.APPLY.name().equals(e.getActionCommand())) { save(false); } else if (SettingsDialogAction.HELP.name().equals(e.getActionCommand())) { DesktopUtil.browse(new HelpLink("https://wiki.jeveassets.org/manual/options", GuiShared.get().helpSettings()), getDialog()); } } @Override public void valueChanged(final TreeSelectionEvent e) { TreePath[] paths = jTree.getSelectionPaths(); if (paths != null && paths.length == 1) { cardLayout.show(jContent, paths[0].getLastPathComponent().toString()); } } } public class IconTreeCellRenderer implements TreeCellRenderer { private Map icons = null; private final DefaultTreeCellRenderer cellRenderer = new DefaultTreeCellRenderer(); public IconTreeCellRenderer(final Map icons) { this.icons = icons; } @Override public Component getTreeCellRendererComponent(final JTree tree, final Object value, final boolean selected, final boolean expanded, final boolean leaf, final int row, final boolean hasFocus) { JLabel label = (JLabel) cellRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); label.setIcon(icons.get(value.toString())); return label; } } private static class SettingsGroup extends JSettingsPanel { public SettingsGroup(final Program program, final SettingsDialog settingsDialog, final String sTitle, final Icon icon) { super(program, settingsDialog, sTitle, icon); } @Override public UpdateType save() { return UpdateType.NONE; } @Override public void load() { } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/ShowToolSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.Component; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DragSource; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.TreeSet; import javax.swing.ButtonGroup; import javax.swing.DefaultListModel; import javax.swing.DropMode; import javax.swing.GroupLayout; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; import javax.swing.TransferHandler; import static javax.swing.TransferHandler.MOVE; import javax.swing.TransferHandler.TransferSupport; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.ToolLoader; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JMainTab; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ShowToolSettingsPanel extends JSettingsPanel { private static final Logger LOG = LoggerFactory.getLogger(ShowToolSettingsPanel.class); private final static double COLUMN_COUNT = 4.0; private final JRadioButton jSelected; private final JRadioButton jSave; private final JLabel jToolsLabel; private final DefaultListModel model = new DefaultListModel<>(); private final JList jTools; TreeSet tools = new TreeSet<>(); public ShowToolSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().show(), Images.EDIT_SHOW.getIcon()); for (String toolTitle : ToolLoader.getToolTitles(program)) { tools.add(new Tool(toolTitle)); } ButtonGroup buttonGroup = new ButtonGroup(); jSave = new JRadioButton(DialoguesSettings.get().saveTools()); jSave.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setEnabled(false); } }); buttonGroup.add(jSave); jSelected = new JRadioButton(DialoguesSettings.get().selectTools()); jSelected.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setEnabled(true); } }); buttonGroup.add(jSelected); GroupLayout.SequentialGroup horizontal = layout.createSequentialGroup(); List columns = new ArrayList<>(); for (int i = 0; i < COLUMN_COUNT; i++) { GroupLayout.ParallelGroup column = layout.createParallelGroup(GroupLayout.Alignment.LEADING); horizontal.addGroup(column); columns.add(column); } int rowCount = (int) Math.ceil(tools.size() / COLUMN_COUNT); GroupLayout.SequentialGroup vertical = layout.createSequentialGroup(); List rows = new ArrayList<>(); for (int i = 0; i < rowCount; i++) { GroupLayout.ParallelGroup row = layout.createParallelGroup(GroupLayout.Alignment.LEADING); vertical.addGroup(row); rows.add(row); } int row = 0; int column = 0; for (Tool tool : tools) { if (row >= rowCount) { row = 0; column++; } JCheckBox jCheckBox = tool.getCheckBox(); jCheckBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (jCheckBox.isSelected()) { if (!model.contains(tool)) { model.addElement(tool); } } else { model.removeElement(tool); } } }); rows.get(row).addComponent(jCheckBox); columns.get(column).addComponent(jCheckBox); row++; } jToolsLabel = new JLabel(DialoguesSettings.get().toolsOrderHelp()); jTools = new JList<>(model); jTools.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); jTools.setTransferHandler(new ListItemTransferHandler()); jTools.setDropMode(DropMode.INSERT); jTools.setDragEnabled(true); JScrollPane jToolsOrderScroll = new JScrollPane(jTools); jToolsOrderScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jSave) .addComponent(jSelected) .addGroup(horizontal) .addComponent(jToolsLabel) .addComponent(jToolsOrderScroll) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jSave, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSelected, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(vertical) .addComponent(jToolsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGap(0) .addComponent(jToolsOrderScroll, 140, 140, Integer.MAX_VALUE) ); } @Override public UpdateType save() { Settings.get().setSaveToolsOnExit(jSave.isSelected()); //must be before: program.getMainWindow().saveShown() (or it won't save) if (jSave.isSelected()) { Settings.get().getShowTools().clear(); for (JMainTab tab : program.getMainWindow().getTabs()) { Settings.get().getShowTools().add(tab.getTitle()); } } else { Settings.get().getShowTools().clear(); for (int i = 0; i < model.size(); i++) { Settings.get().getShowTools().add(model.get(i).getTitle()); } } return UpdateType.NONE; } @Override public void load() { //Reset model.removeAllElements(); for (Tool tool : tools) { tool.setSelected(false); } if (Settings.get().isSaveToolsOnExit()) { jSave.setSelected(true); } else { jSelected.setSelected(true); for (String toolTitle :Settings.get().getShowTools()) { for (Tool tool : tools) { if (tool.getTitle().equals(toolTitle)) { tool.setSelected(true); model.addElement(tool); } } } } setEnabled(!Settings.get().isSaveToolsOnExit()); } private void setEnabled(boolean b) { jTools.setEnabled(b); jToolsLabel.setEnabled(b); for (Tool tool : tools) { tool.setEnabled(b); } } private static class Tool implements Comparable, Serializable { private final String title; private final JCheckBox jCheckBox; public Tool(String title) { this.title = title; this.jCheckBox = new JCheckBox(title); } public String getTitle() { return title; } public void setSelected(boolean b) { jCheckBox.setSelected(b); } public void setEnabled(boolean b) { jCheckBox.setEnabled(b); } public boolean isSelected() { return jCheckBox.isSelected(); } public JCheckBox getCheckBox() { return jCheckBox; } @Override public int compareTo(Tool o) { return title.compareTo(o.title); } @Override public int hashCode() { int hash = 7; hash = 83 * hash + Objects.hashCode(this.title); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Tool other = (Tool) obj; if (!Objects.equals(this.title, other.title)) { return false; } return true; } @Override public String toString() { return title; } } // @camickr already suggested above. // https://docs.oracle.com/javase/tutorial/uiswing/dnd/dropmodedemo.html @SuppressWarnings("serial") public static class ListItemTransferHandler extends TransferHandler { protected final DataFlavor localObjectFlavor; protected int[] indices; protected int addIndex = -1; // Location where items were added protected int addCount; // Number of items added. public ListItemTransferHandler() { super(); // localObjectFlavor = new ActivationDataFlavor( // Object[].class, DataFlavor.javaJVMLocalObjectMimeType, "Array of items"); localObjectFlavor = new DataFlavor(Object[].class, "Array of items"); } @Override protected Transferable createTransferable(JComponent c) { JList source = (JList) c; c.getRootPane().getGlassPane().setVisible(true); indices = source.getSelectedIndices(); Object[] transferedObjects = source.getSelectedValuesList().toArray(new Object[0]); // return new DataHandler(transferedObjects, localObjectFlavor.getMimeType()); return new Transferable() { @Override public DataFlavor[] getTransferDataFlavors() { return new DataFlavor[]{localObjectFlavor}; } @Override public boolean isDataFlavorSupported(DataFlavor flavor) { return Objects.equals(localObjectFlavor, flavor); } @Override public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { if (isDataFlavorSupported(flavor)) { return transferedObjects; } else { throw new UnsupportedFlavorException(flavor); } } }; } @Override public boolean canImport(TransferSupport info) { return info.isDrop() && info.isDataFlavorSupported(localObjectFlavor); } @Override public int getSourceActions(JComponent c) { Component glassPane = c.getRootPane().getGlassPane(); glassPane.setCursor(DragSource.DefaultMoveDrop); return MOVE; // COPY_OR_MOVE; } @SuppressWarnings("unchecked") @Override public boolean importData(TransferSupport info) { TransferHandler.DropLocation tdl = info.getDropLocation(); if (!canImport(info) || !(tdl instanceof JList.DropLocation)) { return false; } JList.DropLocation dl = (JList.DropLocation) tdl; JList target = (JList) info.getComponent(); DefaultListModel listModel = (DefaultListModel) target.getModel(); int max = listModel.getSize(); int index = dl.getIndex(); index = index < 0 ? max : index; // If it is out of range, it is appended to the end index = Math.min(index, max); addIndex = index; try { Object[] values = (Object[]) info.getTransferable().getTransferData(localObjectFlavor); for (Object value : values) { int idx = index++; listModel.add(idx, value); target.addSelectionInterval(idx, idx); } addCount = values.length; return true; } catch (UnsupportedFlavorException | IOException ex) { LOG.error(ex.getMessage(), ex); return false; } } @Override protected void exportDone(JComponent c, Transferable data, int action) { c.getRootPane().getGlassPane().setVisible(false); cleanup(c, action == MOVE); } private void cleanup(JComponent c, boolean remove) { if (remove && Objects.nonNull(indices)) { if (addCount > 0) { // https://github.com/aterai/java-swing-tips/blob/master/DragSelectDropReordering/src/java/example/MainPanel.java for (int i = 0; i < indices.length; i++) { if (indices[i] >= addIndex) { indices[i] += addCount; } } } JList source = (JList) c; DefaultListModel model = (DefaultListModel) source.getModel(); for (int i = indices.length - 1; i >= 0; i--) { model.remove(indices[i]); } } indices = null; addCount = 0; addIndex = -1; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/SoundsSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import javax.swing.DefaultComboBoxModel; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JCustomFileChooser; import net.nikr.eve.jeveasset.gui.sounds.DefaultSound; import net.nikr.eve.jeveasset.gui.sounds.Sound; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; import net.nikr.eve.jeveasset.gui.sounds.SoundPlayer; import net.nikr.eve.jeveasset.io.local.SoundFinder; import net.nikr.eve.jeveasset.io.shared.FileUtil; public class SoundsSettingsPanel extends JSettingsPanel { private enum SoundsSettingsAction { DELETE, ADD } public static enum SoundOption { OUTBID_UPDATE_COMPLETED() { @Override public String getText() { return DialoguesSettings.get().soundsOutbidUpdateCompleted(); } }, OUTBID_UPDATE_AVAILABLE() { @Override public String getText() { return DialoguesSettings.get().soundsOutbidUpdateAvailable(); } }, INDUSTRY_JOB_COMPLETED() { @Override public String getText() { return DialoguesSettings.get().soundsIndustryJobCompleted(); } }; @Override public String toString() { return getText(); } public abstract String getText(); } private static final int COMBOBOX_SIZE = 160; private static final List DEFAULT_SOUNDS = Arrays.asList(DefaultSound.values()); private final JCustomFileChooser jFileChooser; private final JComboBox jUserSounds; private final JButton jDelete; private final JButton jPlay; private final JButton jStop; private final List soundPanels = new ArrayList<>(); private Sound playing = null; public SoundsSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().sounds(), Images.MISC_SOUNDS.getIcon()); ListenerClass listener = new ListenerClass(); jFileChooser = new JCustomFileChooser("mp3"); jFileChooser.setMultiSelectionEnabled(false); jFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); jUserSounds = new JComboBox<>(); JButton jAdd = new JButton(DialoguesSettings.get().soundsMp3Add(), Images.EDIT_ADD.getIcon()); jAdd.setActionCommand(SoundsSettingsAction.ADD.name()); jAdd.addActionListener(listener); jDelete = new JButton(Images.EDIT_DELETE.getIcon()); jDelete.setActionCommand(SoundsSettingsAction.DELETE.name()); jDelete.addActionListener(listener); jPlay = new JButton(Images.MISC_PLAY.getIcon()); jPlay.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { play(); } }); jStop = new JButton(Images.MISC_STOP.getIcon()); jStop.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { stopAll(); } }); for (SoundOption option : SoundOption.values()) { soundPanels.add(new SoundPanel(option)); } GroupLayout.ParallelGroup horizontalLabels = layout.createParallelGroup(GroupLayout.Alignment.LEADING); GroupLayout.ParallelGroup horizontalComboBoxs = layout.createParallelGroup(GroupLayout.Alignment.LEADING); GroupLayout.ParallelGroup horizontalPlays = layout.createParallelGroup(GroupLayout.Alignment.LEADING); GroupLayout.ParallelGroup horizontalStops = layout.createParallelGroup(GroupLayout.Alignment.LEADING); GroupLayout.SequentialGroup verticalGroup = layout.createSequentialGroup(); horizontalLabels.addGroup( layout.createSequentialGroup() .addComponent(jAdd) .addComponent(jDelete, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) ); horizontalComboBoxs.addComponent(jUserSounds, COMBOBOX_SIZE, COMBOBOX_SIZE, COMBOBOX_SIZE); horizontalPlays.addComponent(jPlay, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()); horizontalStops.addComponent(jStop, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()); verticalGroup.addGroup( layout.createParallelGroup() .addComponent(jDelete, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jAdd, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jUserSounds, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jPlay, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jStop, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); for (SoundPanel panel : soundPanels) { horizontalLabels.addComponent(panel.jLabel); horizontalComboBoxs.addComponent(panel.jComboBox, COMBOBOX_SIZE, COMBOBOX_SIZE, COMBOBOX_SIZE); horizontalPlays.addComponent(panel.jPlay, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()); horizontalStops.addComponent(panel.jStop, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()); verticalGroup.addGroup( layout.createParallelGroup() .addComponent(panel.jLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(panel.jComboBox, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(panel.jPlay, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(panel.jStop, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } layout.setHorizontalGroup( layout.createSequentialGroup() .addGroup(horizontalLabels) .addGroup(horizontalComboBoxs) .addGroup(horizontalPlays) .addGroup(horizontalStops) ); layout.setVerticalGroup(verticalGroup); } @Override public UpdateType save() { for (SoundPanel panel : soundPanels) { panel.save(); } stopAll(); return UpdateType.NONE; } @Override public void load() { updateSoundOptions(); for (SoundPanel panel : soundPanels) { panel.load(); } } private void updateSoundOptions() { List userSounds = SoundFinder.load(); List sounds = new ArrayList<>(); sounds.addAll(DEFAULT_SOUNDS); sounds.addAll(userSounds); Sound[] arrSounds = toArray(sounds); for (SoundPanel panel : soundPanels) { panel.updateSoundOptions(arrSounds); } if (userSounds.isEmpty()) { jUserSounds.getModel().setSelectedItem(DialoguesSettings.get().soundsMp3NoFilesAdded()); jUserSounds.setEnabled(false); jDelete.setEnabled(false); jPlay.setEnabled(false); jStop.setEnabled(false); } else { jUserSounds.setModel(new DefaultComboBoxModel<>(toArray(userSounds))); jUserSounds.setEnabled(true); jDelete.setEnabled(true); jPlay.setEnabled(true); jStop.setEnabled(true); } } private void stopAll() { SoundPlayer.stop(playing); for (SoundPanel panel : soundPanels) { panel.stop(); } } private void play() { stopAll(); playing = jUserSounds.getItemAt(jUserSounds.getSelectedIndex()); SoundPlayer.play(playing); } private Sound[] toArray(Collection c) { Sound[] arr = new Sound[c.size()]; c.toArray(arr); return arr; } private class SoundPanel { private final SoundOption option; private final JLabel jLabel; private final JComboBox jComboBox; private final JButton jPlay; private final JButton jStop; private Sound playing = null; public SoundPanel(SoundOption key) { this.option = key; jLabel = new JLabel(key.getText()); jComboBox = new JComboBox<>(); jPlay = new JButton(Images.MISC_PLAY.getIcon()); jPlay.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { play(); } }); jStop = new JButton(Images.MISC_STOP.getIcon()); jStop.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { stopAll(); } }); } public void updateSoundOptions(Sound[] options) { Object selected = jComboBox.getSelectedItem(); jComboBox.setModel(new DefaultComboBoxModel<>(options)); jComboBox.setSelectedItem(selected); } public void save() { Sound sound = jComboBox.getItemAt(jComboBox.getSelectedIndex()); Settings.get().getSoundSettings().put(option, sound); } public void load() { Sound sound = Settings.get().getSoundSettings().get(option); if (sound == null) { jComboBox.setSelectedIndex(0); } else { jComboBox.setSelectedItem(sound); } } private void play() { stopAll(); playing = jComboBox.getItemAt(jComboBox.getSelectedIndex()); SoundPlayer.play(playing); } private void stop() { SoundPlayer.stop(playing); } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(ActionEvent e) { if (SoundsSettingsAction.ADD.name().equals(e.getActionCommand())) { int returnValue = jFileChooser.showOpenDialog(parent); if (returnValue != JCustomFileChooser.APPROVE_OPTION) { return; } File fromFile = jFileChooser.getSelectedFile(); File toFile = new File(FileUtil.getPathSounds(fromFile.getName())); if (toFile.exists()) { JOptionPane.showMessageDialog(parent, DialoguesSettings.get().soundsMp3ImportExist(), DialoguesSettings.get().soundsMp3ImportTitle(), JOptionPane.PLAIN_MESSAGE); return; } Path from = Paths.get(fromFile.getAbsolutePath()); Path to = Paths.get(toFile.getAbsolutePath()); try { Files.copy(from, to); updateSoundOptions(); } catch (IOException ex) { JOptionPane.showMessageDialog(parent, DialoguesSettings.get().soundsMp3ImportCopy(), DialoguesSettings.get().soundsMp3ImportTitle(), JOptionPane.PLAIN_MESSAGE); } } else if (SoundsSettingsAction.DELETE.name().equals(e.getActionCommand())) { Sound sound = jUserSounds.getItemAt(jUserSounds.getSelectedIndex()); int returnValue = JOptionPane.showConfirmDialog(parent, DialoguesSettings.get().soundsMp3DeleteMsg(sound.getID()), DialoguesSettings.get().soundsMp3DeleteTitle(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if (returnValue != JOptionPane.OK_OPTION) { return; //Cancelled } File file = new File(FileUtil.getPathSounds(sound.getID())); file.delete(); updateSoundOptions(); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/StockpileToolSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.JCheckBox; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import javax.swing.JRadioButton; import javax.swing.SwingUtilities; import javax.swing.text.JTextComponent; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class StockpileToolSettingsPanel extends JSettingsPanel { private final JCheckBox jSwitchTab; private final JRadioButton jTwoGroups; private final JRadioButton jThreeGroups; private final JFormattedTextField jGroup2; private final JFormattedTextField jGroup3; private final JLabel jGroup1Label; private final JLabel jGroup2Label; private final JLabel jGroup3Label; public StockpileToolSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().stockpile(), Images.TOOL_STOCKPILE.getIcon()); jSwitchTab = new JCheckBox(DialoguesSettings.get().stockpileSwitchTab()); ButtonGroup group = new ButtonGroup(); jTwoGroups = new JRadioButton(DialoguesSettings.get().stockpileTwoGroups()); jTwoGroups.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { useTwoGroups(); } }); group.add(jTwoGroups); jThreeGroups = new JRadioButton(DialoguesSettings.get().stockpileThreeGroups()); jThreeGroups.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { useThreeGroups(); } }); group.add(jThreeGroups); JLabel jColors = new JLabel(DialoguesSettings.get().stockpileColors()); jGroup1Label = new JLabel(); jGroup1Label.setOpaque(true); jGroup1Label.setHorizontalAlignment(JLabel.CENTER); ColorSettings.config(jGroup1Label, ColorEntry.STOCKPILE_TABLE_BELOW_THRESHOLD); jGroup1Label.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); jGroup2 = new JFormattedTextField(new DecimalFormat("##0", new DecimalFormatSymbols(Locale.ENGLISH)) ); jGroup2.setOpaque(true); jGroup2.setHorizontalAlignment(JLabel.TRAILING); jGroup2.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { validate(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { jGroup2.selectAll(); } }); } @Override public void focusLost(FocusEvent e) { validate(); } }); jGroup2Label = new JLabel(); jGroup2Label.setOpaque(true); jGroup2Label.setHorizontalAlignment(JLabel.LEADING); jGroup2Label.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 1, Color.BLACK)); jGroup2Label.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { jGroup2.requestFocusInWindow(); } }); jGroup3 = new JFormattedTextField(new DecimalFormat("##0", new DecimalFormatSymbols(Locale.ENGLISH)) ); jGroup3.setOpaque(true); jGroup3.setHorizontalAlignment(JLabel.TRAILING); jGroup3.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { validate(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { jGroup3.selectAll(); } }); } @Override public void focusLost(FocusEvent e) { validate(); } }); jGroup3Label = new JLabel(); jGroup3Label.setOpaque(true); jGroup3Label.setHorizontalAlignment(JLabel.LEADING); jGroup3Label.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 1, Color.BLACK)); jGroup3Label.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (jGroup3.isEnabled()) { jGroup3.requestFocusInWindow(); } } }); jTwoGroups.setSelected(true); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jSwitchTab) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jColors) .addComponent(jGroup1Label, 70, 70, Integer.MAX_VALUE) ) .addGroup(layout.createParallelGroup() .addComponent(jTwoGroups) .addGroup(layout.createSequentialGroup() .addComponent(jGroup2, 35, 35, Integer.MAX_VALUE) .addGap(0) .addComponent(jGroup2Label, 35, 35, Integer.MAX_VALUE) ) ) .addGroup(layout.createParallelGroup() .addComponent(jThreeGroups) .addGroup(layout.createSequentialGroup() .addComponent(jGroup3, 35, 35, Integer.MAX_VALUE) .addGap(0) .addComponent(jGroup3Label, 35, 35, Integer.MAX_VALUE) ) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jSwitchTab, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGap(20) .addGroup(layout.createParallelGroup() .addComponent(jColors, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jTwoGroups, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jThreeGroups, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jGroup1Label, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jGroup2, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jGroup2Label, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jGroup3, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jGroup3Label, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } @Override public UpdateType save() { int group2 = getNumber(jGroup2); int group3 = getNumber(jGroup3); boolean repaint = Settings.get().isStockpileHalfColors() != jThreeGroups.isSelected() || group2 != Settings.get().getStockpileColorGroup2() || group3 != Settings.get().getStockpileColorGroup3(); Settings.get().setStockpileColorGroup2(group2); Settings.get().setStockpileFocusTab(jSwitchTab.isSelected()); Settings.get().setStockpileHalfColors(jThreeGroups.isSelected()); Settings.get().setStockpileColorGroup3(group3); return repaint ? UpdateType.REPAINT_STOCKPILE_TABLE : UpdateType.NONE; } @Override public void load() { jSwitchTab.setSelected(Settings.get().isStockpileFocusTab()); int group1 = Settings.get().getStockpileColorGroup2(); int group2 = Settings.get().getStockpileColorGroup3(); if (Settings.get().isStockpileHalfColors()) { jThreeGroups.setSelected(true); if (group1 > 0) { jGroup2.setText(String.valueOf(group1)); } else { jGroup2.setText("50"); } if (group2 > 0) { jGroup3.setText(String.valueOf(group2)); } else { jGroup3.setText("100"); } useThreeGroups(); } else { jTwoGroups.setSelected(true); if (group1 > 0) { jGroup2.setText(String.valueOf(group1)); } else { jGroup2.setText("100"); } useTwoGroups(); } validate(); } private void validate() { int group2 = getNumber(jGroup2); if (group2 <= 0) { group2 = 1; jGroup2.setText("1"); } jGroup1Label.setText("0-" + jGroup2.getText() + DialoguesSettings.get().percentSymbol()); if (jGroup3.isEnabled()) { int group3 = getNumber(jGroup3); if (group2 >= group3) { jGroup3.setText(String.valueOf(group2 + 1)); } jGroup2Label.setText("-" + jGroup3.getText() + DialoguesSettings.get().percentSymbol()); jGroup3Label.setText(DialoguesSettings.get().percentPlusSymbol()); } else { jGroup3Label.setText(""); jGroup2Label.setText(DialoguesSettings.get().percentPlusSymbol()); } } private void useTwoGroups() { ColorSettings.config(jGroup2Label, ColorEntry.STOCKPILE_ICON_OVER_THRESHOLD); jGroup3Label.setBackground(Color.LIGHT_GRAY); jGroup3.setText(""); jGroup3.setEnabled(false); jGroup2.requestFocusInWindow(); } private void useThreeGroups() { ColorSettings.config(jGroup2Label, ColorEntry.STOCKPILE_TABLE_BELOW_THRESHOLD_2ND); ColorSettings.config(jGroup3Label, ColorEntry.STOCKPILE_ICON_OVER_THRESHOLD); jGroup3.setEnabled(true); jGroup2.requestFocusInWindow(); } private int getNumber(JTextComponent jText) { int number; try { number = Integer.valueOf(jText.getText()); } catch (NumberFormatException ex) { number = 0; } return number; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/TagsSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import ca.odell.glazedlists.GlazedLists; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; import javax.swing.DefaultListModel; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.ListCellRenderer; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.tag.Tag; import net.nikr.eve.jeveasset.data.settings.tag.TagID; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.menu.JTagsDialog; import net.nikr.eve.jeveasset.i18n.GuiShared; public class TagsSettingsPanel extends JSettingsPanel { private enum TagsSettingsAction { EDIT, DELETE, ADD } //GUI private final JList jTags; private final JButton jEdit; private final JButton jDelete; private final DefaultListModel listModel; private final JTagsDialog jTagsDialog; //Date private final List tasks = new ArrayList<>(); private final Set currentTags = new HashSet<>(); public TagsSettingsPanel(Program program, SettingsDialog settingsDialog) { super(program, settingsDialog, GuiShared.get().tags(), Images.TAG_GRAY.getIcon()); ListenerClass listener = new ListenerClass(); jTagsDialog = new JTagsDialog(program); listModel = new DefaultListModel<>(); jTags = new JList<>(listModel); jTags.setCellRenderer(new TagListCellRenderer(jTags.getCellRenderer())); jTags.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); jTags.addListSelectionListener(listener); JButton jAdd = new JButton(GuiShared.get().add()); jAdd.setActionCommand(TagsSettingsAction.ADD.name()); jAdd.addActionListener(listener); jEdit = new JButton(GuiShared.get().edit()); jEdit.setActionCommand(TagsSettingsAction.EDIT.name()); jEdit.addActionListener(listener); jDelete = new JButton(GuiShared.get().delete()); jDelete.setActionCommand(TagsSettingsAction.DELETE.name()); jDelete.addActionListener(listener); JScrollPane jTagsScroll = new JScrollPane(jTags); layout.setHorizontalGroup( layout.createSequentialGroup() .addComponent(jTagsScroll, 200, 200, Integer.MAX_VALUE) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jAdd, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jEdit, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jDelete, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jTagsScroll, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addComponent(jAdd, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jEdit, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDelete, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } @Override public UpdateType save() { for (TagTask task : tasks) { task.runTask(); } return tasks.isEmpty() ? UpdateType.NONE : UpdateType.UPDATE_TAGS; } @Override public void load() { tasks.clear(); Set allTags = new TreeSet<>(GlazedLists.comparableComparator()); allTags.addAll(Settings.get().getTags().values()); currentTags.clear(); currentTags.addAll(Settings.get().getTags().keySet()); jTags.clearSelection(); listModel.clear(); for (Tag tag : allTags) { listModel.addElement(tag); } jEdit.setEnabled(false); jDelete.setEnabled(false); } private int addToList(Tag tag) { boolean ok = false; int index = 0; for (int i = index; i < listModel.size(); i++) { Tag listTag = listModel.get(i); int compareTo = listTag.compareTo(tag); if (compareTo >= 0) { listModel.insertElementAt(tag, i); index = i; //Update selected index ok = true; break; } } if (!ok) { //Handle insert if last in list listModel.addElement(tag); index = listModel.size() - 1; //Update selected index } return index; } private class ListenerClass implements ListSelectionListener, ActionListener { @Override public void valueChanged(ListSelectionEvent e) { int index = jTags.getSelectedIndex(); boolean valid = (index >= 0); jEdit.setEnabled(valid); jDelete.setEnabled(valid); } @Override public void actionPerformed(ActionEvent e) { if (TagsSettingsAction.ADD.name().equals(e.getActionCommand())) { Tag tag = jTagsDialog.show(currentTags); if (tag != null && !tag.getName().isEmpty()) { //Save for update (only executed if saved AKA ignored on cancel) tasks.add(new AddTask(tag)); //Update List addToList(tag); //Update current tags currentTags.add(tag.getName()); } } else if (TagsSettingsAction.EDIT.name().equals(e.getActionCommand())) { Tag tag = jTags.getSelectedValue(); Tag editedTag = jTagsDialog.show(tag, currentTags); if (editedTag != null && !editedTag.getName().isEmpty()) { //Update count editedTag.getIDs().addAll(tag.getIDs()); //Update current tags currentTags.remove(tag.getName()); currentTags.add(editedTag.getName()); //Remove from List listModel.removeElement(tag); //Get original tag if (tag instanceof EditTag) { EditTag editTag = (EditTag) tag; tag = editTag.getTag(); } //Save for update (only executed if saved AKA ignored on cancel) tasks.add(new EditTask(tag, editedTag)); //Add to list int index = addToList(new EditTag(tag, editedTag)); //Load selected index jTags.setSelectedIndex(index); } } else if (TagsSettingsAction.DELETE.name().equals(e.getActionCommand())) { Tag tag = jTags.getSelectedValue(); //Save for update (only executed if saved AKA ignored on cancel) tasks.add(new DeleteTask(tag)); //Update List listModel.removeElement(tag); //Update current tags currentTags.remove(tag.getName()); } } } private abstract static class TagTask { public abstract void runTask(); } private static class EditTask extends TagTask { private final Tag tag; private final Tag editedTag; public EditTask(Tag tag, Tag editedTag) { this.tag = tag; this.editedTag = editedTag; } @Override public void runTask() { //Remove old Settings.get().getTags().remove(tag.getName()); //Update tag tag.update(editedTag); //Add updated Settings.get().getTags().put(tag.getName(), tag); //Update tags for (TagID ids : tag.getIDs()) { Tags tags = Settings.get().getTags(ids); tags.updateTags(); } } } private static class AddTask extends TagTask { private final Tag tag; public AddTask(Tag tag) { this.tag = tag; } @Override public void runTask() { Settings.get().getTags().put(tag.getName(), tag); } } private static class DeleteTask extends TagTask { private final Tag tag; public DeleteTask(Tag tag) { this.tag = tag; } @Override public void runTask() { for (TagID tagID : tag.getIDs()) { //Remove from all items Tags tags = Settings.get().getTags(tagID); tags.remove(tag); } //Remove from settings Settings.get().getTags().remove(tag.getName()); } } private static class EditTag extends Tag { private final Tag tag; public EditTag(Tag tag, Tag editedTag) { super(editedTag.getName(), editedTag.getColor()); this.tag = tag; this.getIDs().addAll(editedTag.getIDs()); } public Tag getTag() { return tag; } } private static class TagListCellRenderer implements ListCellRenderer { private final ListCellRenderer renderer; public TagListCellRenderer(ListCellRenderer renderer) { this.renderer = renderer; } @Override public Component getListCellRendererComponent(JList list, Tag value, int index, boolean isSelected, boolean cellHasFocus) { JLabel jLabel = (JLabel) renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); jLabel.setText(GuiShared.get().tagsName(value.getName(), value.getIDs().size())); jLabel.setIcon(new JTagsDialog.TagIcon(value.getColor())); return jLabel; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/TrackerToolSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import javax.swing.GroupLayout; import javax.swing.JCheckBox; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class TrackerToolSettingsPanel extends JSettingsPanel { private final JCheckBox jUseAssetPriceForSellOrders; public TrackerToolSettingsPanel(Program program, SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().tracker(), Images.TOOL_TRACKER.getIcon()); jUseAssetPriceForSellOrders = new JCheckBox(DialoguesSettings.get().useAssetPriceForSellOrders()); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jUseAssetPriceForSellOrders) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jUseAssetPriceForSellOrders, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } @Override public UpdateType save() { Settings.get().setTrackerUseAssetPriceForSellOrders(jUseAssetPriceForSellOrders.isSelected()); return UpdateType.NONE; } @Override public void load() { jUseAssetPriceForSellOrders.setSelected(Settings.get().isTrackerUseAssetPriceForSellOrders()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/TransactionsToolSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import javax.swing.GroupLayout; import javax.swing.JCheckBox; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JLabelMultiline; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class TransactionsToolSettingsPanel extends JSettingsPanel { private final JCheckBox jSaveHistory; public TransactionsToolSettingsPanel(final Program program, final SettingsDialog settingsDialog) { super(program, settingsDialog, DialoguesSettings.get().transactions(), Images.TOOL_TRANSACTION.getIcon()); jSaveHistory = new JCheckBox(DialoguesSettings.get().transactionsSaveHistory()); JLabelMultiline jSaveHistoryWarning = new JLabelMultiline(DialoguesSettings.get().saveHistoryWarning(), 2); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jSaveHistory) .addComponent(jSaveHistoryWarning, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jSaveHistory, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSaveHistoryWarning, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ); } @Override public UpdateType save() { Settings.get().setTransactionHistory(jSaveHistory.isSelected()); return UpdateType.NONE; } @Override public void load() { jSaveHistory.setSelected(Settings.get().isTransactionHistory()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/UserLocationSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.Citadel; import net.nikr.eve.jeveasset.data.settings.Citadel.CitadelSource; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.JOptionInput; import net.nikr.eve.jeveasset.gui.shared.components.JAutoCompleteDialog; import net.nikr.eve.jeveasset.gui.shared.components.JLabelMultiline; import net.nikr.eve.jeveasset.gui.shared.components.ListComboBoxModel; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.io.online.CitadelGetter; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class UserLocationSettingsPanel extends JSettingsPanel { private enum UserListAction { DELETE, EDIT } private final JComboBox jItems; private final JButton jEdit; private final JButton jDelete; private final JAutoCompleteDialog jSystemDialog; private final Set delete = new HashSet<>(); private final List edit = new ArrayList<>(); private final Map citadels = new HashMap<>(); public UserLocationSettingsPanel(Program program, SettingsDialog settingsDialog) { super(program, settingsDialog, GuiShared.get().location(), Images.LOC_LOCATIONS.getIcon()); ListenerClass listener = new ListenerClass(); jSystemDialog = new JAutoCompleteDialog<>(program, GuiShared.get().locationRename(), settingsDialog.getDialog(), Images.LOC_LOCATIONS.getImage(), GuiShared.get().locationSystem(), true, JAutoCompleteDialog.LOCATION_OPTIONS); jItems = new JComboBox<>(); jEdit = new JButton(DialoguesSettings.get().editItem()); jEdit.setActionCommand(UserListAction.EDIT.name()); jEdit.addActionListener(listener); jDelete = new JButton(DialoguesSettings.get().deleteItem()); jDelete.setActionCommand(UserListAction.DELETE.name()); jDelete.addActionListener(listener); JLabelMultiline jHelp = new JLabelMultiline(DialoguesSettings.get().locationsInstructions()); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jItems) .addGroup(layout.createSequentialGroup() .addComponent(jEdit, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jDelete, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) .addComponent(jHelp, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jItems, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup() .addComponent(jEdit, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDelete, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jHelp, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ); } @Override public UpdateType save() { CitadelGetter.remove(delete); CitadelGetter.set(edit); return delete.isEmpty() && edit.isEmpty() ? UpdateType.NONE : UpdateType.FULL_UPDATE; } @Override public void load() { delete.clear(); edit.clear(); citadels.clear(); for (Map.Entry entry : CitadelGetter.getAll()) { if (entry.getValue().isUserLocation()) { citadels.put(entry.getKey(), entry.getValue().toLocation()); } } if (citadels.isEmpty()) { setEnabledAll(false); jItems.setModel(new ListComboBoxModel<>()); jItems.getModel().setSelectedItem(DialoguesSettings.get().itemEmpty()); } else { setEnabledAll(true); jItems.setModel(new ListComboBoxModel<>(new ArrayList<>(new TreeSet<>(citadels.values())))); } } private void updateGUI() { if (citadels.isEmpty()) { setEnabledAll(false); jItems.setModel(new ListComboBoxModel<>()); jItems.getModel().setSelectedItem(DialoguesSettings.get().itemEmpty()); } else { setEnabledAll(true); Object selectedItem = jItems.getSelectedItem(); jItems.setModel(new ListComboBoxModel<>(new ArrayList<>(new TreeSet<>(citadels.values())))); jItems.setSelectedItem(selectedItem); } } private MyLocation getSelectedItem() { Object object = jItems.getSelectedItem(); if (object != null && object instanceof MyLocation) { return (MyLocation)object; } return null; } private void setEnabledAll(final boolean b) { jItems.setEnabled(b); jEdit.setEnabled(b); jDelete.setEnabled(b); } public Long deleteLocation(MyLocation location) { if (location == null) { //Cancel return null; } int value2 = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), GuiShared.get().locationClearConfirm(location.getLocation()), GuiShared.get().locationClear(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if (value2 != JOptionPane.OK_OPTION) { return null; } return location.getLocationID(); } public Citadel editLocation(MyLocation renameLocation) { if (renameLocation == null) { //Cancel return null; } String locationName; if (renameLocation.isUserLocation()) { //Input previous value locationName = getLocationName(CitadelGetter.get(renameLocation.getLocationID()).getLocation()); } else { locationName = getLocationName(""); } if (locationName == null) { //Cancel return null; } //Create data for the system dialog List locations = new ArrayList<>(); for (MyLocation system : StaticData.get().getLocations()) { if (system.isSystem()) { locations.add(system); } } jSystemDialog.updateData(locations); MyLocation system; if (renameLocation.isUserLocation()) { //Input previous value MyLocation renameSystem = ApiIdConverter.getLocation(renameLocation.getSystemID()); system = jSystemDialog.show(renameSystem); } else { system = jSystemDialog.show(); } if (system == null) { //Cancel return null; } return new Citadel(renameLocation.getLocationID(), locationName, system.getSystemID(), true, true, CitadelSource.USER); } private String getLocationName(String text) { text = (String) JOptionInput.showInputDialog(program.getMainWindow().getFrame(), GuiShared.get().locationName(), GuiShared.get().locationRename(), JOptionPane.PLAIN_MESSAGE, null, null, text); if (text == null) { return null; } if (text.isEmpty()) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), GuiShared.get().locationEmpty(), GuiShared.get().locationRename(), JOptionPane.WARNING_MESSAGE); return getLocationName(text); } return text; } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (UserListAction.DELETE.name().equals(e.getActionCommand())) { MyLocation location = getSelectedItem(); if (location != null) { Long locationID = deleteLocation(location); if (locationID != null) { delete.add(locationID); citadels.remove(locationID); updateGUI(); } } } if (UserListAction.EDIT.name().equals(e.getActionCommand())) { MyLocation location = getSelectedItem(); if (location != null) { Citadel citadel = editLocation(location); if (citadel != null) { edit.add(citadel); citadels.put(citadel.getLocationID(), citadel.toLocation()); updateGUI(); } } } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/UserNameSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.util.HashSet; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class UserNameSettingsPanel extends JUserListPanel { public UserNameSettingsPanel(final Program program, final SettingsDialog optionsDialog) { super(program, optionsDialog, Images.SETTINGS_USER_NAME.getIcon(), DialoguesSettings.get().names(), DialoguesSettings.get().name(), DialoguesSettings.get().namesInstruction() ); } @Override protected void updateEventList(List keys) { program.updateNames(new HashSet<>(keys)); } @Override protected String valueOf(final String value) { return value; } @Override protected Map> getItems() { return Settings.get().getUserItemNames(); } @Override protected void setItems(final Map> items) { Settings.get().setUserItemNames(items); } @Override protected UserItem newUserItem(final UserItem userItem) { return new UserName(userItem); } public static class UserName extends UserItem { public UserName(final UserItem userItem) { super(userItem); } public UserName(final MyAsset asset) { super(asset.getName(), asset.getItemID(), asset.getItem().getTypeName()); } public UserName(final String value, final Long key, final String name) { super(value, key, name); } @Override public String toString() { return getValue(); } @Override public String getValueFormatted() { return getValue(); } @Override public int compare(final UserItem o1, final UserItem o2) { return o1.getValue().compareToIgnoreCase(o2.getValue()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/UserPriceSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class UserPriceSettingsPanel extends JUserListPanel { public UserPriceSettingsPanel(final Program program, final SettingsDialog optionsDialog) { super(program, optionsDialog, Images.SETTINGS_USER_PRICE.getIcon(), DialoguesSettings.get().pricePrices(), DialoguesSettings.get().pricePrice(), DialoguesSettings.get().priceInstructions() ); } @Override protected void updateEventList(List keys) { program.updatePrices(new HashSet<>(keys)); } @Override protected Map> getItems() { return Settings.get().getUserPrices(); } @Override protected void setItems(final Map> items) { Settings.get().setUserPrices(items); } @Override protected Double valueOf(final String value) { try { return Double.valueOf(value); } catch (NumberFormatException ex) { return null; } } @Override protected UserItem newUserItem(final UserItem userItem) { return new UserPrice(userItem); } public static class UserPrice extends UserItem { private final DecimalFormat simpleFormat = new DecimalFormat("0.##", new DecimalFormatSymbols(Locale.ENGLISH)); public UserPrice(final UserItem userItem) { super(userItem); } public UserPrice(final Double value, final Integer key, final String name) { super(value, key, name); } @Override public String toString() { return getName(); } @Override public String getValueFormatted() { return simpleFormat.format(getValue()); } @Override public int compare(final UserItem o1, final UserItem o2) { return o1.getName().compareToIgnoreCase(o2.getName()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/settings/WindowSettingsPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.settings; import java.awt.Dimension; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.DocumentFactory; import net.nikr.eve.jeveasset.gui.shared.components.JIntegerField; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public class WindowSettingsPanel extends JSettingsPanel { private enum WindowSettingsAction { AUTO_SAVE, FIXED, DEFAULT } public static final int SAVE_ON_EXIT = 1; public static final int FLAG_SAVE_MAXIMIZED = 2; public static final int FLAG_SAVE_FIXED = 3; private final JRadioButton jAutoSave; private final JRadioButton jFixed; private final JTextField jWidth; private final JTextField jHeight; private final JTextField jX; private final JTextField jY; private final JCheckBox jMaximized; private final JCheckBox jAlwaysOnTop; private final JButton jDefault; public WindowSettingsPanel(final Program program, final SettingsDialog optionsDialog) { super(program, optionsDialog, DialoguesSettings.get().windowWindow(), Images.SETTINGS_WINDOW.getIcon()); ListenerClass listener = new ListenerClass(); jAutoSave = new JRadioButton(DialoguesSettings.get().windowSaveOnExit()); jAutoSave.setActionCommand(WindowSettingsAction.AUTO_SAVE.name()); jAutoSave.addActionListener(listener); jFixed = new JRadioButton(DialoguesSettings.get().windowFixed()); jFixed.setActionCommand(WindowSettingsAction.FIXED.name()); jFixed.addActionListener(listener); JLabel jWidthLabel = new JLabel(DialoguesSettings.get().windowWidth()); jWidth = new JIntegerField(DocumentFactory.ValueFlag.POSITIVE_AND_ZERO); JLabel jHeightLabel = new JLabel(DialoguesSettings.get().windowHeight()); jHeight = new JIntegerField(DocumentFactory.ValueFlag.POSITIVE_AND_ZERO); JLabel jXLabel = new JLabel(DialoguesSettings.get().windowX()); jX = new JIntegerField(DocumentFactory.ValueFlag.POSITIVE_AND_ZERO); JLabel jYLabel = new JLabel(DialoguesSettings.get().windowY()); jY = new JIntegerField(DocumentFactory.ValueFlag.POSITIVE_AND_ZERO); jMaximized = new JCheckBox(DialoguesSettings.get().windowMaximised()); jAlwaysOnTop = new JCheckBox(DialoguesSettings.get().windowAlwaysOnTop()); ButtonGroup group = new ButtonGroup(); group.add(jAutoSave); group.add(jFixed); jDefault = new JButton("Default"); jDefault.setActionCommand(WindowSettingsAction.DEFAULT.name()); jDefault.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jAlwaysOnTop) .addComponent(jAutoSave) .addComponent(jFixed) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jWidthLabel) .addComponent(jXLabel) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jWidth) .addComponent(jX) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jHeightLabel) .addComponent(jYLabel) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jHeight) .addComponent(jY) .addComponent(jDefault) ) ) .addComponent(jMaximized) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jAlwaysOnTop, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jAutoSave, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFixed, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jWidthLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jWidth, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jHeightLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jHeight, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jXLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jX, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jYLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jY, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jMaximized, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDefault, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } private void setValuesFromSettings() { jWidth.setText(String.valueOf(program.getMainWindow().getFrame().getSize().width)); jHeight.setText(String.valueOf(program.getMainWindow().getFrame().getSize().height)); jX.setText(String.valueOf(fixValue(program.getMainWindow().getFrame().getLocation().x))); jY.setText(String.valueOf(fixValue(program.getMainWindow().getFrame().getLocation().y))); jMaximized.setSelected(program.getMainWindow().getFrame().getState() == JFrame.MAXIMIZED_BOTH); } private int fixValue(int i) { if (i < 0) { return 0; } else { return i; } } private void setValuesFromWindow() { jWidth.setText(String.valueOf(Settings.get().getWindowSize().width)); jHeight.setText(String.valueOf(Settings.get().getWindowSize().height)); jX.setText(String.valueOf(Settings.get().getWindowLocation().x)); jY.setText(String.valueOf(Settings.get().getWindowLocation().y)); jMaximized.setSelected(Settings.get().isWindowMaximized()); } private int validate(final String s) { int n; try { n = Integer.valueOf(s); } catch (NumberFormatException ex) { n = 0; } if (n < 0) { n = 0; } return n; } private void setInputEnabled(final boolean b) { jWidth.setEnabled(b); jHeight.setEnabled(b); jX.setEnabled(b); jY.setEnabled(b); jMaximized.setEnabled(b); jDefault.setEnabled(b); } @Override public UpdateType save() { if (jAutoSave.isSelected()) { Settings.get().setWindowAutoSave(true); } else { int width = validate(jWidth.getText()); int height = validate(jHeight.getText()); int x = validate(jX.getText()); int y = validate(jY.getText()); boolean maximized = jMaximized.isSelected(); Dimension d = new Dimension(width, height); Point p = new Point(x, y); boolean first = Settings.get().isWindowAutoSave(); Settings.get().setWindowAutoSave(false); //if changed... if ((Settings.get().getWindowSize().height != d.height) || (Settings.get().getWindowSize().width != d.width) || (Settings.get().getWindowLocation().x != p.x) || (Settings.get().getWindowLocation().y != p.y) || (Settings.get().isWindowMaximized() != maximized) || first) { Settings.get().setWindowSize(d); Settings.get().setWindowLocation(p); Settings.get().setWindowMaximized(maximized); program.getMainWindow().setSizeAndLocation(d, p, maximized); } } boolean alwaysOnTop = jAlwaysOnTop.isSelected(); Settings.get().setWindowAlwaysOnTop(alwaysOnTop); program.getMainWindow().getFrame().setAlwaysOnTop(alwaysOnTop); return UpdateType.NONE; } @Override public void load() { if (Settings.get().isWindowAutoSave()) { jAutoSave.setSelected(true); setValuesFromSettings(); setInputEnabled(false); } else { jFixed.setSelected(true); setValuesFromWindow(); setInputEnabled(true); } jAlwaysOnTop.setSelected(Settings.get().isWindowAlwaysOnTop()); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (WindowSettingsAction.AUTO_SAVE.name().equals(e.getActionCommand())) { setInputEnabled(false); } if (WindowSettingsAction.FIXED.name().equals(e.getActionCommand())) { setInputEnabled(true); } if (WindowSettingsAction.DEFAULT.name().equals(e.getActionCommand())) { jWidth.setText("800"); jHeight.setText("600"); jX.setText("0"); jY.setText("0"); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/update/StructureUpdateDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.update; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Set; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JRadioButton; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.UpdateType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.Updatable; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.shared.components.ListComboBoxModel; import net.nikr.eve.jeveasset.gui.tabs.values.AssetValue; import net.nikr.eve.jeveasset.i18n.DialoguesStructure; import net.nikr.eve.jeveasset.i18n.DialoguesUpdate; import net.nikr.eve.jeveasset.io.esi.EsiStructuresGetter; public class StructureUpdateDialog extends JDialogCentered { private final JRadioButton jOwnersAll; private final JRadioButton jOwnersSingle; private final JRadioButton jLocationsAll; private final JRadioButton jLocationsOwned; private final JRadioButton jLocationsSelected; private final JCheckBox jTrackerLocations; private final JLabel jTime; private final JComboBox jOwners; private final JButton jOk; private final JButton jCancel; private final List owners = new ArrayList<>();; private Set locations; private boolean minimizable; public StructureUpdateDialog(Program program) { super(program, DialoguesStructure.get().title(), Images.DIALOG_UPDATE.getImage()); ButtonGroup ownersGroup = new ButtonGroup(); jOwnersAll = new JRadioButton(DialoguesStructure.get().ownersAll()); jOwnersAll.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jOwners.setEnabled(false); updateETA(); } }); ownersGroup.add(jOwnersAll); jOwnersSingle = new JRadioButton(DialoguesStructure.get().ownersSingle()); jOwnersSingle.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jOwners.setEnabled(true); updateETA(); } }); ownersGroup.add(jOwnersSingle); jOwners = new JComboBox<>(); jOwners.setEnabled(false); ButtonGroup LocationsGroup = new ButtonGroup(); jLocationsAll = new JRadioButton(DialoguesStructure.get().locationsAll()); jLocationsAll.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateETA(); } }); LocationsGroup.add(jLocationsAll); jLocationsOwned = new JRadioButton(DialoguesStructure.get().locationsItem()); jLocationsOwned.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateETA(); } }); LocationsGroup.add(jLocationsOwned); jLocationsSelected = new JRadioButton(DialoguesStructure.get().locationsSelected()); jLocationsSelected.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateETA(); } }); LocationsGroup.add(jLocationsSelected); jTrackerLocations = new JCheckBox(DialoguesStructure.get().locationsTracker()); jTrackerLocations.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateETA(); } }); jOk = new JButton(DialoguesUpdate.get().ok()); jOk.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { save(); } }); jCancel = new JButton(DialoguesUpdate.get().cancel()); jCancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setVisible(false); } }); jTime = new JLabel(); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jOwnersAll) .addComponent(jOwnersSingle) .addGroup(layout.createSequentialGroup() .addGap(20) .addComponent(jOwners) ) ) .addGap(20) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jLocationsAll) .addComponent(jLocationsOwned) .addComponent(jLocationsSelected) .addComponent(jTrackerLocations) ) ) .addGroup(layout.createSequentialGroup() .addComponent(jTime) .addGap(0, 0, Integer.MAX_VALUE) ) .addGroup(layout.createSequentialGroup() .addComponent(jOk, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addComponent(jOwnersAll, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOwnersSingle, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOwners, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createSequentialGroup() .addComponent(jLocationsAll, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jLocationsOwned, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jLocationsSelected, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jTrackerLocations, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ) .addComponent(jTime, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup() .addComponent(jOk, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } @Override protected JComponent getDefaultFocus() { return jOk; } @Override protected JButton getDefaultButton() { return jOk; } @Override protected void windowShown() {} @Override protected void save() { List esiOwners; if (jOwnersAll.isSelected()) { esiOwners = owners; } else { EsiOwner owner = (EsiOwner) jOwners.getSelectedItem(); esiOwners = Collections.singletonList(owner); } List ownerTypes; if (jLocationsAll.isSelected()) { ownerTypes = program.getOwnerTypes(); } else { ownerTypes = null; } setVisible(false); TaskDialog taskDialog = new TaskDialog(program, new StructureUpdateTask(esiOwners, ownerTypes, locations, jTrackerLocations.isSelected()), esiOwners.size() > 1, false, false, minimizable ? UpdateType.STRUCTURE : null, new TaskDialog.TasksCompleted() { @Override public void tasksCompleted(TaskDialog taskDialog) { //Update tracker locations AssetValue.updateData(); //Change and save tracker data //Update eventlists program.updateEventLists(); } }); } public void show(Set locations, boolean minimizable) { this.locations = locations; this.minimizable = minimizable; setVisible(true); } @Override public void setVisible(boolean b) { if (b) { owners.clear(); Date structuresNextUpdate = null; for (EsiOwner esiOwner : program.getProfileManager().getEsiOwners()) { if (!esiOwner.isShowOwner() || !esiOwner.isStructures() || esiOwner.isInvalid()) { continue; } if (esiOwner.getStructuresNextUpdate() != null && (structuresNextUpdate == null || esiOwner.getStructuresNextUpdate().after(structuresNextUpdate))) { structuresNextUpdate = esiOwner.getStructuresNextUpdate(); } owners.add(esiOwner); } if (structuresNextUpdate == null) { //No ESI owners with structure scope JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), DialoguesStructure.get().invalid(), DialoguesStructure.get().title(), JOptionPane.PLAIN_MESSAGE); return; //Do not show } if (!Updatable.isUpdatable(structuresNextUpdate)) { //Update not allowed yet... long time = structuresNextUpdate.getTime() - Settings.getNow().getTime(); String updatableIn; if (time <= 1000) { //less than 1 second updatableIn = "seconds"; } else if (time < (60 * 1000)) { //less than 1 minute updatableIn = Formatter.milliseconds(time, false, true, false, true); } else { updatableIn = Formatter.milliseconds(time, false, true, true, true, true, false); } JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), DialoguesStructure.get().nextUpdate(updatableIn), DialoguesStructure.get().title(), JOptionPane.PLAIN_MESSAGE); return; //Do not show } jOwners.setModel(new ListComboBoxModel<>(owners)); jOwnersAll.setSelected(true); if (locations != null) { jLocationsSelected.setEnabled(true); jLocationsAll.setEnabled(false); jLocationsOwned.setEnabled(false); jTrackerLocations.setEnabled(false); jTrackerLocations.setSelected(false); jLocationsSelected.setSelected(true); } else { jLocationsSelected.setEnabled(false); jLocationsAll.setEnabled(true); jLocationsOwned.setEnabled(true); jLocationsAll.setSelected(true); jTrackerLocations.setEnabled(true); jTrackerLocations.setSelected(true); } updateETA(); } super.setVisible(b); } private void updateETA() { List esiOwners; if (jOwnersAll.isSelected()) { esiOwners = owners; } else { EsiOwner owner = (EsiOwner) jOwners.getSelectedItem(); esiOwners = Collections.singletonList(owner); } List ownerTypes; if (jLocationsAll.isSelected()) { ownerTypes = program.getOwnerTypes(); } else { ownerTypes = null; } jTime.setText(DialoguesStructure.get().eta(EsiStructuresGetter.estimate(esiOwners, ownerTypes, locations, jTrackerLocations.isSelected()))); } public static boolean structuresUpdatable(Program program) { boolean updatable = true; boolean structures = false; for (EsiOwner esiOwner : program.getProfileManager().getEsiOwners()) { if (!esiOwner.isShowOwner() || !esiOwner.isStructures() || esiOwner.isInvalid()) { continue; } structures = true; if (esiOwner.getStructuresNextUpdate() != null && !Updatable.isUpdatable(esiOwner.getStructuresNextUpdate())) { updatable = false; break; } } return updatable && structures; } private static class StructureUpdateTask extends UpdateTask { private final List owners; private final List ownerTypes; private final Set locations; private final boolean tracker; public StructureUpdateTask(List owners, List ownerTypes, Set locations, boolean tracker) { super(DialoguesUpdate.get().structures()); this.owners = new ArrayList<>(owners); //Copy, since we do this in the background it may be changed this.ownerTypes = ownerTypes; this.locations = locations; this.tracker = tracker; } @Override public void update() { setIcon(Images.MISC_ESI.getIcon()); if (locations != null) { EsiStructuresGetter.createIDsFromLocations(locations); } else if (ownerTypes != null) { EsiStructuresGetter.createIDsFromOwners(ownerTypes, tracker); } else { EsiStructuresGetter.createIDsFromOwner(); } int progress = 0; for (EsiOwner owner : owners) { if (isCancelled()) { return; } EsiStructuresGetter esiStructuresGetter = new EsiStructuresGetter(this, owner, tracker); esiStructuresGetter.run(); progress++; setTotalProgress(owners.size(), progress, 0, 100); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/update/TaskDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.update; import java.awt.Font; import java.awt.Window; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Collections; import java.util.List; import javax.swing.GroupLayout; import javax.swing.GroupLayout.ParallelGroup; import javax.swing.GroupLayout.SequentialGroup; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.JTextPane; import javax.swing.SwingUtilities; import javax.swing.WindowConstants; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Colors; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.Progress; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.UpdateType; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow.LockWorkerAdaptor; import net.nikr.eve.jeveasset.i18n.DialoguesUpdate; import net.nikr.eve.jeveasset.i18n.GuiShared; public class TaskDialog { private enum TaskAction { OK, CANCEL, MINIMIZE } private static final int WIDTH_LOG = 280; //GUI private final JDialog jWindow; private final JLabel jIcon; private final JProgressBar jProgressBar; private final JProgressBar jTotalProgressBar; private final JButton jOK; private final JButton jCancel; private final JButton jMinimize; private final JTextPane jErrorMessage; private final JLabel jErrorName; private final JScrollPane jErrorScroll; private final JLockWindow jLockWindow; private final ListenerClass listener; private final Program program; //Data private List updateTasks; private int index; private UpdateTask updateTask; private Progress progress; private final TasksCompleted completed; private final boolean auto; public TaskDialog(final Program program, final UpdateTask updateTask, boolean totalProgress, boolean minimized, boolean auto, UpdateType updateType, TasksCompleted completed) { this(program, Collections.singletonList(updateTask), totalProgress, minimized, auto, updateType, completed); } public TaskDialog(final Program program, final List updateTasks, boolean totalProgress, boolean minimized, boolean auto, UpdateType updateType, TasksCompleted completed) { this.program = program; this.updateTasks = updateTasks; this.completed = completed; this.auto = auto; listener = new ListenerClass(); jWindow = new JDialog(program.getMainWindow().getFrame(), JDialog.DEFAULT_MODALITY_TYPE); jWindow.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); jWindow.setResizable(false); jWindow.addWindowListener(listener); jLockWindow = new JLockWindow(jWindow); JPanel jPanel = new JPanel(); GroupLayout layout = new GroupLayout(jPanel); jPanel.setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(true); jWindow.add(jPanel); JLabel jUpdate = new JLabel(DialoguesUpdate.get().updating()); jUpdate.setFont(new Font(jUpdate.getFont().getName(), Font.BOLD, 15)); jMinimize = new JButton(DialoguesUpdate.get().minimize()); jMinimize.setActionCommand(TaskAction.MINIMIZE.name()); jMinimize.addActionListener(listener); jMinimize.setVisible(updateType != null); if (updateType != null) { progress = program.getStatusPanel().addProgress(updateType, new StatusPanel.ProgressControl() { @Override public void show() { if (auto) { return; //Ignore on auto } progress.setVisible(false); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { jWindow.setVisible(true); //Blocking - do later } }); if (progress.isDone()) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { done(); //Needs to be done after showing the dialog (add to EDT queue) } }); } } @Override public void cancel() { cancelUpdate(); } @Override public void setPause(boolean pause) { updateTask.setPause(pause); } @Override public boolean isAuto() { return auto; } }); } jIcon = new JLabel(new UpdateTask.EmptyIcon()); jProgressBar = new JProgressBar(0, 100); jTotalProgressBar = new JProgressBar(0, 100); jTotalProgressBar.setIndeterminate(true); jOK = new JButton(DialoguesUpdate.get().ok()); jOK.setActionCommand(TaskAction.OK.name()); jOK.addActionListener(listener); jCancel = new JButton(DialoguesUpdate.get().cancel()); jCancel.setActionCommand(TaskAction.CANCEL.name()); jCancel.addActionListener(listener); jErrorName = new JLabel(""); jErrorName.setFont(new Font(jErrorName.getFont().getName(), Font.BOLD, 15)); jErrorName.setVisible(false); jErrorMessage = new JTextPane(); jErrorMessage.setText(""); jErrorMessage.setEditable(false); jErrorMessage.setFocusable(true); jErrorMessage.setOpaque(false); jErrorMessage.setBackground(Colors.COMPONENT_TRANSPARENT.getColor()); jErrorScroll = new JScrollPane(jErrorMessage); jErrorScroll.setVisible(false); ParallelGroup horizontalGroup = layout.createParallelGroup(GroupLayout.Alignment.CENTER); horizontalGroup.addGroup(layout.createSequentialGroup() .addComponent(jUpdate) .addGap(0, 0, Integer.MAX_VALUE) .addComponent(jMinimize) ); int taskWidth = 230; for (UpdateTask updateTaskLoop : updateTasks) { horizontalGroup.addGroup(layout.createSequentialGroup() .addComponent(updateTaskLoop.getTextLabel(), 100, 100, Integer.MAX_VALUE) .addComponent(updateTaskLoop.getShowButton(), 20, 20, 20) .addGap(5) ); updateTaskLoop.addErrorListener(new ErrorListener(updateTaskLoop)); taskWidth = Math.max(taskWidth, updateTaskLoop.getWidth() + 25); } horizontalGroup.addGroup(layout.createSequentialGroup() .addComponent(jIcon, 16, 16, 16) .addGap(5) .addComponent(jProgressBar, taskWidth, taskWidth, taskWidth) ); if (totalProgress) { horizontalGroup.addComponent(jTotalProgressBar); } horizontalGroup.addGroup(layout.createSequentialGroup() .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ); layout.setHorizontalGroup( layout.createSequentialGroup() .addGroup(horizontalGroup) .addGap(5) .addGroup(layout.createParallelGroup() .addComponent(jErrorName) .addComponent(jErrorScroll, WIDTH_LOG, WIDTH_LOG, WIDTH_LOG) ) ); SequentialGroup verticalGroup = layout.createSequentialGroup(); verticalGroup.addGroup(layout.createParallelGroup() .addComponent(jUpdate, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jMinimize, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); for (UpdateTask updateTaskLoop : updateTasks) { verticalGroup.addGroup(layout.createParallelGroup() .addComponent(updateTaskLoop.getTextLabel(), Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(updateTaskLoop.getShowButton(), Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } verticalGroup.addGroup( layout.createParallelGroup() .addComponent(jIcon, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jProgressBar, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); if (totalProgress) { verticalGroup.addComponent(jTotalProgressBar, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()); } verticalGroup.addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); layout.setVerticalGroup( layout.createParallelGroup() .addGroup(verticalGroup) .addGroup(layout.createSequentialGroup() .addComponent(jErrorName) .addComponent(jErrorScroll) ) ); if (!updateTasks.isEmpty()) { index = 0; update(); setVisible(true, minimized); } } public JDialog getDialog() { return jWindow; } private void update() { if (index < updateTasks.size()) { jOK.setEnabled(false); if (updateTask != null) { //Remove PropertyChangeListener from last updateTask updateTask.removePropertyChangeListener(listener); } updateTask = updateTasks.get(index); updateTask.addPropertyChangeListener(listener); updateTask.execute(); } else { //Done jIcon.setIcon(new UpdateTask.EmptyIcon()); jCancel.setEnabled(false); if (!auto && progress != null && progress.isVisible()) { progress.setDone(true); } else { done(); } } } private void done() { if (!auto || jWindow.isVisible()) { jLockWindow.show(GuiShared.get().updating(), new LockWorkerAdaptor() { @Override public void task() { completed.tasksCompleted(TaskDialog.this); } @Override public void gui() { jOK.setEnabled(true); jMinimize.setEnabled(false); //Should not minimize after completed } @Override public void hidden() { if (completed instanceof TasksCompletedAdvanced) { ((TasksCompletedAdvanced) completed).tasksHidden(TaskDialog.this); } } }); } else { JLockWindow jLockMainFrame = new JLockWindow(getTopWindow(program.getMainWindow().getFrame())); jLockMainFrame.show(GuiShared.get().updating(), new LockWorkerAdaptor() { @Override public void task() { completed.tasksCompleted(TaskDialog.this); } @Override public void gui() { setVisible(false); } @Override public void hidden() { if (completed instanceof TasksCompletedAdvanced) { ((TasksCompletedAdvanced) completed).tasksHidden(TaskDialog.this); } } }); } } private Window getTopWindow(Window in) { for (Window window : in.getOwnedWindows()) { if (window.isVisible()) { return getTopWindow(window); } } return in; } private void centerWindow() { jWindow.pack(); jWindow.setLocationRelativeTo(jWindow.getParent()); } private void setVisible(final boolean b) { setVisible(b, false); } private void setVisible(final boolean b, boolean minimized) { if (b) { centerWindow(); if (minimized) { if (progress != null) { progress.setVisible(true); } jWindow.setVisible(false); } else { if (progress != null) { progress.setVisible(false); } jWindow.setVisible(true); } } else { //Memory for (UpdateTask task : updateTasks) { for (MouseListener mouseListener : task.getTextLabel().getMouseListeners()) { task.getTextLabel().removeMouseListener(mouseListener); } } jWindow.removeWindowListener(listener); jOK.removeActionListener(listener); jCancel.removeActionListener(listener); jMinimize.removeActionListener(listener); updateTask.removePropertyChangeListener(listener); for (UpdateTask updateTaskLoop : updateTasks) { updateTaskLoop.removeErrorListener(); } if (progress != null) { program.getStatusPanel().removeProgress(progress); } jWindow.setVisible(false); } } private void cancelUpdate() { int cancelledIndex = index; index = updateTasks.size(); updateTask.addWarning("Update", "Cancelled"); updateTask.cancel(true); for (int i = cancelledIndex; i < updateTasks.size(); i++) { updateTasks.get(i).cancelled(); } jProgressBar.setIndeterminate(false); jProgressBar.setValue(0); jIcon.setIcon(new UpdateTask.EmptyIcon()); jMinimize.setEnabled(false); //Should not minimize after cancel } private class ListenerClass implements PropertyChangeListener, ActionListener, WindowListener { @Override public void propertyChange(final PropertyChangeEvent evt) { Integer totalProgress = updateTask.getTotalProgress(); if (totalProgress != null && totalProgress > 0 && totalProgress <= 100) { jTotalProgressBar.setValue(totalProgress); jTotalProgressBar.setIndeterminate(false); } else { jTotalProgressBar.setIndeterminate(true); } if (progress != null) { if (totalProgress != null && totalProgress > 0 && totalProgress <= 100) { progress.setValue(totalProgress); progress.setIndeterminate(false); } else { progress.setIndeterminate(true); } } int value = updateTask.getProgress(); jIcon.setIcon(updateTask.getIcon()); if (value == 100 && updateTask.isTaskDone()) { updateTask.setTaskDone(false); jProgressBar.setValue(100); jProgressBar.setIndeterminate(false); index++; update(); } else if (value > 1) { jProgressBar.setIndeterminate(false); jProgressBar.setValue(value); } else { jProgressBar.setIndeterminate(true); } } @Override public void actionPerformed(final ActionEvent e) { if (TaskAction.OK.name().equals(e.getActionCommand())) { setVisible(false); } else if (TaskAction.CANCEL.name().equals(e.getActionCommand())) { cancelUpdate(); } else if (TaskAction.MINIMIZE.name().equals(e.getActionCommand())) { progress.setVisible(true); jWindow.setVisible(false); } } @Override public void windowOpened(final WindowEvent e) { } @Override public void windowClosing(final WindowEvent e) { if (index >= updateTasks.size()) { setVisible(false); } else { int value = JOptionPane.showConfirmDialog(jWindow, DialoguesUpdate.get().cancelQuestion(), DialoguesUpdate.get().cancelQuestionTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (value == JOptionPane.YES_OPTION) { cancelUpdate(); setVisible(false); } } } @Override public void windowClosed(final WindowEvent e) { } @Override public void windowIconified(final WindowEvent e) { } @Override public void windowDeiconified(final WindowEvent e) { } @Override public void windowActivated(final WindowEvent e) { } @Override public void windowDeactivated(final WindowEvent e) { } } public class ErrorListener implements MouseListener, ActionListener { private final UpdateTask mouseTask; public ErrorListener(final UpdateTask mouseTask) { this.mouseTask = mouseTask; } @Override public void actionPerformed(ActionEvent e) { handleEvent(); } @Override public void mouseClicked(final MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1) { handleEvent(); } } @Override public void mousePressed(final MouseEvent e) { } @Override public void mouseReleased(final MouseEvent e) { } @Override public void mouseEntered(final MouseEvent e) { } @Override public void mouseExited(final MouseEvent e) { } private void handleEvent() { if (mouseTask.hasLog()) { jErrorMessage.setText(""); jErrorName.setText(""); boolean shown = mouseTask.isErrorShown(); for (UpdateTask task : updateTasks) { task.showLog(false); } if (shown) { mouseTask.showLog(false); jErrorScroll.setVisible(false); jErrorName.setVisible(false); jWindow.pack(); } else { jErrorScroll.setVisible(true); jErrorName.setVisible(true); jWindow.pack(); mouseTask.showLog(true); mouseTask.insertLog(jErrorMessage); jErrorName.setText(mouseTask.getName()); } } } } public static interface TasksCompleted { public void tasksCompleted(TaskDialog taskDialog); } public static interface TasksCompletedAdvanced extends TasksCompleted { public void tasksHidden(TaskDialog taskDialog); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/update/UpdateDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.update; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.GroupLayout.Alignment; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JRadioButton; import javax.swing.JToggleButton; import javax.swing.Timer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.Updatable; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.tabs.values.AssetValue; import net.nikr.eve.jeveasset.i18n.DialoguesUpdate; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.io.esi.EsiAccountBalanceGetter; import net.nikr.eve.jeveasset.io.esi.EsiAssetsGetter; import net.nikr.eve.jeveasset.io.esi.EsiBlueprintsGetter; import net.nikr.eve.jeveasset.io.esi.EsiClonesGetter; import net.nikr.eve.jeveasset.io.esi.EsiContractItemsGetter; import net.nikr.eve.jeveasset.io.esi.EsiContractsGetter; import net.nikr.eve.jeveasset.io.esi.EsiDivisionsGetter; import net.nikr.eve.jeveasset.io.esi.EsiFactionWarfareGetter; import net.nikr.eve.jeveasset.io.esi.EsiIndustryJobsGetter; import net.nikr.eve.jeveasset.io.esi.EsiJournalGetter; import net.nikr.eve.jeveasset.io.esi.EsiLocationsGetter; import net.nikr.eve.jeveasset.io.esi.EsiLoyaltyPointsGetter; import net.nikr.eve.jeveasset.io.esi.EsiManufacturingPrices; import net.nikr.eve.jeveasset.io.esi.EsiMarketOrdersGetter; import net.nikr.eve.jeveasset.io.esi.EsiMiningGetter; import net.nikr.eve.jeveasset.io.esi.EsiNameGetter; import net.nikr.eve.jeveasset.io.esi.EsiOwnerGetter; import net.nikr.eve.jeveasset.io.esi.EsiPlanetaryInteractionGetter; import net.nikr.eve.jeveasset.io.esi.EsiShipGetter; import net.nikr.eve.jeveasset.io.esi.EsiSkillGetter; import net.nikr.eve.jeveasset.io.esi.EsiNpcStandingGetter; import net.nikr.eve.jeveasset.io.esi.EsiTransactionsGetter; import net.nikr.eve.jeveasset.io.online.EveImageGetter; import net.nikr.eve.jeveasset.io.online.PriceDataGetter; import net.nikr.eve.jeveasset.io.shared.ThreadWoker; public class UpdateDialog extends JDialogCentered { private enum UpdateDialogAction { CANCEL, UPDATE, CHANGED, CHECK_ALL } public static enum Updates { MARKET_ORDERS(DialoguesUpdate.get().marketOrders()){ @Override public boolean isEnabled(OwnerType owner) { return owner.isMarketOrders(); } @Override public Date getNextUpdate(OwnerType owner) { return owner.getMarketOrdersNextUpdate(); } }, JOURNAL(DialoguesUpdate.get().journal()){ @Override public boolean isEnabled(OwnerType owner) { return owner.isJournal(); } @Override public Date getNextUpdate(OwnerType owner) { return owner.getJournalNextUpdate(); } }, TRANSACTIONS(DialoguesUpdate.get().transactions()){ @Override public boolean isEnabled(OwnerType owner) { return owner.isTransactions(); } @Override public Date getNextUpdate(OwnerType owner) { return owner.getTransactionsNextUpdate(); } }, INDUSTRY_JOBS(DialoguesUpdate.get().industryJobs()){ @Override public boolean isEnabled(OwnerType owner) { return owner.isIndustryJobs(); } @Override public Date getNextUpdate(OwnerType owner) { return owner.getIndustryJobsNextUpdate(); } }, ACCOUNT_BALANCE(DialoguesUpdate.get().accountBalance()){ @Override public boolean isEnabled(OwnerType owner) { return owner.isAccountBalance(); } @Override public Date getNextUpdate(OwnerType owner) { return owner.getBalanceNextUpdate(); } }, CONTRACTS(DialoguesUpdate.get().contracts()){ @Override public boolean isEnabled(OwnerType owner) { return owner.isContracts(); } @Override public Date getNextUpdate(OwnerType owner) { return owner.getContractsNextUpdate(); } }, ASSETS(DialoguesUpdate.get().assets()) { @Override public boolean isEnabled(OwnerType owner) { return owner.isAssetList(); } @Override public Date getNextUpdate(OwnerType owner) { return owner.getAssetNextUpdate(); } }, BLUEPRINTS(DialoguesUpdate.get().blueprints()){ @Override public boolean isEnabled(OwnerType owner) { return owner.isBlueprints(); } @Override public Date getNextUpdate(OwnerType owner) { return owner.getBlueprintsNextUpdate(); } }, SKILLS(DialoguesUpdate.get().skills()){ @Override public boolean isEnabled(OwnerType owner) { return owner.isSkills(); } @Override public Date getNextUpdate(OwnerType owner) { return owner.getSkillsNextUpdate(); } }, LOYALTY_POINTS(DialoguesUpdate.get().loyaltyPoints()){ @Override public boolean isEnabled(OwnerType owner) { return owner.isLoyaltyPoints(); } @Override public Date getNextUpdate(OwnerType owner) { return owner.getLoyaltyPointsNextUpdate(); } }, NPC_STANDING(DialoguesUpdate.get().npcStanding()) { @Override public boolean isEnabled(OwnerType owner) { return owner.isNpcStanding(); } @Override public Date getNextUpdate(OwnerType owner) { return owner.getNpcStandingNextUpdate(); } }, MINING(DialoguesUpdate.get().mining()){ @Override public boolean isEnabled(OwnerType owner) { return owner.isMining(); } @Override public Date getNextUpdate(OwnerType owner) { return owner.getMiningNextUpdate(); } }; private final String title; private UpdateUI updateUI = null; private Date first = null; private Date last = null; private Updates(String title) { this.title = title; } public abstract boolean isEnabled(OwnerType owner); public abstract Date getNextUpdate(OwnerType owner); public Date getFirst() { return first; } public Date getLast() { return last; } public JCheckBox getCheckBox() { return getUI().getCheckBox(); } public JLabel getLeftFirst() { return getUI().getLeftFirst(); } public JLabel getLeftLast() { return getUI().getLeftLast(); } public boolean isSelected() { return getCheckBox().isSelected(); } public void setSelected(boolean b) { getCheckBox().setSelected(b); } public void reset() { first = null; last = null; } public void updateDates(OwnerType owner) { if (isEnabled(owner)) { first = updateFirst(first, getNextUpdate(owner)); last = updateLast(last, getNextUpdate(owner)); } } private UpdateUI getUI() { if (updateUI == null) { updateUI = new UpdateUI(title); } return updateUI; } private Date updateFirst(Date nextUpdate, Date thisUpdate) { if (nextUpdate == null) { //First nextUpdate = thisUpdate; } else if (thisUpdate.before(nextUpdate)) { nextUpdate = thisUpdate; } return nextUpdate; } private Date updateLast(Date lastUpdate, Date thisUpdate) { if (lastUpdate == null) { //First lastUpdate = thisUpdate; } else if (thisUpdate.after(lastUpdate)) { lastUpdate = thisUpdate; } return lastUpdate; } } private final JCheckBox jCheckAll; private final JRadioButton jPriceDataAll; private final JRadioButton jPriceDataNew; private final JRadioButton jPriceDataNone; private final JLabel jPriceDataLeft; private final JButton jUpdate; private final JButton jCancel; private final Timer timer; public UpdateDialog(final Program program) { super(program, DialoguesUpdate.get().update(), Images.DIALOG_UPDATE.getImage()); ListenerClass listener = new ListenerClass(); timer = new Timer(1000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { update(false); } }); jCheckAll = new JCheckBox(General.get().all()); jCheckAll.setActionCommand(UpdateDialogAction.CHECK_ALL.name()); jCheckAll.addActionListener(listener); JLabel jLeftFirst = new JLabel(DialoguesUpdate.get().firstAccount()); JLabel jLeftLast = new JLabel(DialoguesUpdate.get().allAccounts()); jPriceDataAll = new JRadioButton(DialoguesUpdate.get().priceData()); jPriceDataAll.setActionCommand(UpdateDialogAction.CHANGED.name()); jPriceDataAll.addActionListener(listener); jPriceDataNew = new JRadioButton(DialoguesUpdate.get().priceDataNew()); jPriceDataNew.setActionCommand(UpdateDialogAction.CHANGED.name()); jPriceDataNew.addActionListener(listener); jPriceDataNone = new JRadioButton(DialoguesUpdate.get().priceDataNone()); jPriceDataNone.setActionCommand(UpdateDialogAction.CHANGED.name()); jPriceDataNone.addActionListener(listener); jPriceDataLeft = new JLabel(); ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(jPriceDataAll); buttonGroup.add(jPriceDataNew); buttonGroup.add(jPriceDataNone); jUpdate = new JButton(DialoguesUpdate.get().update()); jUpdate.setActionCommand(UpdateDialogAction.UPDATE.name()); jUpdate.addActionListener(listener); jCancel = new JButton(DialoguesUpdate.get().cancel()); jCancel.setActionCommand(UpdateDialogAction.CANCEL.name()); jCancel.addActionListener(listener); GroupLayout.ParallelGroup horizontalCheckBox = layout.createParallelGroup(); GroupLayout.ParallelGroup horizontalLeftFirst = layout.createParallelGroup(Alignment.TRAILING); GroupLayout.ParallelGroup horizontalLeftLast = layout.createParallelGroup(Alignment.TRAILING); horizontalCheckBox.addComponent(jCheckAll); horizontalLeftFirst.addComponent(jLeftFirst); horizontalLeftLast.addComponent(jLeftLast); GroupLayout.SequentialGroup vertical = layout.createSequentialGroup(); vertical.addGroup(layout.createParallelGroup() .addComponent(jCheckAll, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jLeftFirst, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jLeftLast, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); for (Updates updates : Updates.values()) { JCheckBox jCheckBox = updates.getCheckBox(); horizontalCheckBox.addComponent(jCheckBox); horizontalLeftFirst.addComponent(updates.getLeftFirst()); horizontalLeftLast.addComponent(updates.getLeftLast()); vertical.addGroup(layout.createParallelGroup() .addComponent(updates.getCheckBox(), Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(updates.getLeftFirst(), Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(updates.getLeftLast(), Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); jCheckBox.setActionCommand(UpdateDialogAction.CHANGED.name()); jCheckBox.addActionListener(listener); } horizontalLeftLast.addComponent(jPriceDataLeft); vertical.addGroup(layout.createParallelGroup() .addComponent(jPriceDataAll, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jPriceDataNew, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jPriceDataNone, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jPriceDataLeft, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(30) .addGroup(layout.createParallelGroup() .addComponent(jUpdate, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); layout.setHorizontalGroup( layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addGroup(horizontalCheckBox) .addGap(20) .addGroup(horizontalLeftFirst) .addGap(20) ) .addGroup(layout.createSequentialGroup() .addComponent(jPriceDataAll) .addGap(10) .addComponent(jPriceDataNew) .addGap(10) .addComponent(jPriceDataNone) ) ) .addGroup(horizontalLeftLast) ) .addGroup(Alignment.TRAILING, layout.createSequentialGroup() .addComponent(jUpdate, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup(vertical); } private void changed() { boolean allChecked = true; boolean someChecked = false; boolean allDisabled = true; for (Updates updates : Updates.values()) { JCheckBox jCheckBox = updates.getCheckBox(); if (jCheckBox.isEnabled()) { if (jCheckBox.isSelected()) { someChecked = true; } else { allChecked = false; } allDisabled = false; } } if (jPriceDataAll.isEnabled()) { if (jPriceDataAll.isSelected()) { someChecked = true; } else { //Not selected allChecked = false; } allDisabled = false; } else if (jPriceDataNew.isEnabled()) { if (!jPriceDataNew.isSelected()) { allChecked = false; } allDisabled = false; } jUpdate.setEnabled(someChecked); jCheckAll.setSelected(allChecked && !allDisabled); jCheckAll.setEnabled(!allDisabled); } private void update(boolean check) { for (Updates updates : Updates.values()) { updates.reset(); } Date priceData = program.getPriceDataGetter().getNextUpdate(); for (OwnerType owner : program.getOwnerTypes()) { if (!owner.isShowOwner() || owner.isInvalid() || owner.isExpired()) { continue; } for (Updates updates : Updates.values()) { updates.updateDates(owner); } } if (program.getOwnerTypes().isEmpty()) { jPriceDataNone.setSelected(true); jPriceDataNone.setEnabled(false); jPriceDataNew.setEnabled(false); jPriceDataAll.setEnabled(false); setUpdateLabel(null, jPriceDataLeft, jPriceDataAll, null, null, check); } else { jPriceDataNone.setEnabled(true); jPriceDataNew.setEnabled(true); jPriceDataAll.setEnabled(true); setUpdateLabel(null, jPriceDataLeft, jPriceDataAll, null, priceData, check); if (!jPriceDataAll.isEnabled() && jPriceDataNew.isEnabled() && !jPriceDataNone.isSelected()) { jPriceDataNew.setSelected(true); } } for (Updates updates : Updates.values()) { setUpdateLabel(updates.getLeftFirst(), updates.getLeftLast(), updates.getCheckBox(), updates.getFirst(), updates.getLast(), check); } changed(); } private void setUpdateLabel(final JLabel jFirst, final JLabel jLast, final JToggleButton jCheckBox, final Date first, final Date last, boolean check) { if (jFirst != null) { if (Updatable.isUpdatable(last)) { jFirst.setText(""); } else { jFirst.setText(getFormattedDuration(first)); } jFirst.setEnabled(first != null); } else { } if (jLast != null) { jLast.setText(getFormattedDuration(last)); jLast.setEnabled(last != null); } if (jCheckBox != null) { if ((Updatable.isUpdatable(first) || Updatable.isUpdatable(last))) { if (!jCheckBox.isEnabled()) { if (check) { jCheckBox.setSelected(true); } jCheckBox.setEnabled(true); } } else { jCheckBox.setEnabled(false); jCheckBox.setSelected(false); } } } private String getFormattedDuration(Date date) { if (date == null) { //less than 1 second return DialoguesUpdate.get().noAccounts(); } else if (Updatable.isUpdatable(date)) { return DialoguesUpdate.get().now(); } else { long time = date.getTime() - Settings.getNow().getTime(); if (time <= 1000) { //less than 1 second return "..."; } else if (time < (60 * 1000)) { //less than 1 minute return Formatter.milliseconds(time, false, false, false, true); } else { return Formatter.milliseconds(time, true, true, true, false); } } } @Override protected JComponent getDefaultFocus() { return jUpdate; } @Override protected JButton getDefaultButton() { return jUpdate; } @Override protected void windowShown() { } @Override public void setVisible(boolean b) { if (b) { for (Updates updates : Updates.values()) { updates.setSelected(true); } jPriceDataAll.setSelected(true); update(true); timer.start(); } else { timer.stop(); } super.setVisible(b); } @Override protected void save() { } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (UpdateDialogAction.UPDATE.name().equals(e.getActionCommand())) { setVisible(false); List updateTasks = new ArrayList<>(); if (Updates.ASSETS.isSelected() || Updates.ACCOUNT_BALANCE.isSelected() || Updates.BLUEPRINTS.isSelected() || Updates.CONTRACTS.isSelected() || Updates.INDUSTRY_JOBS.isSelected() || Updates.JOURNAL.isSelected() || Updates.MARKET_ORDERS.isSelected() || Updates.MINING.isSelected() || Updates.TRANSACTIONS.isSelected() || Updates.SKILLS.isSelected() || Updates.LOYALTY_POINTS.isSelected() || Updates.NPC_STANDING.isSelected() ) { updateTasks.add(new Step1Task(program.getProfileManager())); updateTasks.add(new Step2Task(program.getProfileManager(), Updates.ASSETS.isSelected(), Updates.ACCOUNT_BALANCE.isSelected(), Updates.BLUEPRINTS.isSelected(), Updates.CONTRACTS.isSelected(), Updates.INDUSTRY_JOBS.isSelected(), Updates.JOURNAL.isSelected(), Updates.MARKET_ORDERS.isSelected(), Updates.MINING.isSelected(), Updates.TRANSACTIONS.isSelected(), Updates.SKILLS.isSelected(), Updates.LOYALTY_POINTS.isSelected(), Updates.NPC_STANDING.isSelected())); updateTasks.add(new Step3Task(program.getProfileManager(), Updates.ASSETS.isSelected())); } if (Updates.CONTRACTS.isSelected()) { updateTasks.add(new Step4Task(program.getProfileManager())); } if (jPriceDataAll.isSelected() || jPriceDataNew.isSelected()) { updateTasks.add(new PriceDataTask(program.getPriceDataGetter(), program.getProfileData(), jPriceDataAll.isSelected())); } if (!updateTasks.isEmpty()) { //Pause structure update program.getStatusPanel().setPauseUpdates(true); TaskDialog taskDialog = new TaskDialog(program, updateTasks, false, false, false, null, new TaskDialog.TasksCompleted() { @Override public void tasksCompleted(TaskDialog taskDialog) { //Update tracker locations AssetValue.updateData(); //Update eventlists program.updateEventLists(); //Create value tracker point program.createTrackerDataPoint(); //Save settings after updating (if we crash later) program.saveSettingsAndProfile(); //Save updated id<->name data //Resume structure update program.getStatusPanel().setPauseUpdates(false); } }); } } if (UpdateDialogAction.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); } if (UpdateDialogAction.CHANGED.name().equals(e.getActionCommand())) { changed(); } if (UpdateDialogAction.CHECK_ALL.name().equals(e.getActionCommand())) { boolean checked = jCheckAll.isSelected(); for (Updates updates : Updates.values()) { JCheckBox jCheckBox = updates.getCheckBox(); if (jCheckBox.isEnabled()) { jCheckBox.setSelected(checked); } } if (checked) { if (jPriceDataAll.isEnabled()) { jPriceDataAll.setSelected(true); } else { jPriceDataNew.setSelected(true); } } else { jPriceDataNone.setSelected(true); } changed(); } } } public static class Step1Task extends UpdateTask { private final ProfileManager profileManager; public Step1Task(final ProfileManager profileManager) { super(DialoguesUpdate.get().step1()); this.profileManager = profileManager; } @Override public void update() { setIcon(null); //Esi List updates = new ArrayList<>(); for (EsiOwner esiOwner : profileManager.getEsiOwners()) { updates.add(new EsiOwnerGetter(this, esiOwner)); } ThreadWoker.start(this, updates); } } public static class Step2Task extends UpdateTask { private final ProfileManager profileManager; private final boolean assets; private final boolean accountBalance; private final boolean blueprints; private final boolean contracts; private final boolean industryJobs; private final boolean journal; private final boolean marketOrders; private final boolean mining; private final boolean transactions; private final boolean skills; private final boolean loyaltyPoints; private final boolean npcStanding; public Step2Task(final ProfileManager profileManager, final boolean assets, final boolean accountBalance, final boolean blueprints, final boolean contracts, final boolean industryJobs, final boolean journal, final boolean marketOrders, final boolean mining, final boolean transactions, final boolean skills, final boolean loyaltyPoints, final boolean npcStanding) { super(DialoguesUpdate.get().step2()); this.profileManager = profileManager; this.assets = assets; this.accountBalance = accountBalance; this.blueprints = blueprints; this.contracts = contracts; this.industryJobs = industryJobs; this.journal = journal; this.marketOrders = marketOrders; this.mining = mining; this.transactions = transactions; this.skills = skills; this.loyaltyPoints = loyaltyPoints; this.npcStanding = npcStanding; } @Override public void update() { setIcon(null); //Esi List updates = new ArrayList<>(); for (EsiOwner esiOwner : profileManager.getEsiOwners()) { if (accountBalance) { updates.add(new EsiAccountBalanceGetter(this, esiOwner)); } if (assets) { updates.add(new EsiAssetsGetter(this, esiOwner)); if (esiOwner.isCorporation()) { updates.add(new EsiDivisionsGetter(this, esiOwner)); } } if (industryJobs) { updates.add(new EsiIndustryJobsGetter(this, esiOwner, Settings.get().isIndustryJobsHistory())); } if (mining) { updates.add(new EsiMiningGetter(this, esiOwner, Settings.get().isMiningHistory())); } if (marketOrders) { updates.add(new EsiMarketOrdersGetter(this, esiOwner, Settings.get().isMarketOrderHistory())); } if (journal) { updates.add(new EsiJournalGetter(this, esiOwner, Settings.get().isJournalHistory())); } if (transactions) { updates.add(new EsiTransactionsGetter(this, esiOwner, Settings.get().isTransactionHistory())); } if (contracts) { updates.add(new EsiContractsGetter(this, esiOwner, Settings.get().isContractHistory())); } if (blueprints) { updates.add(new EsiBlueprintsGetter(this, esiOwner)); } if (skills) { updates.add(new EsiSkillGetter(this, esiOwner)); } if (loyaltyPoints) { updates.add(new EsiLoyaltyPointsGetter(this, esiOwner)); } if (npcStanding) { updates.add(new EsiNpcStandingGetter(this, esiOwner)); } } ThreadWoker.start(this, updates); } } public static class Step3Task extends UpdateTask { private final ProfileManager profileManager; private final boolean assets; private final Map assetNextUpdate = new HashMap<>(); public Step3Task(final ProfileManager profileManager, final boolean assets) { super(DialoguesUpdate.get().step3()); this.profileManager = profileManager; this.assets = assets; for (EsiOwner esiOwner : profileManager.getEsiOwners()) { assetNextUpdate.put(esiOwner, esiOwner.getAssetNextUpdate()); } } @Override public void update() { setIcon(null); List updates = new ArrayList<>(); //Locations if (assets) { //Esi for (EsiOwner esiOwner : profileManager.getEsiOwners()) { updates.add(new EsiLocationsGetter(this, esiOwner)); updates.add(new EsiShipGetter(this, esiOwner, assetNextUpdate.getOrDefault(esiOwner, Settings.getNow()))); updates.add(new EsiPlanetaryInteractionGetter(this, esiOwner, assetNextUpdate.getOrDefault(esiOwner, Settings.getNow()))); updates.add(new EsiClonesGetter(this, esiOwner, assetNextUpdate.getOrDefault(esiOwner, Settings.getNow()))); } } updates.add(new EsiFactionWarfareGetter(this)); //char/corp/alliance IDs to names (ESI) updates.add(new EsiNameGetter(this, profileManager.getOwnerTypes())); //char/corp/alliance images updates.add(new EveImageGetter(this, profileManager.getOwnerTypes())); ThreadWoker.start(this, updates); } } public static class Step4Task extends UpdateTask { private final ProfileManager profileManager; public Step4Task(final ProfileManager profileManager) { super(DialoguesUpdate.get().step4()); this.profileManager = profileManager; } @Override public void update() { setIcon(null); //Contract Items //Esi List updates = new ArrayList<>(); EsiContractItemsGetter.reset(); for (EsiOwner esiOwner : profileManager.getEsiOwners()) { updates.add(new EsiContractItemsGetter(this, esiOwner, profileManager.getEsiOwners(), Settings.get().isContractHistory())); } ThreadWoker.start(this, updates, false); } } public static class PriceDataTask extends UpdateTask { private final PriceDataGetter priceDataGetter; private final ProfileData profileData; private final boolean update; public PriceDataTask(final PriceDataGetter priceDataGetter, final ProfileData profileData, final boolean update) { super(DialoguesUpdate.get().priceData() + " (" + (Settings.get().getPriceDataSettings().getSource().toString()) + ")"); this.priceDataGetter = priceDataGetter; this.profileData = profileData; this.update = update; } @Override public void update() { setIcon(Settings.get().getPriceDataSettings().getSource().getIcon()); ThreadWoker.start(this, Collections.singleton(new EsiManufacturingPrices(this)), false); if (update) { priceDataGetter.updateAll(profileData, this); } else { priceDataGetter.updateNew(profileData, this); } } } private static class UpdateUI { private final JCheckBox jCheckBox; private final JLabel jLeftFirst; private final JLabel jLeftLast; public UpdateUI(String title) { jCheckBox = new JCheckBox(title); jLeftFirst = new JLabel(); jLeftLast = new JLabel(); } public JCheckBox getCheckBox() { return jCheckBox; } public JLabel getLeftFirst() { return jLeftFirst; } public JLabel getLeftLast() { return jLeftLast; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/dialogs/update/UpdateTask.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.dialogs.update; import java.awt.Component; import java.awt.Cursor; import java.awt.Font; import java.awt.Graphics; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.concurrent.CancellationException; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JTextPane; import javax.swing.SwingWorker; import javax.swing.text.*; import net.nikr.eve.jeveasset.gui.dialogs.update.TaskDialog.ErrorListener; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.i18n.DialoguesUpdate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class UpdateTask extends SwingWorker { private static final Logger LOG = LoggerFactory.getLogger(UpdateTask.class); private Icon icon; private final JLabel jText; private final JButton jShow; private final List log; private final String name; private Integer totalProgress = null; private boolean info = false; private boolean warning = false; private boolean error = false; private boolean errorShown = false; private boolean taskDone = false; private boolean pause = false; private ErrorListener errorListener; public UpdateTask(final String name) { this.name = name; this.addPropertyChangeListener(new ListenerClass()); jText = new JLabel(name); jText.setIcon(Images.UPDATE_NOT_STARTED.getIcon()); jText.setFont(jText.getFont().deriveFont(Font.PLAIN)); jShow = new JButton(); jShow.setFocusPainted(false); jShow.setIcon(Images.MISC_EXPANDED.getIcon()); jShow.setVisible(false); log = Collections.synchronizedList(new ArrayList<>()); } public void addErrorListener(ErrorListener errorListener) { removeErrorListener(); jShow.addActionListener(errorListener); jText.addMouseListener(errorListener); this.errorListener = errorListener; } public void removeErrorListener() { if (errorListener != null) { jShow.removeActionListener(errorListener); jText.removeMouseListener(errorListener); errorListener = null; } } public void setTotalProgress(final float end, final float progress, final int minimum, final int maximum) { int percent = Math.round(((progress / end) * (maximum - minimum)) + minimum); if (percent > 100) { percent = 100; } else if (percent < 0) { percent = 0; } if (totalProgress == null || totalProgress != percent) { Integer oldValue = totalProgress; totalProgress = percent; firePropertyChange("TotalProgress", oldValue, percent); } } public void pause() { while (isPause()) { synchronized(this) { try { wait(); } catch (InterruptedException ex) { //No problem } } } } public synchronized boolean isPause() { return pause; } public synchronized void setPause(boolean pause) { this.pause = pause; notifyAll(); } public Integer getTotalProgress() { return totalProgress; } public String getName() { return name; } public JLabel getTextLabel() { return jText; } public int getWidth() { int width = jText.getPreferredSize().width; int plain = jText.getFontMetrics(jText.getFont()).stringWidth(name); int bold = jText.getFontMetrics(jText.getFont().deriveFont(Font.BOLD)).stringWidth(name); return width + (bold - plain); } public JButton getShowButton() { return jShow; } public void addError(final String owner, final String msg) { log.add(new LogClass(owner, msg)); error = true; } public void addWarning(final String owner, final String msg) { log.add(new LogClass(owner, msg)); warning = true; } public void addInfo(final String owner, final String msg) { log.add(new LogClass(owner, msg)); info = true; } public boolean hasInfo() { return info; } public boolean hasWarning() { return warning; } public boolean hasError() { return error; } public boolean hasLog() { return !log.isEmpty(); } public Icon getIcon() { if (icon == null) { icon = Images.UPDATE_WORKING.getIcon(); } return icon; } public final void setIcon(Icon icon) { this.icon = icon; } public abstract void update(); @Override public Void doInBackground() { setProgress(0); update(); return null; } @Override public void done() { try { get(); } catch (CancellationException ex) { LOG.info("Update cancelled by user"); } catch (Exception ex) { //InterruptedException, ExecutionException LOG.error(ex.getMessage(), ex); throw new RuntimeException(ex); } taskDone = true; setProgress(100); } public boolean isTaskDone() { return taskDone; } public void setTaskDone(final boolean done) { this.taskDone = done; } protected void setTaskProgress(final int progress) { this.setProgress(progress); } public void insertLog(final JTextPane jError) { if (!log.isEmpty()) { StyledDocument doc = new DefaultStyledDocument(); UpdateTask.this.insertLog(doc); jError.setDocument(doc); } } public void insertLog(final StyledDocument doc) { if (!log.isEmpty()) { SimpleAttributeSet errorAttributeSet = new SimpleAttributeSet(); errorAttributeSet.addAttribute(StyleConstants.CharacterConstants.Foreground, jText.getBackground().darker().darker()); try { boolean first = true; synchronized (log) { for (LogClass errorClass : log) { if (first) { first = false; } else { doc.insertString(doc.getLength(), "\n\r", null); } doc.insertString(doc.getLength(), errorClass.getOwner(), null); doc.insertString(doc.getLength(), "\r\n" + processError(errorClass.getError()), errorAttributeSet); } } } catch (BadLocationException ex) { LOG.warn("Ignoring exception: " + ex.getMessage(), ex); } } } public void setTaskProgress(final float progressEnd, final float progressNow, final int minimum, final int maximum) { int progress = Math.round(((progressNow / progressEnd) * (maximum - minimum)) + minimum); if (progress > 100) { progress = 100; } else if (progress < 0) { progress = 0; } if (progress != getProgress()) { setProgress(progress); } } public void resetTaskProgress() { setProgress(0); } public void cancelled() { jText.setIcon(Images.UPDATE_CANCELLED.getIcon()); } public void showLog(final boolean b) { if (!log.isEmpty()) { if (b) { errorShown = true; jText.setFont(jText.getFont().deriveFont(Font.BOLD)); jShow.setIcon(Images.MISC_COLLAPSED.getIcon()); jShow.setSelected(true); jShow.requestFocusInWindow(); } else { jText.setFont(jText.getFont().deriveFont(Font.PLAIN)); jShow.setIcon(Images.MISC_EXPANDED.getIcon()); jShow.setSelected(false); errorShown = false; } } } public boolean isErrorShown() { return errorShown; } private String processError(String error) { if (error == null) { return ""; } Pattern p = Pattern.compile("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}"); DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Matcher m = p.matcher(error); while (m.find()) { int start = m.start(); int end = m.end(); String time = error.substring(start, end); try { Date date = df.parse(time); time = Formatter.weekdayAndTime(date); } catch (ParseException ex) { time = error.substring(start, end); } error = error.substring(0, start) + time + error.substring(end); error = error.replace("retry after", "\r\n" + DialoguesUpdate.get().nextUpdate()); } return error; } private class ListenerClass implements PropertyChangeListener { @Override public void propertyChange(final PropertyChangeEvent evt) { int value = getProgress(); if (value == 100) { if (error) { jText.setIcon(Images.UPDATE_DONE_ERROR.getIcon()); jShow.setVisible(true); } else if (isCancelled() || warning) { jText.setIcon(Images.UPDATE_DONE_SOME.getIcon()); jShow.setVisible(true); } else if (info) { jText.setIcon(Images.UPDATE_DONE_INFO.getIcon()); jShow.setVisible(true); } else { jShow.setVisible(false); jText.setIcon(Images.UPDATE_DONE_OK.getIcon()); } if (!log.isEmpty()) { jText.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } } else { jText.setIcon(Images.UPDATE_WORKING.getIcon()); } } } private static class LogClass { private final String owner; private final String error; public LogClass(String owner, String error) { this.owner = owner; this.error = error; } public String getOwner() { return owner; } public String getError() { return error; } } public static class EmptyIcon implements Icon { @Override public void paintIcon(Component c, Graphics g, int x, int y) { //Nothing to paint } @Override public int getIconWidth() { return 16; } @Override public int getIconHeight() { return 16; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/frame/MainMenu.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.util.concurrent.ExecutionException; import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.CliOptions; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.i18n.GuiFrame; public class MainMenu extends JMenuBar { private static final long serialVersionUID = 1L; public enum MainMenuAction { VALUES, VALUE_TABLE, PRICE_HISTORY, LOADOUTS, MARKET_ORDERS, TRANSACTION, JOURNAL, INDUSTRY_JOBS, OVERVIEW, MATERIALS, ACCOUNT_MANAGER, PROFILES, OPTIONS, ABOUT, LICENSE, CREDITS, README, CHANGELOG, LINK_FEEDBACK_AND_HELP, LINK_WIKI, LINK_DISCORD, ROUTING, STOCKPILE, UPDATE, UPDATE_STRUCTURE, ITEMS, TREE, TRACKER, REPROCESSED, CONTRACTS, SLOTS, SKILLS, SKILLS_OVERVIEW, LOYALTY_POINTS, NPC_STANDING, AGENTS, MINING_ALL, MINING_LOG, MINING_GRAPH, EXTRACTIONS, PRICE_CHANGES, EXIT_PROGRAM } private final JMenuItem jUpdateMenu; private final JMenuItem jStructureMenu; private final JMenu jTableMenu; public MainMenu(final Program program) { JMenu menu; JMenu submenu; JMenuItem menuItem; JCheckBoxMenuItem checkBoxMenuItem; //FILE menu = new JMenu(GuiFrame.get().file()); menu.setMnemonic(KeyEvent.VK_F); this.add(menu); menuItem = new JMenuItem(GuiFrame.get().exit()); menuItem.setIcon(Images.MISC_EXIT.getIcon()); menuItem.setActionCommand(MainMenuAction.EXIT_PROGRAM.name()); menuItem.addActionListener(program); menu.add(menuItem); //TOOLS menu = new JMenu(GuiFrame.get().tools()); menu.setMnemonic(KeyEvent.VK_T); this.add(menu); //ISK submenu = new JMenu(GuiFrame.get().netWorth()); submenu.setIcon(Images.TOOL_VALUES.getIcon()); menu.add(submenu); menuItem = new JMenuItem(GuiFrame.get().tracker()); menuItem.setIcon(Images.TOOL_TRACKER.getIcon()); menuItem.setActionCommand(MainMenuAction.TRACKER.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().values()); menuItem.setIcon(Images.TOOL_VALUES.getIcon()); menuItem.setActionCommand(MainMenuAction.VALUES.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().valueTable()); menuItem.setIcon(Images.TOOL_VALUE_TABLE.getIcon()); menuItem.setActionCommand(MainMenuAction.VALUE_TABLE.name()); menuItem.addActionListener(program); submenu.add(menuItem); submenu.addSeparator(); menuItem = new JMenuItem(GuiFrame.get().priceHistory()); menuItem.setIcon(Images.TOOL_PRICE_HISTORY.getIcon()); menuItem.setActionCommand(MainMenuAction.PRICE_HISTORY.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().priceChanges()); menuItem.setIcon(Images.TOOL_PRICE_CHANGE.getIcon()); menuItem.setActionCommand(MainMenuAction.PRICE_CHANGES.name()); menuItem.addActionListener(program); submenu.add(menuItem); //Invertory submenu = new JMenu(GuiFrame.get().inventory()); // submenu.setIcon(Images.TOOL_ASSETS.getIcon()); menu.add(submenu); menuItem = new JMenuItem(GuiFrame.get().tree()); menuItem.setIcon(Images.TOOL_TREE.getIcon()); menuItem.setActionCommand(MainMenuAction.TREE.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().stockpile()); menuItem.setIcon(Images.TOOL_STOCKPILE.getIcon()); menuItem.setActionCommand(MainMenuAction.STOCKPILE.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().overview()); menuItem.setIcon(Images.TOOL_OVERVIEW.getIcon()); menuItem.setActionCommand(MainMenuAction.OVERVIEW.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().materials()); menuItem.setIcon(Images.TOOL_MATERIALS.getIcon()); menuItem.setActionCommand(MainMenuAction.MATERIALS.name()); menuItem.addActionListener(program); submenu.add(menuItem); submenu = new JMenu(GuiFrame.get().mining()); submenu.setIcon(Images.TOOL_MINING.getIcon()); menu.add(submenu); menuItem = new JMenuItem(GuiFrame.get().miningAll()); menuItem.setIcon(Images.TOOL_MINING.getIcon()); menuItem.setActionCommand(MainMenuAction.MINING_ALL.name()); menuItem.addActionListener(program); submenu.add(menuItem); submenu.addSeparator(); menuItem = new JMenuItem(GuiFrame.get().miningLog()); menuItem.setIcon(Images.TOOL_MINING_LOG.getIcon()); menuItem.setActionCommand(MainMenuAction.MINING_LOG.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().miningGraph()); menuItem.setIcon(Images.TOOL_MINING_GRAPH.getIcon()); menuItem.setActionCommand(MainMenuAction.MINING_GRAPH.name()); menuItem.addActionListener(program); submenu.add(menuItem); submenu.addSeparator(); menuItem = new JMenuItem(GuiFrame.get().extractions()); menuItem.setIcon(Images.TOOL_EXTRACTIONS.getIcon()); menuItem.setActionCommand(MainMenuAction.EXTRACTIONS.name()); menuItem.addActionListener(program); submenu.add(menuItem); //Business submenu = new JMenu(GuiFrame.get().business()); submenu.setIcon(Images.TOOL_JOURNAL.getIcon()); menu.add(submenu); menuItem = new JMenuItem(GuiFrame.get().journal()); menuItem.setIcon(Images.TOOL_JOURNAL.getIcon()); menuItem.setActionCommand(MainMenuAction.JOURNAL.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().transaction()); menuItem.setIcon(Images.TOOL_TRANSACTION.getIcon()); menuItem.setActionCommand(MainMenuAction.TRANSACTION.name()); menuItem.addActionListener(program); submenu.add(menuItem); submenu.addSeparator(); menuItem = new JMenuItem(GuiFrame.get().market()); menuItem.setIcon(Images.TOOL_MARKET_ORDERS.getIcon()); menuItem.setActionCommand(MainMenuAction.MARKET_ORDERS.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().contracts()); menuItem.setIcon(Images.TOOL_CONTRACTS.getIcon()); menuItem.setActionCommand(MainMenuAction.CONTRACTS.name()); menuItem.addActionListener(program); submenu.add(menuItem); submenu.addSeparator(); menuItem = new JMenuItem(GuiFrame.get().industry()); menuItem.setIcon(Images.TOOL_INDUSTRY_JOBS.getIcon()); menuItem.setActionCommand(MainMenuAction.INDUSTRY_JOBS.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().slots()); menuItem.setIcon(Images.TOOL_SLOTS.getIcon()); menuItem.setActionCommand(MainMenuAction.SLOTS.name()); menuItem.addActionListener(program); submenu.add(menuItem); //Owners submenu = new JMenu(GuiFrame.get().owners()); submenu.setIcon(Images.MISC_OWNERS.getIcon()); menu.add(submenu); menuItem = new JMenuItem(GuiFrame.get().skills()); menuItem.setIcon(Images.TOOL_SKILLS.getIcon()); menuItem.setActionCommand(MainMenuAction.SKILLS.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().skillsOverview()); menuItem.setIcon(Images.TOOL_SKILLS.getIcon()); menuItem.setActionCommand(MainMenuAction.SKILLS_OVERVIEW.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().loyaltyPoints()); menuItem.setIcon(Images.TOOL_LOYALTY_POINTS.getIcon()); menuItem.setActionCommand(MainMenuAction.LOYALTY_POINTS.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().npcStanding()); menuItem.setIcon(Images.TOOL_NPC_STANDING.getIcon()); menuItem.setActionCommand(MainMenuAction.NPC_STANDING.name()); menuItem.addActionListener(program); submenu.add(menuItem); //Misc submenu = new JMenu(GuiFrame.get().misc()); submenu.setIcon(Images.MISC_MISC.getIcon()); menu.add(submenu); menuItem = new JMenuItem(GuiFrame.get().routing()); menuItem.setIcon(Images.TOOL_ROUTING.getIcon()); menuItem.setActionCommand(MainMenuAction.ROUTING.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().ship()); menuItem.setIcon(Images.TOOL_SHIP_LOADOUTS.getIcon()); menuItem.setActionCommand(MainMenuAction.LOADOUTS.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().reprocessed()); menuItem.setIcon(Images.TOOL_REPROCESSED.getIcon()); menuItem.setActionCommand(MainMenuAction.REPROCESSED.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().items()); menuItem.setIcon(Images.TOOL_ITEMS.getIcon()); menuItem.setActionCommand(MainMenuAction.ITEMS.name()); menuItem.addActionListener(program); submenu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().agents()); menuItem.setIcon(Images.TOOL_AGENTS.getIcon()); menuItem.setActionCommand(MainMenuAction.AGENTS.name()); menuItem.addActionListener(program); submenu.add(menuItem); //Lock menu.addSeparator(); checkBoxMenuItem = new JCheckBoxMenuItem(GuiFrame.get().lock()); checkBoxMenuItem.setSelected(Settings.get().isToolsLocked()); checkBoxMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Settings.lock("Lock Tools"); Settings.get().setToolsLocked(checkBoxMenuItem.isSelected()); Settings.unlock("Lock Tools"); program.saveSettings("Lock Tools"); program.getMainWindow().updateTabCloseButtons(); } }); menu.add(checkBoxMenuItem); //UPDATE menu = new JMenu(GuiFrame.get().update()); menu.setMnemonic(KeyEvent.VK_U); this.add(menu); jUpdateMenu = new JMenuItem(GuiFrame.get().update1()); jUpdateMenu.setIcon(Images.DIALOG_UPDATE.getIcon()); jUpdateMenu.setActionCommand(MainMenuAction.UPDATE.name()); jUpdateMenu.addActionListener(program); menu.add(jUpdateMenu); menu.addSeparator(); jStructureMenu = new JMenuItem(GuiFrame.get().updateStructure()); jStructureMenu.setIcon(Images.DIALOG_UPDATE.getIcon()); jStructureMenu.setActionCommand(MainMenuAction.UPDATE_STRUCTURE.name()); jStructureMenu.addActionListener(program); menu.add(jStructureMenu); //TABLE jTableMenu = new JMenu(GuiFrame.get().table()); jTableMenu.setMnemonic(KeyEvent.VK_A); this.add(jTableMenu); //OPTIONS menu = new JMenu(GuiFrame.get().options()); menu.setMnemonic(KeyEvent.VK_O); this.add(menu); menuItem = new JMenuItem(GuiFrame.get().accounts()); menuItem.setIcon(Images.DIALOG_ACCOUNTS.getIcon()); menuItem.setActionCommand(MainMenuAction.ACCOUNT_MANAGER.name()); menuItem.addActionListener(program); menu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().profiles()); menuItem.setIcon(Images.DIALOG_PROFILES.getIcon()); menuItem.setActionCommand(MainMenuAction.PROFILES.name()); menuItem.addActionListener(program); menu.add(menuItem); menu.addSeparator(); menuItem = new JMenuItem(GuiFrame.get().options1()); menuItem.setIcon(Images.DIALOG_SETTINGS.getIcon()); menuItem.setActionCommand(MainMenuAction.OPTIONS.name()); menuItem.addActionListener(program); menu.add(menuItem); //HELP menu = new JMenu(GuiFrame.get().help()); menu.setMnemonic(KeyEvent.VK_H); this.add(menu); menuItem = new JMenuItem(GuiFrame.get().linkWiki()); menuItem.setIcon(Images.TOOL_ASSETS.getIcon()); menuItem.setActionCommand(MainMenuAction.LINK_WIKI.name()); menuItem.addActionListener(program); menu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().linkFeedbackAndHelp()); menuItem.setIcon(Images.MISC_HELP.getIcon()); menuItem.setActionCommand(MainMenuAction.LINK_FEEDBACK_AND_HELP.name()); menuItem.addActionListener(program); menu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().linkDiscord()); menuItem.setIcon(Images.MISC_DISCORD.getIcon()); menuItem.setActionCommand(MainMenuAction.LINK_DISCORD.name()); menuItem.addActionListener(program); menu.add(menuItem); menu.addSeparator(); menuItem = new JMenuItem(GuiFrame.get().readme()); menuItem.setIcon(Images.STOCKPILE_SHOPPING_LIST.getIcon()); menuItem.setActionCommand(MainMenuAction.README.name()); menuItem.addActionListener(program); menu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().credits()); menuItem.setIcon(Images.STOCKPILE_SHOPPING_LIST.getIcon()); menuItem.setActionCommand(MainMenuAction.CREDITS.name()); menuItem.addActionListener(program); menu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().license()); menuItem.setIcon(Images.STOCKPILE_SHOPPING_LIST.getIcon()); menuItem.setActionCommand(MainMenuAction.LICENSE.name()); menuItem.addActionListener(program); menu.add(menuItem); menuItem = new JMenuItem(GuiFrame.get().change()); menuItem.setIcon(Images.STOCKPILE_SHOPPING_LIST.getIcon()); menuItem.setActionCommand(MainMenuAction.CHANGELOG.name()); menuItem.addActionListener(program); menu.add(menuItem); menu.addSeparator(); menuItem = new JMenuItem(GuiFrame.get().about()); menuItem.setIcon(Images.DIALOG_ABOUT.getIcon()); menuItem.setActionCommand(MainMenuAction.ABOUT.name()); menuItem.addActionListener(program); menu.add(menuItem); //DEBUG if (CliOptions.get().isDebug()) { menu = new JMenu("Debug"); //FIXME - - > Remove for production //this.add(menu); menuItem = new JMenuItem("Update EventLists", Images.MISC_DEBUG.getIcon()); menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { program.updateEventLists(); } }); menu.add(menuItem); menuItem = new JMenuItem("Create Tracker Point", Images.MISC_DEBUG.getIcon()); menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { program.createTrackerDataPoint(); } }); menu.add(menuItem); menuItem = new JMenuItem("Throw out of memory", Images.MISC_DEBUG.getIcon()); menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { OutOfMemoryError oome = new OutOfMemoryError(); ExecutionException ee = new ExecutionException(oome); RuntimeException re = new RuntimeException(ee); throw re; } }); menu.add(menuItem); } } @Override public final JMenu add(JMenu c) { return super.add(c); } public JMenu getTableMenu() { return jTableMenu; } public void timerTicked(final boolean updatable, final boolean structure) { if (updatable) { jUpdateMenu.setIcon(Images.DIALOG_UPDATE.getIcon()); jUpdateMenu.setToolTipText(GuiFrame.get().updatable()); } else { jUpdateMenu.setIcon(Images.DIALOG_UPDATE_DISABLED.getIcon()); jUpdateMenu.setToolTipText(GuiFrame.get().not()); } if (structure) { jStructureMenu.setIcon(Images.DIALOG_UPDATE.getIcon()); jStructureMenu.setToolTipText(GuiFrame.get().updatable()); } else { jStructureMenu.setIcon(Images.DIALOG_UPDATE_DISABLED.getIcon()); jStructureMenu.setToolTipText(GuiFrame.get().not()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/frame/MainWindow.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.frame; import java.awt.*; import java.awt.event.*; import java.util.ArrayList; import java.util.List; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.basic.BasicButtonUI; import net.nikr.eve.jeveasset.CliOptions; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.TextManager; import net.nikr.eve.jeveasset.gui.shared.components.JDragTabbedPane; import net.nikr.eve.jeveasset.gui.shared.components.JDragTabbedPane.TabMoveListener; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow.LockWorkerAdaptor; import net.nikr.eve.jeveasset.gui.shared.components.JMainTab; import net.nikr.eve.jeveasset.i18n.GuiFrame; import net.nikr.eve.jeveasset.i18n.GuiShared; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MainWindow { private static final Logger LOG = LoggerFactory.getLogger(MainWindow.class); private static final String RE_OPEN_TAB = "reOpenTab"; //GUI private final MainMenu mainMenu; private final JFrame jFrame; private final JDragTabbedPane jTabbedPane; private final StatusPanel statusPanel; private final JLockWindow jLockWindow; private final Timer timer; //Data private final Program program; private final List tabs = new ArrayList<>(); private final List closed = new ArrayList<>(); public MainWindow(final Program program) { this.program = program; ListenerClass listener = new ListenerClass(); timer = new Timer(1000, listener); //Frame jFrame = new JFrame(); updateTitle(); setSizeAndLocation(Settings.get().getWindowSize(), Settings.get().getWindowLocation(), Settings.get().isWindowMaximized()); jFrame.setAlwaysOnTop(Settings.get().isWindowAlwaysOnTop()); List icons = new ArrayList<>(); icons.add(Images.TOOL_ASSETS.getImage()); icons.add(Images.MISC_ASSETS_32.getImage()); icons.add(Images.MISC_ASSETS_64.getImage()); jFrame.setIconImages(icons); jFrame.addWindowListener(listener); jFrame.addComponentListener(listener); jFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); jLockWindow = new JLockWindow(jFrame); JPanel jPanel = new JPanel(); //Global key shortcuts //Re-open closed tab //Windows/Linux jPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.CTRL_DOWN_MASK + InputEvent.SHIFT_DOWN_MASK), RE_OPEN_TAB); //Mac OSX jPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.META_DOWN_MASK + InputEvent.SHIFT_DOWN_MASK), RE_OPEN_TAB); jPanel.getActionMap().put(RE_OPEN_TAB, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (closed.isEmpty()) { return; } addTab(closed.get(closed.size() - 1), true); } }); GroupLayout layout = new GroupLayout(jPanel); jPanel.setLayout(layout); layout.setAutoCreateGaps(false); layout.setAutoCreateContainerGaps(false); jFrame.getContentPane().add(jPanel); mainMenu = new MainMenu(program); jFrame.setJMenuBar(mainMenu); jTabbedPane = new JDragTabbedPane(); jTabbedPane.addChangeListener(listener); jTabbedPane.addMouseListener(new MouseAdapter() { @Override public void mousePressed(final MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON2) { int index = jTabbedPane.indexAtLocation(e.getX(), e.getY()); if (index < 0) { return; } JMainTab jMainTab = tabs.get(index); if (isCloseable(jMainTab)) { removeTab(jMainTab); } } } }); jTabbedPane.addTabMoveListeners(listener); jTabbedPane.addDragLock(0); statusPanel = new StatusPanel(program); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(jTabbedPane, 0, 0, Short.MAX_VALUE) .addComponent(statusPanel.getPanel(), 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jTabbedPane, 0, 0, Short.MAX_VALUE) .addComponent(statusPanel.getPanel(), Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } public final void updateTitle() { jFrame.setTitle(GuiFrame.get().windowTitle( Program.PROGRAM_NAME, Program.PROGRAM_VERSION, CliOptions.get().isPortable() ? 1 : 0, program.getProfileManager().getProfiles().size(), program.getProfileManager().getActiveProfile().getName() )); } public void addTab(final MainTabInit mainTabInit) { if (jFrame.isVisible()) { jLockWindow.show(GuiShared.get().updating(), new LockWorkerAdaptor() { @Override public void task() { } @Override public void hidden() { } @Override public void gui() { addTab(mainTabInit.init(), true, false); } }); } else { addTab(mainTabInit.init(), true, false); } } public void addTab(final JMainTab jMainTab) { addTab(jMainTab, true, true); } public void addTab(final JMainTab jMainTab, final boolean focus) { addTab(jMainTab, focus, true); } public void addTab(final JMainTab jMainTab, final boolean focus, boolean lockWindow) { if (!tabs.contains(jMainTab)) { LOG.info("Opening tab: " + jMainTab.getTitle()); TextManager.installAll(jMainTab.getPanel()); jMainTab.loadCurrentSorting(); jMainTab.beforeUpdateData(); jMainTab.updateData(); jMainTab.afterUpdateData(); if (lockWindow && jFrame.isVisible()) { jLockWindow.show(GuiShared.get().updating(), new LockWorkerAdaptor() { @Override public void task() { jMainTab.updateCache(); } }); } else { jMainTab.updateCache(); } tabs.add(jMainTab); closed.remove(jMainTab); jTabbedPane.addTab(jMainTab.getTitle(), jMainTab.getIcon(), jMainTab.getPanel()); jTabbedPane.setTabComponentAt(jTabbedPane.getTabCount() - 1, new TabCloseButton(jMainTab)); if (Settings.get().isSaveToolsOnExit() && !Settings.get().getShowTools().contains(jMainTab.getTitle())) { Settings.get().getShowTools().add(jMainTab.getTitle()); program.saveSettings("Showing Tool"); } } if (focus) { LOG.info("Focusing tab: " + jMainTab.getTitle()); jTabbedPane.setSelectedComponent(jMainTab.getPanel()); } } public boolean isOpen(final JMainTab jMainTab) { return tabs.contains(jMainTab); } public JMainTab getSelectedTab() { return tabs.get(jTabbedPane.getSelectedIndex()); } private void removeTab(final JMainTab jMainTab) { LOG.info("Closing tab: " + jMainTab.getTitle()); int index = tabs.indexOf(jMainTab); jTabbedPane.removeTabAt(index); tabs.remove(index); closed.add(jMainTab); jMainTab.clearData(); if (Settings.get().isSaveToolsOnExit()) { boolean removed = Settings.get().getShowTools().remove(jMainTab.getTitle()); if (removed) { program.saveSettings("Hiding Tool"); } } } public List getTabs() { return tabs; } public MainMenu getMenu() { return mainMenu; } public void show() { jFrame.setVisible(true); } public final void setSizeAndLocation(final Dimension windowSize, final Point windowLocation, final boolean windowMaximized) { Rectangle screen = null; for (GraphicsDevice screenDevices :GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) { Rectangle bounds = screenDevices.getDefaultConfiguration().getBounds(); if (windowLocation.x >= bounds.x && windowLocation.x <= bounds.x + bounds.width && windowLocation.y >= bounds.y && windowLocation.y <= bounds.y + bounds.height) { screen = bounds; break; } } if (screen == null) { Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); screen = new Rectangle(0, 0, d.width, d.height); } //Fix size if (windowSize.width > screen.width) { windowSize.width = screen.width; } if (windowSize.height > screen.height) { windowSize.height = screen.height; } if (windowSize.width < 200) { windowSize.width = 200; } if (windowSize.height < 200) { windowSize.height = 200; } //Fix location if (windowLocation.x + windowSize.width > screen.x + screen.width) { windowLocation.x = screen.x + screen.width - windowSize.width; } if (windowLocation.y + windowSize.height > screen.y + screen.height) { windowLocation.y = screen.y + screen.height - windowSize.height; } if (windowLocation.x < screen.x) { windowLocation.x = screen.x; } if (windowLocation.y < screen.y) { windowLocation.y = screen.y; } //Set location, size, and state jFrame.setLocation(windowLocation); jFrame.setSize(windowSize); if (windowMaximized) { jFrame.setExtendedState(JFrame.MAXIMIZED_BOTH); } else { jFrame.setExtendedState(JFrame.NORMAL); } } public JFrame getFrame() { return jFrame; } public StatusPanel getStatusPanel() { return statusPanel; } public void updateSettings() { if (Settings.get().isWindowAutoSave()) { Settings.get().setWindowMaximized(isMaximized()); if (!isMaximized()) { Settings.get().setWindowSize(jFrame.getSize()); Settings.get().setWindowLocation(jFrame.getLocation()); } } } public void updateTabCloseButtons() { for (int i = 0; i < jTabbedPane.getTabCount(); i++) { Component component = jTabbedPane.getTabComponentAt(i); if (component instanceof TabCloseButton) { TabCloseButton tabCloseButton = (TabCloseButton) component; tabCloseButton.updateCloseButton(); } } } private boolean isMaximized() { return ((jFrame.getExtendedState() & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH); } private class ListenerClass implements WindowListener, ChangeListener, ComponentListener, ActionListener, TabMoveListener { private short move = 0; private short resize = 0; @Override public void windowOpened(final WindowEvent e) { } @Override public void windowClosing(final WindowEvent e) { program.exit(); } @Override public void windowClosed(final WindowEvent e) { } @Override public void windowIconified(final WindowEvent e) { } @Override public void windowDeiconified(final WindowEvent e) { } @Override public void windowActivated(final WindowEvent e) { } @Override public void windowDeactivated(final WindowEvent e) { } @Override public void stateChanged(final ChangeEvent e) { program.tabChanged(); } @Override public void componentResized(ComponentEvent e) { if (Settings.get().isWindowAutoSave() && !isMaximized()) { if (move > 1) { //Ignore the two first updates program.saveSettings("Window Resized"); } else { move++; } } } @Override public void componentMoved(ComponentEvent e) { if (Settings.get().isWindowAutoSave()) { if (resize > 1) { //Ignore the two first updates timer.stop(); timer.start(); } else { resize++; } } } @Override public void componentShown(ComponentEvent e) { } @Override public void componentHidden(ComponentEvent e) { } @Override public void actionPerformed(ActionEvent e) { timer.stop(); if (isMaximized()) { program.saveSettings("Window Maximized"); } else { program.saveSettings("Window Moved"); } } @Override public void tabMoved(int from, int to) { LOG.info("Moving tab: " + tabs.get(from).getTitle() + " from: " + from + " to: " + to); JMainTab jMainTab = tabs.remove(from); tabs.add(to, jMainTab); if (Settings.get().isSaveToolsOnExit()) { Settings.get().getShowTools().remove(jMainTab.getTitle()); Settings.get().getShowTools().add(to, jMainTab.getTitle()); program.saveSettings("Moved Tool"); } } } private static boolean isCloseable(final JMainTab jMainTab) { return jMainTab.isCloseable() && !Settings.get().isToolsLocked(); } private class TabCloseButton extends JPanel { private final JButton jClose; private final JMainTab jMainTab; public TabCloseButton(final JMainTab jMainTab) { super(new FlowLayout(FlowLayout.LEFT, 0, 0)); this.jMainTab = jMainTab; this.setOpaque(false); JLabel jTitle = new JLabel(jMainTab.getTitle(), jMainTab.getIcon(), SwingConstants.LEFT); add(jTitle); jClose = new JButton(); jClose.setToolTipText(GuiFrame.get().close()); jClose.setIcon(Images.TAB_CLOSE.getIcon()); jClose.setRolloverIcon(Images.TAB_CLOSE_ACTIVE.getIcon()); jClose.setUI(new BasicButtonUI()); jClose.setPreferredSize(new Dimension(16, 16)); jClose.setOpaque(false); jClose.setContentAreaFilled(false); jClose.setFocusable(false); jClose.setBorderPainted(false); jClose.setRolloverEnabled(true); jClose.addMouseListener(new MouseAdapter() { @Override public void mousePressed(final MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON2) { if (isCloseable(jMainTab)) { removeTab(jMainTab); } } } }); jClose.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { if (isCloseable(jMainTab)) { removeTab(jMainTab); } } }); if (jMainTab.isCloseable()) { add(jClose); } jClose.setEnabled(isCloseable(jMainTab)); } private void updateCloseButton() { jClose.setEnabled(isCloseable(jMainTab)); } } @FunctionalInterface public static interface MainTabInit { public JMainTab init(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/frame/StatusPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.frame; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.GroupLayout; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JProgressBar; import javax.swing.Timer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.ColorUtil; import net.nikr.eve.jeveasset.gui.shared.CopyHandler; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JGroupLayoutPanel; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.AutoNumberFormat; import net.nikr.eve.jeveasset.i18n.DialoguesStructure; import net.nikr.eve.jeveasset.i18n.GuiFrame; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.i18n.TabsPriceHistory; import net.nikr.eve.jeveasset.i18n.TabsOrders; public class StatusPanel extends JGroupLayoutPanel { //GUI private final JButton jUpdate; private final JLabel jEveTime; private final JLabel jApiUpdate; private final JFixedToolBar jToolBar; private final Timer eveTimer; private final Timer updateTimer; private final List progressStatus = Collections.synchronizedList(new ArrayList<>()); private final List programStatus = new ArrayList<>(); public StatusPanel(final Program program) { super(program); ListenerClass listener = new ListenerClass(); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(false); jToolBar = new JFixedToolBar(); boolean update = canUpdate(); jUpdate = new JButton(GuiFrame.get().programUpdateText(), Images.MISC_UPDATE.getIcon()); jUpdate.setToolTipText(GuiFrame.get().programUpdateTip()); jUpdate.setVisible(update); jUpdate.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { program.update(); } }); updateTimer = new Timer(3600000, new ActionListener() { //Check for updates once an hour @Override public void actionPerformed(ActionEvent e) { boolean update = canUpdate(); jUpdate.setVisible(update); if (update) { doLayout(); updateTimer.stop(); //Update found, no reason to keep checking for updates } } }); if (!update) { //Update found, no reason to keep checking for updates updateTimer.start(); } jApiUpdate = createIcon(Images.DIALOG_UPDATE.getIcon(), GuiFrame.get().updatable()); programStatus.add(jApiUpdate); jEveTime = createLabel(GuiFrame.get().eve(), Images.MISC_EVE.getIcon(), null); programStatus.add(jEveTime); eveTimer = new Timer(1000, listener); eveTimer.start(); layout.setHorizontalGroup( layout.createSequentialGroup() .addComponent(jToolBar, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ); } public Progress addProgress(UpdateType updateType, ProgressControl progressShow) { Progress progress = new Progress(updateType, progressShow); progressStatus.add(progress); return progress; } public boolean updateing(UpdateType updateType) { synchronized (progressStatus) { for (Progress progress : progressStatus) { if (progress.getTaskType() == updateType) { return true; } } } return false; } public int updateInProgress() { return progressStatus.size(); } public void cancelUpdates() { synchronized (progressStatus) { for (Progress progress : progressStatus) { progress.cancel(); } } } public void setPauseUpdates(boolean pause) { synchronized (progressStatus) { for (Progress progress : progressStatus) { progress.setPause(pause); } } } public void removeProgress(Progress progress) { progressStatus.remove(progress); doLayout(); } public void tabChanged() { doLayout(); } private boolean canUpdate() { return (program.checkProgramUpdate() || program.checkDataUpdate()) && !Program.isDevBuild(); } private void doLayout() { jToolBar.removeAll(); addSpace(5); if (jUpdate.isVisible()) { jToolBar.add(jUpdate); } synchronized (progressStatus) { for (Progress progress : progressStatus) { if (progress.isVisible()) { jToolBar.add(progress.getProgress()); addSpace(10); } } } for (JLabel jLabel : programStatus) { jToolBar.add(jLabel); if (jLabel instanceof JStatusLabel) { addSpace(6); } else { addSpace(8); } } for (JLabel jLabel : program.getMainWindow().getSelectedTab().getStatusbarLabels()) { jToolBar.add(jLabel); if (jLabel instanceof JStatusLabel) { addSpace(6); } else { addSpace(8); } } addSpace(10); this.getPanel().updateUI(); } public void timerTicked(final boolean updatable) { if (updatable) { jApiUpdate.setIcon(Images.DIALOG_UPDATE.getIcon()); jApiUpdate.setToolTipText(GuiFrame.get().updatable()); } else { jApiUpdate.setIcon(Images.DIALOG_UPDATE_DISABLED.getIcon()); jApiUpdate.setToolTipText(GuiFrame.get().not()); } } public static JLabel createIcon(final Icon icon, final String toolTip) { JLabel jLabel = new JLabel(); jLabel.setIcon(icon); jLabel.setHorizontalAlignment(JLabel.CENTER); jLabel.setToolTipText(toolTip); return jLabel; } public static JStatusLabel createLabel(final String toolTip, final Icon icon, final AutoNumberFormat format) { return new JStatusLabel(toolTip, icon, format); } private void addSpace(final int width) { JLabel jSpace = new JLabel(); jSpace.setMinimumSize(new Dimension(width, 25)); jSpace.setPreferredSize(new Dimension(width, 25)); jSpace.setMaximumSize(new Dimension(width, 25)); jToolBar.add(jSpace); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(ActionEvent e) { jEveTime.setText(Formatter.eveTime(Settings.getNow())); } } public class Progress { private final UpdateType updateType; private final String text; private final ProgressControl progressControl; private final JProgressBar jProgress; private final long id = System.currentTimeMillis(); private boolean done = false; public Progress(UpdateType updateType, ProgressControl progressShow) { this.updateType = updateType; this.progressControl = progressShow; switch (updateType) { case STRUCTURE: text = DialoguesStructure.get().updateTitle(); break; case PUBLIC_MARKET_ORDERS: text = TabsOrders.get().updateTitle(); break; case PRICE_HISTORY: text = TabsPriceHistory.get().updateTitle(); break; case TOOLS: text = GuiShared.get().toolsUpdateTitle(); break; default: text = ""; } jProgress = new JProgressBar(0, 100); Dimension size = new Dimension(Program.getButtonsWidth() * 2, Program.getButtonsHeight()); jProgress.setMinimumSize(size); jProgress.setPreferredSize(size); jProgress.setMaximumSize(size); jProgress.setVisible(false); jProgress.setStringPainted(true); if (progressShow.isAuto()) { jProgress.setString(text); } else { jProgress.setString(GuiFrame.get().clickToShow(text)); jProgress.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { progressShow.show(); } }); } } public void setDone(boolean done) { this.done = done; if (done) { jProgress.setString(GuiFrame.get().clickToApply(text)); jProgress.setValue(100); } } public boolean isDone() { return done; } public boolean isVisible() { return jProgress.isVisible(); } public void setVisible(boolean aFlag) { jProgress.setVisible(aFlag); doLayout(); } public void setIndeterminate(boolean newValue) { jProgress.setIndeterminate(newValue); } public void setValue(int n) { jProgress.setValue(n); } private UpdateType getTaskType() { return updateType; } private void cancel() { progressControl.cancel(); } public void setPause(boolean pause) { progressControl.setPause(pause); } private JProgressBar getProgress() { return jProgress; } @Override public int hashCode() { int hash = 7; hash = 41 * hash + (int) (this.id ^ (this.id >>> 32)); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Progress other = (Progress) obj; if (this.id != other.id) { return false; } return true; } } public static class JStatusLabel extends JLabel { private final AutoNumberFormat format; private String text = null; private Number number = null; public JStatusLabel(final String toolTip, final Icon icon, AutoNumberFormat format) { this.format = format; init(toolTip, icon); } private void init(final String toolTip, final Icon icon) { setIcon(icon); if (ColorUtil.isBrightColor(getBackground())) { //Light background color setForeground(getBackground().darker().darker().darker()); } else { //Dark background color setForeground(getBackground().brighter().brighter()); } setIconTextGap(3); setToolTipText(GuiShared.get().clickToCopyWrap(toolTip)); setHorizontalAlignment(JLabel.LEFT); addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1) { if (number != null) { CopyHandler.toClipboard(Formatter.copyFormat(number)); } else { CopyHandler.toClipboard(text); } final Icon restore; if (icon == null) { restore = getIcon(); } else { restore = icon; } JStatusLabel.super.setText(GuiShared.get().selectionCopiedToClipboard()); setIcon(Images.EDIT_COPY.getIcon()); final Timer timer = new Timer(JMenuInfo.COPY_DELAY, null); timer.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateText(); setIcon(restore); timer.stop(); } }); timer.start(); } } }); } @Override public void setText(String text) { this.text = text; this.number = null; updateText(); } public void setNumber(Number number) { this.text = null; this.number = number; updateText(); } public void setNumber(String text, double number) { this.text = text; this.number = number; updateText(); } public void updateText() { if (text != null && number != null && format != null) { super.setText(text + JMenuInfo.format(number, format)); } else if (text != null) { super.setText(text); } else if (number != null && format != null) { super.setText(JMenuInfo.format(number, format)); } else { super.setText(""); } } } public static interface ProgressControl { public boolean isAuto(); public void show(); public void cancel(); public void setPause(boolean pause); } public static enum UpdateType { STRUCTURE, PUBLIC_MARKET_ORDERS, PRICE_HISTORY, TOOLS } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/images/Images.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.images; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.Icon; import javax.swing.ImageIcon; import net.nikr.eve.jeveasset.SplashUpdater; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.io.online.EveImageGetter; import net.nikr.eve.jeveasset.io.online.EveImageGetter.ImageCategory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public enum Images { ASSETS_AVERAGE ("assets_average.png"), ASSETS_VOLUME ("assets_volume.png"), JOBS_INVENTION_SUCCESS ("jobs_invention_success.png"), ORDERS_SELL ("orders_sell.png"), ORDERS_SOLD ("orders_sold.png"), ORDERS_BUY ("orders_buy.png"), ORDERS_BOUGHT ("orders_bought.png"), ORDERS_ESCROW ("orders_escrow.png"), ORDERS_TO_COVER ("orders_to_cover.png"), DIALOG_UPDATE ("dialog_update.png"), DIALOG_UPDATE_DISABLED ("dialog_update_disabled.png"), DIALOG_ACCOUNTS ("dialog_accounts.png"), DIALOG_PROFILES ("dialog_profiles.png"), DIALOG_SETTINGS ("dialog_settings.png"), DIALOG_ABOUT ("dialog_about.png"), DIALOG_CSV_EXPORT ("dialog_csv_export.png"), EDIT_COPY ("edit_copy.png"), EDIT_CUT ("edit_cut.png"), EDIT_PASTE ("edit_paste.png"), EDIT_EDIT ("edit_edit.png"), EDIT_RENAME ("edit_rename.png"), EDIT_DATE ("edit_date.png"), EDIT_DELETE ("edit_delete.png"), EDIT_DELETE_WHITE ("edit_delete_white.png"), EDIT_ADD ("edit_add.png"), EDIT_ADD_WHITE ("edit_add_white.png"), EDIT_SET ("edit_set.png"), EDIT_IMPORT ("edit_import.png"), EDIT_EDIT_WHITE ("edit_edit_white.png"), EDIT_EDIT_BACKGROUND ("edit_edit_background.png"), EDIT_REDO ("edit_redo.png"), EDIT_UNDO ("edit_undo.png"), EDIT_SHOW ("edit_show.png"), FILTER_CLEAR ("filter_clear.png"), FILTER_SAVE ("filter_save.png"), FILTER_LOAD ("filter_load.png"), FILTER_LOAD_DEFAULT ("filter_load_default.png"), FILTER_NOT_CONTAIN ("filter_not_contain.png"), FILTER_CONTAIN ("filter_contain.png"), FILTER_NOT_EQUAL ("filter_not_equal.png"), FILTER_REGEX ("filter_regex.png"), FILTER_EQUAL ("filter_equal.png"), FILTER_EQUAL_DATE ("filter_equal_date.png"), FILTER_NOT_EQUAL_DATE ("filter_not_equal_date.png"), FILTER_GREATER_THAN ("filter_greater_than.png"), FILTER_LAST_DAYS ("filter_last_days.png"), FILTER_NEXT_DAYS ("filter_next_days.png"), FILTER_LAST_HOURS ("filter_last_hours.png"), FILTER_NEXT_HOURS ("filter_next_hours.png"), FILTER_LESS_THAN ("filter_less_than.png"), FILTER_AFTER ("filter_after.png"), FILTER_BEFORE ("filter_before.png"), FILTER_CONTAIN_COLUMN("filter_contain_column.png"), FILTER_EQUAL_COLUMN ("filter_equal_column.png"), FILTER_NOT_CONTAIN_COLUMN ("filter_not_contain_column.png"), FILTER_NOT_EQUAL_COLUMN ("filter_not_equal_column.png"), FILTER_GREATER_THAN_COLUMN ("filter_greater_than_column.png"), FILTER_LESS_THAN_COLUMN ("filter_less_than_column.png"), FILTER_AFTER_COLUMN ("filter_after_column.png"), FILTER_BEFORE_COLUMN ("filter_before_column.png"), LINK_EVE_MARKETDATA ("link_eve_marketdata.png"), LINK_EVEINFO ("link_eveinfo.png"), LINK_DOTLAN_EVEMAPS ("link_dotlan_evemaps.png"), LINK_LOOKUP ("link_lookup.png"), LINK_CHRUKER ("link_chruker.png"), LINK_EVE_TYCOON ("link_eve_tycoon.png"), LINK_JANICE ("link_janice.png"), LINK_JANICE_32 ("link_janice_32.png"), LINK_FUZZWORK ("link_fuzzwork.png"), LINK_ZKILLBOARD ("link_zkillboard.png"), LINK_ZKILLBOARD_32 ("link_zkillboard_32.png"), LINK_ADAM4EVE ("link_adam4eve.png"), LINK_EVE_COOKBOOK ("link_eve_cookbook.png"), LINK_EVEMISSIONEER ("link_evemissioneer.png"), LINK_EVE_REF ("link_eve_ref.png"), LINK_EVE_MARKET_BROWSER ("link_eve_market_browser.png"), LINK_JITA_SPACE ("link_jita_space.png"), LINK_EVECONOMY ("link_eveconomy.png"), LINK_QUANTUM_ANOMALY ("link_quantum_anomaly.png"), LOC_GROUPS ("loc_groups.png"), LOC_PIN_COMMAND ("loc_pin_command.png"), LOC_PIN_EXTRACTOR ("loc_pin_extractor.png"), LOC_PIN_PROCESSOR ("loc_pin_processor.png"), LOC_PIN_SPACEPORT ("loc_pin_spaceport.png"), LOC_PIN_STORAGE ("loc_pin_storage.png"), LOC_PLANET ("loc_planet.png"), LOC_STATION ("loc_station.png"), LOC_SYSTEM ("loc_system.png"), LOC_CONSTELLATION ("loc_constellation.png"), LOC_REGION ("loc_region.png"), LOC_CONTAINER ("loc_container.png"), LOC_CONTAINER_WHITE ("loc_container_white.png"), LOC_LOCATIONS ("loc_locations.png"), LOC_FLAG ("loc_flag.png"), LOC_OWNER ("loc_owner.png"), LOC_INCLUDE ("loc_include.png"), LOC_HANGAR_ITEMS ("loc_hangar_items.png"), LOC_HANGAR_SHIPS ("loc_hangar_ships.png"), LOC_DELIVERIES ("loc_deliveries.png"), LOC_OFFICE ("loc_office.png"), LOC_DIVISION ("loc_division.png"), LOC_INDUSTRY ("loc_industry.png"), LOC_MARKET ("loc_market.png"), LOC_CONTRACTS ("loc_contracts.png"), LOC_SAFTY ("loc_safty.png"), LOC_SHIP ("loc_ship.png"), LOC_CLONEBAY ("loc_clonebay.png"), INCLUDE_ASSETS_SELECTED ("include_assets_selected.png"), INCLUDE_ASSETS ("include_assets.png"), INCLUDE_JOBS_SELECTED ("include_jobs_selected.png"), INCLUDE_JOBS ("include_jobs.png"), INCLUDE_CONTRACTS_SELECTED ("include_contracts_selected.png"), INCLUDE_CONTRACTS ("include_contracts.png"), INCLUDE_ORDERS_SELECTED ("include_orders_selected.png"), INCLUDE_ORDERS ("include_orders.png"), INCLUDE_PACKAGED ("include_packaged.png"), INCLUDE_ADD_FILTER ("include_add_filter.png"), MISC_EVE ("misc_eve.png"), MISC_ESI ("misc_esi.png"), MISC_EXIT ("misc_exit.png"), MISC_HELP ("misc_help.png"), MISC_EXPANDED ("misc_expanded.png"), MISC_COLLAPSED ("misc_collapsed.png"), MISC_EXPANDED_WHITE ("misc_expanded_white.png"), MISC_COLLAPSED_WHITE ("misc_collapsed_white.png"), MISC_COLLAPSE ("misc_collapse.png"), MISC_AND ("misc_and.png"), MISC_ASSETS_32 ("misc_assets_32.png"), MISC_ASSETS_64 ("misc_assets_64.png"), MISC_DEBUG ("misc_debug.png"), MISC_UPDATE ("misc_update.png"), MISC_RUNS ("misc_runs.png"), MISC_BLUEPRINT ("misc_blueprint.png"), MISC_BPC ("misc_bpc.png"), MISC_BPO ("misc_bpo.png"), MISC_COPYING ("misc_copying.png"), MISC_INVENTION ("misc_invention.png"), MISC_MANUFACTURING ("misc_manufacturing.png"), MISC_SUM ("misc_sum.png"), MISC_FORMULA ("misc_formula.png"), MISC_REACTION ("misc_reaction.png"), MISC_CONTRACTS ("misc_contracts.png"), MISC_CONTRACTS_CORP ("misc_contracts_corp.png"), MISC_MARKET_ORDERS ("misc_market_orders.png"), MISC_AVG ("misc_avg.png"), MISC_COUNT ("misc_count.png"), MISC_INFO ("misc_info.png"), MISC_MAX ("misc_max.png"), MISC_MIN ("misc_min.png"), MISC_STATUS ("misc_status.png"), MISC_SOUNDS ("misc_sounds.png"), MISC_PLAY ("misc_play.png"), MISC_STOP ("misc_stop.png"), MISC_PARTNER ("misc_partner.png"), MISC_PARTYPARROT ("misc_partyparrot.gif"), MISC_MATERIALS ("misc_materials.png"), MISC_ORE ("misc_ore.png"), MISC_COMMODITY ("misc_commodity.png"), MISC_PI ("misc_pi.png"), MISC_XML ("misc_xml.png"), MISC_DATE ("misc_date.png"), MISC_NUMBER ("misc_number.png"), MISC_DISCORD ("misc_discord.png"), MISC_MISC ("misc_misc.png"), MISC_OWNERS ("misc_owners.png"), SETTINGS_TOOLS ("settings_tools.png"), SETTINGS_PRICE_DATA ("settings_price_data.png"), SETTINGS_USER_PRICE ("settings_user_price.png"), SETTINGS_USER_NAME ("settings_user_name.png"), SETTINGS_REPROCESSING ("settings_reprocessing.png"), SETTINGS_PROXY ("settings_proxy.png"), SETTINGS_WINDOW ("settings_window.png"), SETTINGS_COLORS ("settings_colors.png"), SETTINGS_COLOR_PICKER ("settings_color_picker.png"), SETTINGS_COLOR_CHECK_BLACK ("settings_color_check_black.png"), SETTINGS_COLOR_CHECK_BLACK_ALPHA ("settings_color_check_black_alpha.png"), SETTINGS_COLOR_CHECK_WHITE ("settings_color_check_white.png"), SETTINGS_COLOR_CHECK_WHITE_ALPHA ("settings_color_check_white_alpha.png"), SETTINGS_COLOR_FOREGROUND ("settings_color_foreground.png"), SETTINGS_COLOR_BACKGROUND ("settings_color_background.png"), SETTINGS_MANUFACTURING ("settings_manufacturing.png"), SLOTS_CONTRACTS ("slots_contracts.png"), SLOTS_CONTRACTS_CORP ("slots_contracts_corp.png"), SLOTS_MANUFACTURING ("slots_manufacturing.png"), SLOTS_MARKET_ORDERS ("slots_market_orders.png"), SLOTS_REACTIONS ("slots_reactions.png"), SLOTS_RESEARCH ("slots_research.png"), STOCKPILE_SHOPPING_LIST ("stockpile_shopping_list.png"), TAB_CLOSE ("tab_close.png"), TAB_CLOSE_ACTIVE ("tab_close_active.png"), TAG_GRAY ("tag_gray.png"), TAG_TICK ("tag_tick.png"), TABLE_COLUMN_RESIZE ("table_column_resize.png"), TABLE_COLUMN_SHOW ("table_column_show.png"), TOOL_ASSETS ("tool_assets.png"), TOOL_OVERVIEW ("tool_overview.png"), TOOL_MARKET_ORDERS ("tool_market_orders.png"), TOOL_VALUES ("tool_values.png"), TOOL_VALUE_TABLE ("tool_value_table.png"), TOOL_INDUSTRY_JOBS ("tool_industry_jobs.png"), TOOL_SLOTS ("tool_slots.png"), TOOL_ROUTING ("tool_routing.png"), TOOL_MATERIALS ("tool_materials.png"), TOOL_SHIP_LOADOUTS ("tool_ship_loadouts.png"), TOOL_STOCKPILE ("tool_stockpile.png"), TOOL_ITEMS ("tool_items.png"), TOOL_TRACKER ("tool_tracker.png"), TOOL_REPROCESSED ("tool_reprocessed.png"), TOOL_CONTRACTS ("tool_contracts.png"), TOOL_TRANSACTION ("tool_transaction.png"), TOOL_JOURNAL ("tool_journal.png"), TOOL_TREE ("tool_tree.png"), TOOL_PRICE_HISTORY ("tool_price_history.png"), TOOL_SKILLS ("tool_skills.png"), TOOL_MINING ("tool_mining.png"), TOOL_MINING_LOG ("tool_mining_log.png"), TOOL_MINING_GRAPH ("tool_mining_graph.png"), TOOL_EXTRACTIONS ("tool_extractions.png"), TOOL_PRICE_CHANGE ("tool_price_change.png"), TOOL_LOYALTY_POINTS ("tool_loyalty_points.png"), TOOL_NPC_STANDING ("tool_npc_standing.png"), TOOL_AGENTS ("tool_agents.png"), UPDATE_NOT_STARTED ("update_not_started.png"), UPDATE_WORKING ("update_working.png"), UPDATE_CANCELLED ("update_cancelled.png"), UPDATE_DONE_OK ("update_done_ok.png"), UPDATE_DONE_INFO ("update_done_info.png"), UPDATE_DONE_SOME ("update_done_some.png"), UPDATE_DONE_ERROR ("update_done_error.png"); private static final Logger LOG = LoggerFactory.getLogger(Images.class); private final String filename; private BufferedImage image = null; private Icon icon; Images(final String filename) { this.filename = filename; } public Icon getIcon() { load(); return icon; } public Image getImage() { load(); return image; } public String getFilename() { return filename; } private boolean load() { if (image == null) { image = getBufferedImage(filename); icon = new ImageIcon(image); } return (image != null); } public static boolean preload() { int count = 0; boolean ok = true; for (Images i : Images.values()) { if (!i.load()) { ok = false; } count++; SplashUpdater.setSubProgress((int) (count * 100.0 / Images.values().length)); } SplashUpdater.setSubProgress(100); return ok; } public static BufferedImage getBufferedImage(final String s) { try { java.net.URL imgURL = Images.class.getResource(s); if (imgURL != null) { return ImageIO.read(imgURL); } else { LOG.warn("image: " + s + " not found (URL == null)"); } } catch (IOException ex) { LOG.warn("image: " + s + " not found (IOException)"); } return null; } public static BufferedImage getBufferedImage(int corporationID, ImageCategory imageCategory) { return EveImageGetter.getBufferedImage(corporationID, imageCategory); } public static ImageIcon getIcon(int corporationID, ImageCategory imageCategory) { BufferedImage bufferedImage = getBufferedImage(corporationID, imageCategory); if (bufferedImage != null) { bufferedImage = setBackground(bufferedImage, Color.BLACK); return new ImageIcon(bufferedImage); } return null; } public static BufferedImage getBufferedImage(MyNpcStanding npcStanding) { return EveImageGetter.getBufferedImage(npcStanding); } public static ImageIcon getIcon(MyNpcStanding npcStanding) { BufferedImage bufferedImage = getBufferedImage(npcStanding); if (bufferedImage != null) { bufferedImage = setBackground(bufferedImage, Color.BLACK); return new ImageIcon(bufferedImage); } return null; } public static BufferedImage getBufferedImage(MyLoyaltyPoints loyaltyPoints) { return EveImageGetter.getBufferedImage(loyaltyPoints); } public static ImageIcon getIcon(MyLoyaltyPoints loyaltyPoints) { BufferedImage bufferedImage = getBufferedImage(loyaltyPoints); if (bufferedImage != null) { bufferedImage = setBackground(bufferedImage, Color.BLACK); return new ImageIcon(bufferedImage); } return null; } private static BufferedImage setBackground(BufferedImage input, Color color) { BufferedImage output = new BufferedImage(input.getWidth(), input.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D g2d = output.createGraphics(); g2d.setBackground(color); g2d.clearRect(0, 0, input.getWidth(), input.getHeight()); g2d.drawImage(input, 0, 0, null); g2d.dispose(); return output; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/ColorIcon.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import javax.swing.Icon; public class ColorIcon implements Icon { private final Color color; public ColorIcon(Color color) { this.color = color; } @Override public void paintIcon(Component c, Graphics g, int x, int y) { Graphics2D g2d = (Graphics2D) g; //Render settings //g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //Border g2d.setColor(Color.BLACK); g2d.fillOval(x + 2, y + 2, getIconWidth() - 4, getIconHeight() - 4); //Background g2d.setColor(color); g2d.fillOval(x + 3, y + 3, getIconWidth() - 6, getIconHeight() - 6); } @Override public int getIconWidth() { return 16; } @Override public int getIconHeight() { return 16; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/ColorUtil.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import java.awt.Color; public class ColorUtil { private ColorUtil() { } public static double luminance(Color color) { return (0.299 * color.getRed() + 0.587 * color.getGreen() + 0.114 * color.getBlue()) / 255; } public static boolean isBrightColor(Color color) { return luminance(color) > 0.5; } public static Color brighter(Color c, double factor) { int r = c.getRed(); int g = c.getGreen(); int b = c.getBlue(); if (factor > 1) { factor = 1; } else if (factor < 0) { factor = 0; } /* From 2D group: * 1. black.brighter() should return grey * 2. applying brighter to blue will always return blue, brighter * 3. non pure color (non zero rgb) will eventually return white */ int i = (int) (1.0 / (1.0 - factor)); if (r == 0 && g == 0 && b == 0) { return new Color(i, i, i); } if (r > 0 && r < i) { r = i; } if (g > 0 && g < i) { g = i; } if (b > 0 && b < i) { b = i; } return new Color( Math.min((int) (r / factor), 255), Math.min((int) (g / factor), 255), Math.min((int) (b / factor), 255)); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/CopyHandler.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import ca.odell.glazedlists.SeparatorList; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.io.IOException; import java.util.Date; import javax.swing.AbstractAction; import javax.swing.AbstractButton; import javax.swing.JTable; import javax.swing.text.JTextComponent; import net.nikr.eve.jeveasset.gui.shared.table.containers.HierarchyColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.NumberValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CopyHandler { private static final Logger LOG = LoggerFactory.getLogger(CopyHandler.class); public static void installCopyAction(AbstractButton abstractButton, JTable jTable) { abstractButton.addActionListener(new ListenerClass(jTable)); } /** * Install default copy format * @param jTable */ public static void installCopyFormatter(JTable jTable) { ListenerClass listenerClass = new ListenerClass(jTable); //jTable.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ctrl C"), "copy"); jTable.getActionMap().put("copy", listenerClass); jTable.getActionMap().put("cut", listenerClass); } public static void toClipboard(final String text) { toClipboard(text, 0); } private static void toClipboard(final String text, int retries) { if (text == null) { return; } if (text.length() == 0) { return; } Toolkit toolkit = Toolkit.getDefaultToolkit(); StringSelection selection = new StringSelection(text); Clipboard clipboard = toolkit.getSystemClipboard(); try { clipboard.setContents(selection, null); } catch (IllegalStateException ex) { if (retries < 3) { //Retry 3 times retries++; LOG.info("Retrying copy to clipboard (" + retries + " of 3)" ); try { Thread.sleep(100); } catch (InterruptedException ex1) { //No problem } toClipboard(text, retries); } else { LOG.error(ex.getMessage(), ex); } } } public static String fromClipboard() { Toolkit toolkit = Toolkit.getDefaultToolkit(); Clipboard clipboard = toolkit.getSystemClipboard(); Transferable transferable = clipboard.getContents(null); try { return (String) transferable.getTransferData(DataFlavor.stringFlavor); } catch (UnsupportedFlavorException ex) { return null; } catch (IOException ex) { return null; } } public static void paste(JTextComponent jText) { String s = CopyHandler.fromClipboard(); if (s == null) { return; } String text = jText.getText(); String before = text.substring(0, jText.getSelectionStart()); String after = text.substring(jText.getSelectionEnd(), text.length()); jText.setText(before + s + after); int caretPosition = before.length() + s.length(); if (caretPosition <= jText.getText().length()) { jText.setCaretPosition(before.length() + s.length()); } } public static void cut(JTextComponent jText) { String s = jText.getSelectedText(); if (s == null) { return; } if (s.length() == 0) { return; } String text = jText.getText(); String before = text.substring(0, jText.getSelectionStart()); String after = text.substring(jText.getSelectionEnd(), text.length()); jText.setText(before + after); CopyHandler.toClipboard(s); } private static void copy(JTable jTable) { //Rows int[] rows; if (jTable.getRowSelectionAllowed()) { //Selected rows rows = jTable.getSelectedRows(); } else { //All rows (if row selection is not allowed) rows = new int[jTable.getRowCount()]; for (int i = 0; i < jTable.getRowCount(); i++) { rows[i] = i; } } //Columns int[] columns; if (jTable.getColumnSelectionAllowed()) { //Selected columns columns = jTable.getSelectedColumns(); } else { //All columns (if column selection is not allowed) columns = new int[jTable.getColumnCount()]; for (int i = 0; i < jTable.getColumnCount(); i++) { columns[i] = i; } } StringBuilder tableText = new StringBuilder(); //Table text buffer String separatorText = ""; //Separator text buffer (is never added to, only set for each separator) int rowCount = 0; //used to find last row for (int row : rows) { rowCount++; //count rows StringBuilder rowText = new StringBuilder(); //Row text buffer boolean firstColumn = true; //used to find first column for (int column : columns) { //Get value Object value = jTable.getValueAt(row, column); //Handle Separator if (value instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) value; Object object = separator.first(); if (object instanceof CopySeparator) { CopySeparator copySeparator = (CopySeparator) object; separatorText = copySeparator.getCopyString(); } break; } //Add tab separator (except for first column) if (firstColumn) { firstColumn = false; } else { rowText.append("\t"); } //Add value if (value instanceof NumberValue) { value = ((NumberValue)value).getNumber(); } if (value != null) { //Ignore null if (value instanceof Number) { rowText.append(Formatter.copyFormat((Number)value)); } else if (value instanceof Date) { rowText.append(Formatter.columnDate(value)); } else if (value instanceof HierarchyColumn) { HierarchyColumn hierarchyColumn = (HierarchyColumn) value; rowText.append(hierarchyColumn.getExport()); } else { rowText.append(value.toString()); //Default } } } //Add if (rowText.length() > 0 || (!separatorText.isEmpty() && rowCount == rows.length)) { tableText.append(separatorText); //Add separator text (will be empty for normal tables) if (rowText.length() > 0 && !separatorText.isEmpty()) { //Add tab separator (if needed) tableText.append("\t"); } tableText.append(rowText.toString()); //Add row text (will be empty if only copying sinlge separator) if (rowCount != rows.length) { tableText.append("\r\n"); } //Add end line } } toClipboard(tableText.toString()); //Send it all to the clipboard } /** * SeparatorList.Separator string value implementation */ public interface CopySeparator { public String getCopyString(); } private static class ListenerClass extends AbstractAction { private final JTable jTable; public ListenerClass(JTable jTable) { this.jTable = jTable; } @Override public void actionPerformed(final ActionEvent e) { copy(jTable); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/DocumentFactory.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import java.awt.Toolkit; import java.util.regex.Pattern; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultStyledDocument; import javax.swing.text.PlainDocument; public final class DocumentFactory { public enum ValueFlag { POSITIVE_AND_NOT_ZERO { @Override public boolean match(int i) { return i > 0; } @Override public boolean match(double i) { return i > 0; } }, POSITIVE_AND_ZERO { @Override public boolean match(int i) { return i >= 0; } @Override public boolean match(double i) { return i >= 0; } }, NEGATIVE_AND_NOT_ZERO { @Override public boolean match(int i) { return i < 0; } @Override public boolean match(double i) { return i < 0; } }, NEGATIVE_AND_ZERO { @Override public boolean match(int i) { return i <= 0; } @Override public boolean match(double i) { return i <= 0; } }, ANY_NUMBER { @Override public boolean match(int i) { return true; } @Override public boolean match(double i) { return true; } }, NOT_ZERO { @Override public boolean match(int i) { return i != 0; } @Override public boolean match(double i) { return i != 0; } }; public abstract boolean match(int i); public abstract boolean match(double d); } public static IntegerPlainDocument getIntegerPlainDocument() { return new IntegerPlainDocument(ValueFlag.ANY_NUMBER); } public static IntegerPlainDocument getIntegerPlainDocument(ValueFlag flag) { return new IntegerPlainDocument(flag); } public static WordPlainDocument getWordPlainDocument() { return new WordPlainDocument(); } public static DoublePlainDocument getDoublePlainDocument() { return new DoublePlainDocument(ValueFlag.ANY_NUMBER); } public static DoublePlainDocument getDoublePlainDocument(ValueFlag flag) { return new DoublePlainDocument(flag); } public static MaxLengthPlainDocument getMaxLengthPlainDocument(final int maxLength) { return new MaxLengthPlainDocument(maxLength); } public static MaxLengthStyledDocument getMaxLengthStyledDocument(final int maxLength) { return new MaxLengthStyledDocument(maxLength); } private DocumentFactory() { } public static class IntegerPlainDocument extends PlainDocument { ValueFlag flag; public IntegerPlainDocument(ValueFlag flag) { this.flag = flag; } @Override public void insertString(final int offset, final String string, final AttributeSet attributes) throws BadLocationException { int length = getLength(); if (string == null) { return; } String newValue; if (length == 0) { newValue = string; } else { String currentContent = getText(0, length); StringBuilder currentBuffer = new StringBuilder(currentContent); currentBuffer.insert(offset, string); newValue = currentBuffer.toString(); } try { if (flag.match(Integer.parseInt(newValue))) { super.insertString(offset, string, attributes); } else { Toolkit.getDefaultToolkit().beep(); } } catch (NumberFormatException exception) { Toolkit.getDefaultToolkit().beep(); } } } public static class DoublePlainDocument extends PlainDocument { ValueFlag flag; public DoublePlainDocument(ValueFlag flag) { this.flag = flag; } @Override public void insertString(final int offset, final String string, final AttributeSet attributes) throws BadLocationException { int length = getLength(); if (string == null) { return; } String newValue; if (length == 0) { newValue = string; } else { String currentContent = getText(0, length); StringBuilder currentBuffer = new StringBuilder(currentContent); currentBuffer.insert(offset, string); newValue = currentBuffer.toString(); } try { if (flag.match(Double.parseDouble(newValue))) { super.insertString(offset, string, attributes); } else { Toolkit.getDefaultToolkit().beep(); } } catch (NumberFormatException exception) { Toolkit.getDefaultToolkit().beep(); } } } public static class WordPlainDocument extends PlainDocument { @Override public void insertString(final int offset, final String string, final AttributeSet attributes) throws BadLocationException { int length = getLength(); if (string == null) { return; } String newValue; if (length == 0) { newValue = string; } else { String currentContent = getText(0, length); StringBuilder currentBuffer = new StringBuilder(currentContent); currentBuffer.insert(offset, string); newValue = currentBuffer.toString(); } boolean b = Pattern.matches("[\\w\\s]*", newValue); if (b && !newValue.isEmpty()) { super.insertString(offset, string, attributes); } else { Toolkit.getDefaultToolkit().beep(); } } } public static class MaxLengthPlainDocument extends PlainDocument { private int maxLength; public MaxLengthPlainDocument(final int maxLength) { this.maxLength = maxLength; } @Override public void insertString(final int offset, final String string, final AttributeSet attributes) throws BadLocationException { int length = getLength(); if (string == null) { return; } if (length + string.length() > maxLength) { Toolkit.getDefaultToolkit().beep(); return; } super.insertString(offset, string, attributes); } } public static class MaxLengthStyledDocument extends DefaultStyledDocument { private int maxLength; public MaxLengthStyledDocument(final int maxLength) { this.maxLength = maxLength; } @Override public void insertString(final int offset, final String string, final AttributeSet attributes) throws BadLocationException { int length = getLength(); if (string == null) { return; } if (length + string.length() > maxLength) { Toolkit.getDefaultToolkit().beep(); return; } super.insertString(offset, string, attributes); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/Formatter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.FieldPosition; import java.text.NumberFormat; import java.text.ParseException; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.filter.FilterMatcher; import net.nikr.eve.jeveasset.i18n.GuiShared; public final class Formatter { //Must not be changed! please see: FilterControl private static final String COLUMN_DATETIME = "yyyy-MM-dd HH:mm"; public static final String COLUMN_DATE = "yyyy-MM-dd"; private static final DecimalFormat ISK_FORMAT = new DecimalFormat("#,##0.00 isk"); private static final DecimalFormat ITEM_FORMAT = new DecimalFormat("#,##0 item"); private static final DecimalFormat ITEMS_FORMAT = new DecimalFormat("#,##0 items"); private static final DecimalFormat PERCENT_FORMAT = new DecimalFormat("##0%"); private static final DecimalFormat TIMES_FORMAT = new DecimalFormat("##0x"); private static final DecimalFormat INTEGER_FORMAT = new DecimalFormat("0"); private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#,##0.00"); private static final DecimalFormat FLOAT_FORMAT = new DecimalFormat("#,##0.####"); private static final DecimalFormat COMPARE_FORMAT = new DecimalFormat("0.####", new DecimalFormatSymbols(FilterMatcher.LOCALE)); private static final DecimalFormat SECURITY_FORMAT = new DecimalFormat("0.0", new DecimalFormatSymbols(Locale.ENGLISH)); private static final DecimalFormat COPY_FORMAT = new DecimalFormat("0.##", new DecimalFormatSymbols(Locale.ENGLISH)); public static final DecimalFormat LONG_FORMAT = new DecimalFormat("#,##0"); public static final NumberFormat MILLIONS_FORMAT = new FixedFormat(1_000_000.0, "M"); public static final NumberFormat BILLIONS_FORMAT = new FixedFormat(1_000_000_000.0, "B"); public static final NumberFormat TRILLIONS_FORMAT = new FixedFormat(1_000_000_000_000.0, "T"); public static final NumberFormat AUTO_FORMAT = new AutoFormat(); private static final DateFormatThreadSafe EXPIRE_DATE1 = new DateFormatThreadSafe("EEE, dd MMM yyyy kk:mm:ss zzz"); //Tue, 04 Oct 2016 18:21:28 GMT private static final DateFormatThreadSafe EXPIRE_DATE2 = new DateFormatThreadSafe("dd MMM yyyy kk:mm:ss zzz"); private static final DateFormatThreadSafe COLUMN_DATE_FORMAT = new DateFormatThreadSafe(COLUMN_DATE); private static final DateFormatThreadSafe COLUMN_DATETIME_FORMAT = new DateFormatThreadSafe(COLUMN_DATETIME); private static final DateFormatThreadSafe TODAYS_DATE = new DateFormatThreadSafe("yyyyMMdd"); private static final DateFormatThreadSafe TIME_ONLY = new DateFormatThreadSafe("HH:mm z"); private static final DateFormatThreadSafe WEEKDAY_AND_TIME = new DateFormatThreadSafe("EEEEE HH:mm"); private static final DateFormatThreadSafe FILETIME = new DateFormatThreadSafe("yyyy-MM-dd--HH-mm", TimeZone.getDefault()); private static final DateFormatThreadSafe SIMPLE_DATE = new DateFormatThreadSafe("yyyyMMddHHmm"); private static final DateFormatThreadSafe DATE_ONLY = new DateFormatThreadSafe("yyyy-MM-dd"); private Formatter() { } public static Date parseExpireDate(String date) { try { return EXPIRE_DATE1.parse(date); } catch (ParseException ex) { } try { return EXPIRE_DATE2.parse(date); } catch (ParseException ex) { return new Date(); } } public static String copyFormat(final Number number) { DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(Locale.ENGLISH); switch (Settings.get().getCopySettings().getCopyDecimalSeparator()) { case COMMA: otherSymbols.setDecimalSeparator(','); break; case DOT: otherSymbols.setDecimalSeparator('.'); break; } COPY_FORMAT.setDecimalFormatSymbols(otherSymbols); return COPY_FORMAT.format(number); } public static String iskFormat(final Number number) { return ISK_FORMAT.format(number); } public static String percentFormat(final Number number) { return PERCENT_FORMAT.format(number); } public static String timesFormat(final Double number) { return TIMES_FORMAT.format(number); } public static String itemsFormat(final Number number) { if (number.longValue() == 1) { return ITEM_FORMAT.format(number); } else { return ITEMS_FORMAT.format(number); } } public static String doubleFormat(final Object obj) { return DECIMAL_FORMAT.format(obj); } public static String compareFormat(final Object obj) { return COMPARE_FORMAT.format(obj); } public static String securityFormat(final Object obj) { return SECURITY_FORMAT.format(obj); } /** * WARNING: This is not an good format for columns * It does however give a very precise result. * * @param obj value to be formatted * @return formatted value */ public static String floatFormat(final Object obj) { return FLOAT_FORMAT.format(obj); } public static String integerFormat(final Object obj) { return INTEGER_FORMAT.format(obj); } public static String longFormat(final Object obj) { return LONG_FORMAT.format(obj); } public static double longParse(final String s) throws ParseException{ return LONG_FORMAT.parse(s).doubleValue(); } public static double round(final double number, final int decimalPlaces) { double modifier = Math.pow(10.0, decimalPlaces); return Math.round(number * modifier) / modifier; } //DATE public static String weekdayAndTime(final Date date) { if (today(date)) { return GuiShared.get().today(TIME_ONLY.format(date)); } else { return WEEKDAY_AND_TIME.format(date); } } public static String columnDate(final Object date) { return COLUMN_DATETIME_FORMAT.format(date); } /** * Do not use unless only date information is available. * @param date * @return */ public static String columnDateOnly(final Object date) { return COLUMN_DATE_FORMAT.format(date); } public static String fileDate(final Object date) { return FILETIME.format(date); } public static Date columnStringToDate(final String date) { try { return COLUMN_DATETIME_FORMAT.parse(date); } catch (ParseException ex) { } try { return COLUMN_DATE_FORMAT.parse(date); } catch (ParseException ex) { } return null; } public static String timeOnly(final Date date) { return TIME_ONLY.format(date); } public static String eveTime(final Date date) { return TIME_ONLY.format(date); } public static String simpleDate(final Date date) { return SIMPLE_DATE.format(date); } public static String dateOnly(final Object date) { return DATE_ONLY.format(date); } private static boolean today(final Date date) { String sDate = TODAYS_DATE.format(date); String sNow = TODAYS_DATE.format(Settings.getNow()); return sDate.equals(sNow); } public static String milliseconds(long time) { return milliseconds(time, false, false, true, true, true, true); } public static String milliseconds(long time, boolean first, boolean verbose) { return milliseconds(time, first, verbose, true, true, true, true); } public static String milliseconds(long time, boolean showDays, boolean showHours, boolean showMinutes, boolean showSeconds) { return milliseconds(time, false, false, showDays, showHours, showMinutes, showSeconds); } public static String milliseconds(long time, boolean first, boolean verbose, boolean showDays, boolean showHours, boolean showMinutes, boolean showSeconds) { final StringBuilder timeString = new StringBuilder(); long days = time / (24 * 60 * 60 * 1000); boolean space = false; if (days > 0 && showDays) { timeString.append(days); if (verbose) { if (days > 1) { timeString.append(" days"); } else { timeString.append(" day"); } } else { timeString.append("d"); } if (first) { return timeString.toString(); } space = true; } long hours = time / (60 * 60 * 1000) % 24; if (!showDays) { hours = hours + (days * 24); } if (hours > 0 && showHours) { if (space) { timeString.append(" "); } timeString.append(hours); if (verbose) { if (hours > 1) { timeString.append(" hours"); } else { timeString.append(" hour"); } } else { timeString.append("h"); } if (first) { return timeString.toString(); } space = true; } long minutes = time / (60 * 1000) % 60; if (!showHours) { minutes = minutes + (hours * 60); } if (minutes > 0 && showMinutes) { if (space) { timeString.append(" "); } timeString.append(minutes); if (verbose) { if (minutes > 1) { timeString.append(" minutes"); } else { timeString.append(" minute"); } } else { timeString.append("m"); } if (first) { return timeString.toString(); } space = true; } long seconds = time / (1000) % 60; if (!showMinutes) { seconds = seconds + (minutes * 60); } if (seconds > 0 && showSeconds) { if (space) { timeString.append(" "); } timeString.append(seconds); if (verbose) { if (seconds > 1) { timeString.append(" seconds"); } else { timeString.append(" second"); } } else { timeString.append("s"); } if (first) { return timeString.toString(); } } if (days == 0 && hours == 0 && minutes == 0 && seconds == 0) { timeString.append(time); timeString.append("ms"); } return timeString.toString(); } public static class AutoFormat extends NumberFormat { private static final String[] UNITS = new String[] { "", "K", "M", "B", "T", "P", "E" }; private final NumberFormat format; public AutoFormat() { format = new DecimalFormat("#,##0.#"); } private String formatNumber(Number number) { long value = number.longValue(); if(value <= 0) { return "0"; } else { int digitGroups = (int) (Math.log10(value)/Math.log10(1000)); return format.format(value/Math.pow(1000, digitGroups)) + UNITS[digitGroups]; } } @Override public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) { toAppendTo.append(formatNumber(number)); return toAppendTo; } @Override public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) { toAppendTo.append(formatNumber(number)); return toAppendTo; } @Override public Number parse(String source, ParsePosition parsePosition) { return format.parse(source, parsePosition); } } public static class FixedFormat extends NumberFormat { private final NumberFormat format; private final double fix; public FixedFormat(final double fix, final String name) { this.fix = fix; format = new DecimalFormat("#,##0.0"+name); } @Override public StringBuffer format(final double number, final StringBuffer toAppendTo, final FieldPosition pos) { toAppendTo.append(format.format(number/fix)); return toAppendTo; } @Override public StringBuffer format(final long number, final StringBuffer toAppendTo, final FieldPosition pos) { toAppendTo.append(format.format(number/fix)); return toAppendTo; } @Override public Number parse(String source, ParsePosition parsePosition) { return format.parse(source, parsePosition); } } public static class DateFormatThreadSafe { private static final TimeZone TIME_ZONE = TimeZone.getTimeZone("GMT"); private final String format; private final boolean lenient; private final TimeZone timeZone; private final ThreadLocal df = new ThreadLocal() { @Override protected DateFormat initialValue() { SimpleDateFormat value = new SimpleDateFormat(format, new Locale("en")); value.setTimeZone(timeZone); value.setLenient(lenient); return value; } }; public DateFormatThreadSafe(String format) { this(format, false); } public DateFormatThreadSafe(String format, boolean lenient) { this(format, lenient, TIME_ZONE); } public DateFormatThreadSafe(String format, TimeZone timeZone) { this(format, false, timeZone); } public DateFormatThreadSafe(String format, boolean lenient, TimeZone timeZone) { this.format = format; this.lenient = lenient; this.timeZone = timeZone; } public Date parse(String dateString) throws ParseException { return df.get().parse(dateString); } public String format(final Object date) { return df.get().format(date); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/InstantToolTip.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import java.awt.Component; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.ToolTipManager; public class InstantToolTip { private final MouseListener listener; private final Component component; private InstantToolTip(Component component) { this.component = component; this.listener = new MouseAdapter() { //Instant ToolTips private int defaultDismissTimeout; private int defaultInitialDelay; @Override public void mouseEntered(MouseEvent me) { defaultDismissTimeout = ToolTipManager.sharedInstance().getDismissDelay(); defaultInitialDelay = ToolTipManager.sharedInstance().getInitialDelay(); ToolTipManager.sharedInstance().setDismissDelay(60000); ToolTipManager.sharedInstance().setInitialDelay(0); } @Override public void mouseExited(MouseEvent me) { ToolTipManager.sharedInstance().setDismissDelay(defaultDismissTimeout); ToolTipManager.sharedInstance().setInitialDelay(defaultInitialDelay); } }; component.addMouseListener(listener); } public static InstantToolTip install(Component component) { return new InstantToolTip(component); } public void uninstall() { component.removeMouseListener(listener); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/JFreeChartUtil.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.Ellipse2D; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.concurrent.TimeUnit; import javax.swing.JLabel; import net.nikr.eve.jeveasset.data.settings.Colors; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.LegendItem; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.DateTickUnit; import org.jfree.chart.axis.DateTickUnitType; import org.jfree.chart.axis.LogarithmicAxis; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.plot.Plot; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.general.DatasetUtils; import org.jfree.data.time.TimePeriodValuesCollection; import org.jfree.data.xy.XYDataset; public class JFreeChartUtil { private static final DateFormat dateFormat = new SimpleDateFormat(Formatter.COLUMN_DATE, new Locale("en")); private static final DateFormat yearsFormat = new SimpleDateFormat("yyyy", new Locale("en")); private static final DateFormat yearFormat = new SimpleDateFormat("yyyy-MM", new Locale("en")); private static final DateFormat monthsFormat = new SimpleDateFormat("MMM", new Locale("en")); private static final DateFormat monthFormat = new SimpleDateFormat("MMM dd", new Locale("en")); private static final DateFormat daysFormat = new SimpleDateFormat("EEE", new Locale("en")); private static final DateTickUnit yearTick = new DateTickUnit(DateTickUnitType.YEAR, 1); private static final DateTickUnit monthTick = new DateTickUnit(DateTickUnitType.MONTH, 1); private static final DateTickUnit daysTick = new DateTickUnit(DateTickUnitType.DAY, 1); private static Font font = null; public static DateFormat getDateFormat() { return dateFormat; } private JFreeChartUtil() { } private static Font getFont() { if (font == null) { font = new JLabel().getFont(); } return font; } public static DateAxis createDateAxis() { DateAxis dateAxis = new DateAxis(); dateAxis.setDateFormatOverride(JFreeChartUtil.getDateFormat()); dateAxis.setVerticalTickLabels(true); dateAxis.setAutoTickUnitSelection(true); dateAxis.setAutoRange(true); dateAxis.setTickLabelFont(getFont()); dateAxis.setTickLabelPaint(Colors.TEXTFIELD_FOREGROUND.getColor()); return dateAxis; } public static LogarithmicAxis createLogarithmicAxis(boolean includeZero) { LogarithmicAxis logarithmicAxis = new LogarithmicAxis(""); logarithmicAxis.setStrictValuesFlag(false); logarithmicAxis.setNumberFormatOverride(Formatter.AUTO_FORMAT); logarithmicAxis.setTickLabelFont(getFont()); logarithmicAxis.setTickLabelPaint(Colors.TEXTFIELD_FOREGROUND.getColor()); logarithmicAxis.setAutoRangeIncludesZero(includeZero); return logarithmicAxis; } public static NumberAxis createNumberAxis(boolean includeZero) { NumberAxis numberAxis = new NumberAxis(); numberAxis.setAutoRange(true); numberAxis.setNumberFormatOverride(Formatter.AUTO_FORMAT); numberAxis.setStandardTickUnits(NumberAxis.createStandardTickUnits()); numberAxis.setTickLabelFont(getFont()); numberAxis.setTickLabelPaint(Colors.TEXTFIELD_FOREGROUND.getColor()); numberAxis.setAutoRangeIncludesZero(includeZero); return numberAxis; } public static XYPlot createPlot(XYDataset dataset, ValueAxis domainAxis, ValueAxis rangeAxis, XYItemRenderer renderer) { XYPlot plot = new XYPlot(dataset, domainAxis, rangeAxis, renderer); plot.setBackgroundPaint(Colors.TEXTFIELD_BACKGROUND.getColor()); plot.setRangeGridlinePaint(Color.LIGHT_GRAY); plot.setDomainGridlinePaint(Color.LIGHT_GRAY); plot.setDomainCrosshairLockedOnData(true); plot.setDomainCrosshairStroke(new BasicStroke(1)); plot.setDomainCrosshairPaint(Color.BLACK); plot.setDomainCrosshairVisible(false); plot.setRangeCrosshairLockedOnData(true); plot.setRangeCrosshairVisible(false); return plot; } public static JFreeChart createChart(Plot plot) { JFreeChart jFreeChart = new JFreeChart(plot); jFreeChart.setAntiAlias(true); jFreeChart.setBackgroundPaint(Colors.COMPONENT_BACKGROUND.getColor()); jFreeChart.addProgressListener(null); jFreeChart.getLegend().setItemFont(getFont()); jFreeChart.getLegend().setItemPaint(Colors.TEXTFIELD_FOREGROUND.getColor()); jFreeChart.getLegend().setBackgroundPaint(Colors.COMPONENT_BACKGROUND.getColor()); return jFreeChart; //jFreeChart.setTextAntiAlias(false); //jFreeChart.setAntiAlias(false); /* Map rh = new HashMap<>(); rh.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //rh.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_DEFAULT); //rh.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); //rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_DEFAULT); //rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); //rh.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); rh.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DEFAULT); //rh.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE); //rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); //rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP); //rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR); //rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); //rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR); //rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB); //rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); //rh.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); rh.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT); //rh.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF); //rh.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); rh.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); //rh.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); //rh.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); rh.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT); //rh.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED); //rh.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); rh.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_DEFAULT); //rh.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED); //rh.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE); rh.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT); //rh.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); jFreeChart.setRenderingHints(new RenderingHints(rh)); */ } public static ChartPanel createChartPanel(JFreeChart jChart) { ChartPanel jChartPanel = new ChartPanel(jChart); InstantToolTip.install(jChartPanel); jChartPanel.setDomainZoomable(false); jChartPanel.setRangeZoomable(false); jChartPanel.setPopupMenu(null); //jChartPanel.addChartMouseListener(listener); jChartPanel.setMaximumDrawHeight(Integer.MAX_VALUE); jChartPanel.setMaximumDrawWidth(Integer.MAX_VALUE); jChartPanel.setMinimumDrawWidth(10); jChartPanel.setMinimumDrawHeight(10); return jChartPanel; } public static XYLineAndShapeRenderer createRenderer() { return new SimpleRenderer(); } public static void updateTickScale(DateAxis domainAxis, NumberAxis numberAxis, TimePeriodValuesCollection dataset) { updateTickScale(domainAxis); updateTickScale(numberAxis, dataset); } public static void updateTickScale(DateAxis domainAxis, NumberAxis numberAxis, Number maxNumber) { updateTickScale(domainAxis); updateTickScale(numberAxis, maxNumber); } public static void updateTickScale(NumberAxis numberAxis, TimePeriodValuesCollection dataset) { updateTickScale(numberAxis, DatasetUtils.findMaximumRangeValue(dataset)); } public static void updateTickScale(NumberAxis numberAxis, Number maxNumber) { if (maxNumber != null && maxNumber instanceof Double) { double max = (Double) maxNumber; if (max > 1_000_000_000_000.0) {//Higher than 1 Trillion numberAxis.setNumberFormatOverride(Formatter.TRILLIONS_FORMAT); } else if (max > 1_000_000_000.0) { //Higher than 1 Billion numberAxis.setNumberFormatOverride(Formatter.BILLIONS_FORMAT); } else if (max > 1_000_000.0) { //Higher than 1 Million numberAxis.setNumberFormatOverride(Formatter.MILLIONS_FORMAT); } else { //Default numberAxis.setNumberFormatOverride(Formatter.LONG_FORMAT); } } } public static void updateTickScale(DateAxis domainAxis) { Date maximumDate = domainAxis.getMaximumDate(); Date minimumDate = domainAxis.getMinimumDate(); long diff = Math.abs(maximumDate.getTime() - minimumDate.getTime()); long days = TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS); if (days > 732) { // above 2 years domainAxis.setTickUnit(yearTick, false, true); domainAxis.setDateFormatOverride(yearsFormat); } else if (days > 400) { // above 1 years domainAxis.setTickUnit(monthTick, false, true); domainAxis.setDateFormatOverride(yearFormat); } else if (days > 60) { // above 2 months domainAxis.setTickUnit(monthTick, false, true); domainAxis.setDateFormatOverride(monthsFormat); } else if (days > 7) { // above 7 days domainAxis.setAutoTickUnitSelection(true, false); //Auto (hard zone to do well) domainAxis.setDateFormatOverride(monthFormat); } else { // bellow 7 days domainAxis.setTickUnit(daysTick, false, true); domainAxis.setDateFormatOverride(daysFormat); } } public static class SimpleRenderer extends XYLineAndShapeRenderer { private final Stroke LEGEND_STROKE = new BasicStroke(0.9f); private final Shape LEGEND_SHAPE = new Ellipse2D.Float(-5.5f, -5.5f, 11f, 11f); private final Shape ITEM_SHAPE = new Ellipse2D.Float(-3.0f, -3.0f, 6.0f, 6.0f); public SimpleRenderer(boolean lines, boolean shapes) { super(lines, shapes); } public SimpleRenderer() { super(true, false); } @Override public LegendItem getLegendItem(int datasetIndex, int series) { LegendItem original = super.getLegendItem(datasetIndex, series); //To change body of generated methods, choose Tools | Templates. LegendItem fixed = new LegendItem( original.getLabel(), original.getDescription(), original.getToolTipText(), "", //urlText LEGEND_SHAPE, original.getLinePaint(), //set fill paint to line paint LEGEND_STROKE, //original.getOutlineStroke(), Color.BLACK ); fixed.setSeriesIndex(series); fixed.setDatasetIndex(datasetIndex); return fixed; } @Override public Shape getItemShape(int row, int column) { return ITEM_SHAPE; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/JOptionInput.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import java.awt.Component; import java.awt.HeadlessException; import java.util.Locale; import javax.swing.Icon; import javax.swing.JDialog; import javax.swing.JOptionPane; import static javax.swing.JOptionPane.OK_CANCEL_OPTION; import static javax.swing.JOptionPane.QUESTION_MESSAGE; import static javax.swing.JOptionPane.UNINITIALIZED_VALUE; import static javax.swing.JOptionPane.getRootFrame; import javax.swing.UIManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class JOptionInput { private static final Logger LOG = LoggerFactory.getLogger(JOptionInput.class); public static String showInputDialog(Object message) throws HeadlessException { return showInputDialog(null, message); } public static String showInputDialog(Object message, Object initialSelectionValue) { return showInputDialog(null, message, initialSelectionValue); } public static String showInputDialog(Component parentComponent, Object message) throws HeadlessException { return showInputDialog(parentComponent, message, getString("OptionPane.inputDialogTitle", parentComponent), QUESTION_MESSAGE); } public static String showInputDialog(Component parentComponent, Object message, Object initialSelectionValue) { return (String) showInputDialog(parentComponent, message, getString("OptionPane.inputDialogTitle", parentComponent), QUESTION_MESSAGE, null, null, initialSelectionValue); } public static String showInputDialog(Component parentComponent, Object message, String title, int messageType) { return (String) showInputDialog(parentComponent, message, title, messageType, null, null, null); } public static Object showInputDialog(Component parentComponent, Object message, String title, int messageType, Icon icon, Object[] selectionValues, Object initialSelectionValue) { try { return internalInputDialog(parentComponent, message, title, messageType, icon, selectionValues, initialSelectionValue); } catch (Throwable ex) { //Fallback on ANY error LOG.error(ex.getMessage(), ex); return JOptionPane.showInputDialog(parentComponent, message, title, messageType, icon, selectionValues, initialSelectionValue); } } private static Object internalInputDialog(Component parentComponent, Object message, String title, int messageType, Icon icon, Object[] selectionValues, Object initialSelectionValue) { JOptionPane pane = new JOptionPane(message, messageType, OK_CANCEL_OPTION, icon, null, null); pane.setWantsInput(true); pane.setSelectionValues(selectionValues); pane.setInitialSelectionValue(initialSelectionValue); pane.setComponentOrientation(((parentComponent == null) ? getRootFrame() : parentComponent).getComponentOrientation()); TextManager.installAll(pane); JDialog dialog = pane.createDialog(parentComponent, title); pane.selectInitialValue(); dialog.setVisible(true); dialog.dispose(); Object value = pane.getInputValue(); if (value == UNINITIALIZED_VALUE) { return null; } return value; } private static String getString(Object key, Component c) { Locale l = (c == null) ? Locale.getDefault() : c.getLocale(); return UIManager.getString(key, l); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/JSimpleColorPicker.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Component; import java.awt.Composite; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.Point; import java.awt.RenderingHints; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.List; import java.util.Objects; import javax.swing.BorderFactory; import javax.swing.GroupLayout; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JColorChooser; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.border.Border; import net.nikr.eve.jeveasset.data.settings.Colors; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JSimpleColorPicker { private final JDialog jDialog; private final List icons = new ArrayList<>(); private final JButton jDefault; private final JButton jNone; private Color input; private Color defaultColor; private ColorListenere colorListenere; public JSimpleColorPicker(Window jParent) { jDialog = new JDialog(jParent); jDialog.setUndecorated(true); jDialog.addWindowListener(new WindowAdapter() { @Override public void windowDeactivated(WindowEvent e) { cancel(); } }); JPanel jPanel = new JPanel(); if (ColorUtil.isBrightColor(jPanel.getBackground())) { //Light background color jPanel.setBackground(Color.WHITE); } else { //Dark background color jPanel.setBackground(Color.BLACK); } jPanel.setBorder(new JPopupMenu().getBorder()); GroupLayout groupLayout = new GroupLayout(jPanel); groupLayout.setAutoCreateContainerGaps(true); groupLayout.setAutoCreateGaps(true); jPanel.setLayout(groupLayout); jDialog.add(jPanel); jDefault = createButton(GuiShared.get().colorDefault()); jDefault.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { reset(); } }); jNone = createButton(GuiShared.get().colorNone()); jNone.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { none(); } }); JPanel jColorPanel = new JPanel(); jColorPanel.setOpaque(false); jColorPanel.setLayout(new GridLayout(0, 10, 0, 1)); for (Color color : getColors()) { add(jColorPanel, color); } List colors = new ArrayList<>(); colors.add(Colors.LIGHT_GRAY); colors.add(Colors.STRONG_GRAY); colors.add(Colors.FOREGROUND_RED); colors.add(Colors.FOREGROUND_GREEN); colors.add(Colors.LIGHT_RED); colors.add(Colors.STRONG_RED); colors.add(Colors.LIGHT_ORANGE); colors.add(Colors.STRONG_ORANGE); colors.add(Colors.LIGHT_YELLOW); colors.add(Colors.STRONG_YELLOW); colors.add(Colors.LIGHT_GREEN); colors.add(Colors.STRONG_GREEN); colors.add(Colors.LIGHT_BLUE); colors.add(Colors.STRONG_BLUE); colors.add(Colors.LIGHT_MAGENTA); colors.add(Colors.STRONG_MAGENTA); JPanel jClassicPanel = new JPanel(); jClassicPanel.setOpaque(false); jClassicPanel.setLayout(new GridLayout(0, 2, 0, 1)); for (Colors defaultColors : colors) { add(jClassicPanel, defaultColors); } List blindColors = new ArrayList<>(); blindColors.add(Colors.DARK_GRAY); blindColors.add(Colors.COLORBLIND_FOREGROUND_GREEN); blindColors.add(Colors.COLORBLIND_FOREGROUND_RED); blindColors.add(Colors.COLORBLIND_ORANGE); blindColors.add(Colors.COLORBLIND_YELLOW); blindColors.add(Colors.COLORBLIND_GREEN); blindColors.add(Colors.COLORBLIND_BLUE); blindColors.add(Colors.COLORBLIND_MAGENTA); JPanel jBlindPanel = new JPanel(); jBlindPanel.setOpaque(false); jBlindPanel.setLayout(new GridLayout(0, 1, 0, 1)); for (Colors defaultColors : blindColors) { add(jBlindPanel, defaultColors); } List darkColors = new ArrayList<>(); darkColors.add(Colors.DARK_FOREGROUND_GREEN); darkColors.add(Colors.DARK_FOREGROUND_RED); darkColors.add(Colors.DARK_RED); darkColors.add(Colors.DARK_ORANGE); darkColors.add(Colors.DARK_YELLOW); darkColors.add(Colors.DARK_GREEN); darkColors.add(Colors.DARK_BLUE); darkColors.add(Colors.DARK_MAGENTA); JPanel jDarkPanel = new JPanel(); jDarkPanel.setOpaque(false); jDarkPanel.setLayout(new GridLayout(0, 1, 0, 1)); for (Colors defaultColors : darkColors) { add(jDarkPanel, defaultColors); } JButton jCustom = createButton(GuiShared.get().colorCustom()); jCustom.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Color color = JColorChooser.showDialog(jParent, null, input); if (color == null) { cancel(); } else { save(color); } } }); groupLayout.setHorizontalGroup( groupLayout.createParallelGroup(GroupLayout.Alignment.CENTER) .addGroup(groupLayout.createSequentialGroup() .addComponent(jDefault, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jNone, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) ) .addGroup(groupLayout.createSequentialGroup() .addComponent(jColorPanel) .addGap(15) .addComponent(jClassicPanel) .addGap(0) .addComponent(jBlindPanel) .addGap(0) .addComponent(jDarkPanel) ) .addComponent(jCustom, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) ); groupLayout.setVerticalGroup( groupLayout.createSequentialGroup() .addGroup(groupLayout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jDefault) .addComponent(jNone) ) .addGroup(groupLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jColorPanel) .addComponent(jClassicPanel) .addComponent(jBlindPanel) .addComponent(jDarkPanel) ) .addComponent(jCustom) ); } private void add(JPanel jPanel, Colors color) { add(jPanel, color != null ? color.getColor() : null); } private void add(JPanel jPanel, Color color) { if (color == null) { JLabel jLabel = new JLabel(); Dimension dimension = new Dimension(ButtonColorIcon.SIZE, ButtonColorIcon.SIZE); jLabel.setMinimumSize(dimension); jLabel.setPreferredSize(dimension); jLabel.setMaximumSize(dimension); jPanel.add(jLabel); return; } ButtonColorIcon icon = new ButtonColorIcon(color, ColorUtil.isBrightColor(jPanel.getBackground())); icons.add(icon); JButton jButton = createButton(icon); jButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { save(color); } }); jPanel.add(jButton); } public void show(Color input, Color defaultColor, boolean nullable, Point point, ColorListenere colorListenere) { this.input = input; this.defaultColor = defaultColor; this.colorListenere = colorListenere; for (ButtonColorIcon icon : icons) { icon.setSelect(input); } jDefault.setEnabled(!Objects.equals(input, defaultColor)); jDefault.setBorder(getBorder(jDefault)); jNone.setEnabled(input != null && nullable); jNone.setBorder(getBorder(jNone)); jDialog.pack(); jDialog.setLocation(point.x - jDialog.getSize().width, point.y); jDialog.setVisible(true); } private void cancel() { jDialog.setVisible(false); colorListenere.cancelled(); } private void reset() { colorListenere.colorChanged(defaultColor); jDialog.setVisible(false); } private void none() { colorListenere.colorChanged(null); jDialog.setVisible(false); } private void save(Color color) { colorListenere.colorChanged(color); jDialog.setVisible(false); } private Border getBorderInner(JButton jButton) { if (jButton.isEnabled()) { if (ColorUtil.isBrightColor(jButton.getBackground())) { //Light background color return BorderFactory.createLineBorder(Color.BLACK, 1); } else { //Dark background color return BorderFactory.createLineBorder(Color.WHITE, 1); } } else { return BorderFactory.createLineBorder(Color.DARK_GRAY, 1); } } private Border getBorder(JButton jButton) { return BorderFactory.createCompoundBorder(getBorderInner(jButton), BorderFactory.createEmptyBorder(2, 2, 2, 2)); } private JButton createButton(String text) { return config(text, null, true); } private JButton createButton(Icon icon) { return config(null, icon, false); } private JButton config(String text, Icon icon, boolean border) { JButton jButton = new JButton(); if (text != null) { jButton.setText(text); jButton.setBackground(Colors.TABLE_SELECTION_BACKGROUND.getColor()); jButton.addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent e) { if (jButton.isEnabled()) { jButton.setBorder(BorderFactory.createCompoundBorder(getBorderInner(jButton), BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Colors.TABLE_SELECTION_BACKGROUND.getColor(), 1), BorderFactory.createEmptyBorder(1, 1, 1, 1)))); } } @Override public void mouseExited(MouseEvent e) { jButton.setBorder(getBorder(jButton)); } }); } if (icon != null) { jButton.setIcon(icon); if (icon instanceof ButtonColorIcon) { ButtonColorIcon buttonColorIcon = (ButtonColorIcon) icon; jButton.addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent e) { if (jButton.isEnabled()) { buttonColorIcon.setHover(true); jButton.repaint(); } } @Override public void mouseExited(MouseEvent e) { buttonColorIcon.setHover(false); jButton.repaint(); } }); } } jButton.setFocusPainted(false); if (border) { jButton.setBorder(getBorder(jButton)); } else { jButton.setBorder(null); } jButton.setContentAreaFilled(false); return jButton; } public static interface ColorListenere { public void colorChanged(Color color); public void cancelled(); } public static class ButtonColorIcon implements Icon { private static final int SIZE = 22; private final Color color; private final boolean backgroundIsBright; private final boolean colorIsBright; private boolean selected = false; private boolean hover = false; public ButtonColorIcon(Color color, boolean brightBorder) { this.color = color; this.backgroundIsBright = brightBorder; colorIsBright = ColorUtil.isBrightColor(color); } public void setSelect(Color match) { this.selected = color.equals(match); } public void setHover(boolean hover) { this.hover = hover; } @Override public void paintIcon(Component c, Graphics g, int x, int y) { Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); if (hover) { //Hover AlphaComposite newValue = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f); Composite oldValue = g2d.getComposite(); g2d.setComposite(newValue); if (backgroundIsBright) { g2d.setColor(Color.BLACK); } else { g2d.setColor(Color.WHITE); } fillOval(g2d, 0, x, y); g2d.setComposite(oldValue); } //Border if (backgroundIsBright) { g2d.setColor(color.darker()); } else { if (color.equals(Color.BLACK)) { g2d.setColor(Color.DARK_GRAY); } else { g2d.setColor(color.brighter()); } } fillOval(g2d, 2, x, y); //Background g2d.setColor(color); fillOval(g2d, 3, x, y); //Icon if (selected) { if (colorIsBright) { g2d.drawImage(Images.SETTINGS_COLOR_CHECK_BLACK.getImage(), x + (getIconWidth()-16)/2, y + (getIconWidth()-16)/2, null); } else { g2d.drawImage(Images.SETTINGS_COLOR_CHECK_WHITE.getImage(), x + (getIconWidth()-16)/2, y + (getIconWidth()-16)/2, null); } } } private void fillOval(Graphics2D g2d, int offset, int x, int y) { g2d.fillOval(x + (offset), y + (offset), getIconWidth() - (offset*2), getIconHeight() - (offset*2)); } @Override public int getIconWidth() { return SIZE; } @Override public int getIconHeight() { return SIZE; } } private static List getColors() { List colors = new ArrayList<>(); //Black Gray White colors.add(new Color(0, 0, 0)); colors.add(new Color(67, 67, 67)); colors.add(new Color(102, 102, 102)); colors.add(new Color(153, 153, 153)); colors.add(new Color(183, 183, 183)); colors.add(new Color(204, 204, 204)); colors.add(new Color(217, 217, 217)); colors.add(new Color(239, 239, 239)); colors.add(new Color(243, 243, 243)); colors.add(new Color(255, 255, 255)); //Strong colors.add(new Color(152, 0, 0)); //Brown colors.add(new Color(255, 0, 0)); //Red colors.add(new Color(255, 152, 0)); //Orange colors.add(new Color(255, 255, 0)); //Yellow colors.add(new Color(0, 255, 0)); //Green colors.add(new Color(0, 255, 255)); //Cyan colors.add(new Color(74, 134, 232));//Light Blue colors.add(new Color(0, 0, 255)); //Blue colors.add(new Color(152, 0, 255)); //Purple colors.add(new Color(255, 0, 255)); //Magenta colors.add(new Color(230, 184, 175));//Brown colors.add(new Color(244, 204, 204));//Red colors.add(new Color(252, 229, 205));//Orange colors.add(new Color(255, 242, 204));//Yellow colors.add(new Color(217, 234, 211));//Green colors.add(new Color(208, 224, 227));//Cyan colors.add(new Color(201, 218, 248));//Light Blue colors.add(new Color(207, 226, 243));//Blue colors.add(new Color(217, 210, 233));//Purple colors.add(new Color(234, 209, 220));//Magenta colors.add(new Color(221, 126, 107)); //Brown colors.add(new Color(234, 153, 153)); //Red colors.add(new Color(249, 203, 156)); //Orange colors.add(new Color(255, 229, 153)); //Yellow colors.add(new Color(182, 215, 168)); //Green colors.add(new Color(162, 196, 201)); //Cyan colors.add(new Color(164, 194, 244)); //Light Blue colors.add(new Color(159, 197, 232)); //Blue colors.add(new Color(180, 167, 214)); //Purple colors.add(new Color(213, 166, 189)); //Magenta colors.add(new Color(204, 65, 37)); //Brown colors.add(new Color(224, 102, 102)); //Red colors.add(new Color(246, 178, 107)); //Orange colors.add(new Color(255, 217, 102)); //Yellow colors.add(new Color(147, 196, 125)); //Green colors.add(new Color(118, 165, 175)); //Cyan colors.add(new Color(109, 158, 235)); //Light Blue colors.add(new Color(111, 168, 220)); //Blue colors.add(new Color(142, 124, 195)); //Purple colors.add(new Color(194, 123, 160)); //Magenta colors.add(new Color(166, 28, 0)); //Brown colors.add(new Color(204, 0, 0)); //Red colors.add(new Color(230, 145, 56)); //Orange colors.add(new Color(241, 194, 50)); //Yellow colors.add(new Color(106, 168, 79)); //Green colors.add(new Color(69, 129, 142)); //Cyan colors.add(new Color(60, 120, 216)); //Light Blue colors.add(new Color(61, 133, 198)); //Blue colors.add(new Color(103, 78, 167)); //Purple colors.add(new Color(166, 77, 121)); //Magenta colors.add(new Color(133, 32, 12)); //Brown colors.add(new Color(153, 0, 0)); //Red colors.add(new Color(180, 95, 6)); //Orange colors.add(new Color(191, 144, 0)); //Yellow colors.add(new Color(56, 118, 29)); //Green colors.add(new Color(19, 79, 92)); //Cyan colors.add(new Color(17, 85, 204)); //Light Blue colors.add(new Color(11, 83, 148)); //Blue colors.add(new Color(53, 28, 117)); //Purple colors.add(new Color(116, 27, 71)); //Magenta colors.add(new Color(91, 15, 0)); //Brown colors.add(new Color(102, 0, 0)); //Red colors.add(new Color(120, 63, 5)); //Orange colors.add(new Color(127, 96, 0)); //Yellow colors.add(new Color(39, 78, 19)); //Green colors.add(new Color(12, 52, 61)); //Cyan colors.add(new Color(28, 69, 135)); //Light Blue colors.add(new Color(7, 55, 99)); //Blue colors.add(new Color(32, 18, 77)); //Purple colors.add(new Color(76, 17, 48)); //Magenta return colors; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/MarketDetailsColumn.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import net.nikr.eve.jeveasset.data.settings.types.MarketDetailType; import net.nikr.eve.jeveasset.gui.shared.components.JButtonNull; public class MarketDetailsColumn { public static void install(EventList eventList, MarketDetailsActionListener marketDetailsActionListener) { eventList.addListEventListener(new ListEventListener() { @Override @SuppressWarnings("deprecation") public void listChanged(ListEvent listChanges) { try { eventList.getReadWriteLock().readLock().lock(); while(listChanges.next()) { switch (listChanges.getType()) { case ListEvent.DELETE: E oldMarketDetails = listChanges.getOldValue(); JButton jOldButton = oldMarketDetails.getButton(); //check null button if (jOldButton == null || jOldButton instanceof JButtonNull) { continue; } //remove old ActionListener(s) for (ActionListener actionListener : jOldButton.getActionListeners()) { jOldButton.removeActionListener(actionListener); } break; case ListEvent.INSERT: int index = listChanges.getIndex(); //check index if (index < 0 || index >= eventList.size()) { continue; } E newMarketDetails = eventList.get(index); JButton jNewButton = newMarketDetails.getButton(); //check null button if (jNewButton == null || jNewButton instanceof JButtonNull) { continue; } //remove old ActionListener(s) for (ActionListener actionListener : jNewButton.getActionListeners()) { jNewButton.removeActionListener(actionListener); } //add new ActionListener jNewButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { marketDetailsActionListener.openMarketDetails(newMarketDetails); } }); break; } } } finally { eventList.getReadWriteLock().readLock().unlock(); } } }); } public static interface MarketDetailsActionListener { public void openMarketDetails(E marketDetails); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/MenuScroller.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * Original code by Darryl (http://tips4java.wordpress.com/2009/02/01/menu-scroller/) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; /** * A class that provides scrolling capabilities to a long menu dropdown or popup * menu. A number of items can optionally be frozen at the top and/or bottom of * the menu.

Implementation note: The default number of items to * display at a time is 15, and the default scrolling interval is 125 * milliseconds.

* * @author Darryl, http://tips4java.wordpress.com/2009/02/01/menu-scroller/ */ public class MenuScroller { private MenuContainer menu; private Component[] menuItems; private MenuScrollItem upItem; private MenuScrollItem downItem; private final MenuScrollListener menuListener = new MenuScrollListener(); private final MouseScrollListener mouseListener = new MouseScrollListener(); private int scrollCount; private int interval; private int topFixedCount; private int bottomFixedCount; private int firstIndex = 0; private int keepVisibleIndex = -1; /** * Constructs a * MenuScroller that scrolls a popup menu with the default * number of items to display at a time, and default scrolling interval. * * @param menu the popup menu */ public MenuScroller(final JPopupMenu menu) { this(menu, 15); } /** * Constructs a * MenuScroller that scrolls a popup menu with the specified * number of items to display at a time, and specified scrolling interval. * * @param menu the popup menu * @param interval the scroll interval, in milliseconds * @throws IllegalArgumentException if scrollCount or interval is 0 or * negative */ public MenuScroller(final JPopupMenu menu, final int interval) { this(menu, interval, 0, 0); } /** * Constructs a * MenuScroller that scrolls a popup menu with the specified * number of items to display in the scrolling region, the specified * scrolling interval, and the specified numbers of items fixed at the top * and bottom of the popup menu. * * @param menu the popup menu * @param interval the scroll interval, in milliseconds * @param topFixedCount the number of items to fix at the top. May be 0 * @param bottomFixedCount the number of items to fix at the bottom. May be * 0 * @throws IllegalArgumentException if scrollCount or interval is 0 or * negative or if topFixedCount or bottomFixedCount is negative */ public MenuScroller(final JPopupMenu menu, final int interval, final int topFixedCount, final int bottomFixedCount) { this(new MenuContainer(menu), interval, topFixedCount, bottomFixedCount); } public MenuScroller(final JMenu menu) { this(menu, 15); } public MenuScroller(final JMenu menu, final int interval) { this(menu, interval, 0, 0); } public MenuScroller(final JMenu menu, final int interval, final int topFixedCount, final int bottomFixedCount) { this(new MenuContainer(menu), interval, topFixedCount, bottomFixedCount); } private MenuScroller(final MenuContainer menu, final int interval, final int topFixedCount, final int bottomFixedCount) { if (interval <= 0) { throw new IllegalArgumentException("interval must be greater than 0"); } if (topFixedCount < 0 || bottomFixedCount < 0) { throw new IllegalArgumentException("topFixedCount and bottomFixedCount cannot be negative"); } upItem = new MenuScrollItem(MenuIcon.UP, -1); downItem = new MenuScrollItem(MenuIcon.DOWN, +1); scrollCount = 0; setInterval(interval); setTopFixedCount(topFixedCount); setBottomFixedCount(bottomFixedCount); this.menu = menu; menu.addListener(menuListener, mouseListener); } /** * Returns the scroll interval in milliseconds. * * @return the scroll interval in milliseconds */ public int getInterval() { return interval; } /** * Sets the scroll interval in milliseconds. * * @param interval the scroll interval in milliseconds * @throws IllegalArgumentException if interval is 0 or negative */ public final void setInterval(final int interval) { if (interval <= 0) { throw new IllegalArgumentException("interval must be greater than 0"); } upItem.setInterval(interval); downItem.setInterval(interval); this.interval = interval; } /** * Returns the number of items fixed at the top of the menu or popup menu. * * @return the number of items */ public int getTopFixedCount() { return topFixedCount; } /** * Sets the number of items to fix at the top of the menu or popup menu. * * @param topFixedCount the number of items */ public final void setTopFixedCount(final int topFixedCount) { if (firstIndex <= topFixedCount) { firstIndex = topFixedCount; } else { firstIndex += (topFixedCount - this.topFixedCount); } this.topFixedCount = topFixedCount; } /** * Returns the number of items fixed at the bottom of the menu or popup * menu. * * @return the number of items */ public int getBottomFixedCount() { return bottomFixedCount; } /** * Sets the number of items to fix at the bottom of the menu or popup menu. * * @param bottomFixedCount the number of items */ public final void setBottomFixedCount(final int bottomFixedCount) { this.bottomFixedCount = bottomFixedCount; } /** * Scrolls the specified item into view each time the menu is opened. Call * this method with * null to restore the default behavior, which is to show the * menu as it last appeared. * * @param item the item to keep visible * @see #keepVisible(int) */ public void keepVisible(final JMenuItem item) { if (item == null) { keepVisibleIndex = -1; } else { int index = menu.getComponentIndex(item); keepVisibleIndex = index; } } /** * Scrolls the item at the specified index into view each time the menu is * opened. Call this method with * -1 to restore the default behavior, which is to show the * menu as it last appeared. * * @param index the index of the item to keep visible * @see #keepVisible(javax.swing.JMenuItem) */ public void keepVisible(final int index) { keepVisibleIndex = index; } /** * Removes this MenuScroller from the associated menu and restores the * default behavior of the menu. */ public void dispose() { if (menu != null) { menu.removeListener(menuListener, mouseListener); menu = null; } } private void refreshMenu() { if (menuItems != null && menuItems.length > 0) { int maxScroll = menuItems.length - (topFixedCount + bottomFixedCount + 2); if (scrollCount == maxScroll) { //Show All menu.setPreferredSize(null); return; } firstIndex = Math.max(topFixedCount, firstIndex); firstIndex = Math.min(menuItems.length - bottomFixedCount - scrollCount, firstIndex); upItem.setEnabled(firstIndex > topFixedCount); downItem.setEnabled(firstIndex + scrollCount < menuItems.length - bottomFixedCount); menu.removeAll(); //Top Fixed for (int i = 0; i < topFixedCount && i < menuItems.length; i++) { menu.add(menuItems[i]); } //Scroll menu.add(upItem); for (int i = firstIndex; i < scrollCount + firstIndex; i++) { menu.add(menuItems[i]); } menu.add(downItem); //Bottom Fixed for (int i = menuItems.length - bottomFixedCount; i < menuItems.length; i++) { menu.add(menuItems[i]); } int preferredWidth = 0; for (Component item : menuItems) { preferredWidth = Math.max(preferredWidth, item.getPreferredSize().width); } menu.setPreferredSize(null); //Reset height menu.setPreferredSize(new Dimension(preferredWidth, menu.getPreferredSize().height)); JComponent parent = (JComponent) upItem.getParent(); parent.revalidate(); parent.repaint(); } } public void scrollCountForScreen() { int maxHeight = 0; if (menuItems != null && menuItems.length > 0) { for (Component item : menuItems) { maxHeight = Math.max(maxHeight, item.getPreferredSize().height); } Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); int height = screenSize.height; int maxScroll = (height / maxHeight) - (topFixedCount + bottomFixedCount + 2); // 2 just takes the menu up a bit from the bottom which looks nicer scrollCount = Math.min(maxScroll, menuItems.length - (topFixedCount + bottomFixedCount + 2)); } } private class MenuScrollListener implements PopupMenuListener, MenuListener { @Override public void menuSelected(MenuEvent e) { setMenuItems(); } @Override public void menuDeselected(MenuEvent e) { restoreMenuItems(); } @Override public void menuCanceled(MenuEvent e) { //restoreMenuItems(); } @Override public void popupMenuWillBecomeVisible(final PopupMenuEvent e) { setMenuItems(); } @Override public void popupMenuWillBecomeInvisible(final PopupMenuEvent e) { restoreMenuItems(); } @Override public void popupMenuCanceled(final PopupMenuEvent e) { restoreMenuItems(); } private void setMenuItems() { menuItems = menu.getComponents(); scrollCountForScreen(); if (keepVisibleIndex >= topFixedCount && keepVisibleIndex <= menuItems.length - bottomFixedCount && (keepVisibleIndex > firstIndex + scrollCount || keepVisibleIndex < firstIndex)) { firstIndex = Math.min(firstIndex, keepVisibleIndex); firstIndex = Math.max(firstIndex, keepVisibleIndex - scrollCount + 1); } if (menuItems.length > topFixedCount + scrollCount + bottomFixedCount) { refreshMenu(); } } private void restoreMenuItems() { menu.removeAll(); for (Component component : menuItems) { menu.add(component); } } } private class MouseScrollListener implements MouseWheelListener { @Override public void mouseWheelMoved(final MouseWheelEvent mwe) { firstIndex += mwe.getWheelRotation(); mwe.consume(); refreshMenu(); } } private class MenuScrollItem extends JMenuItem implements ChangeListener, MouseListener{ private Timer timer; public MenuScrollItem(final MenuIcon icon, final int increment) { setIcon(icon); setDisabledIcon(icon); timer = new Timer(interval, new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { firstIndex += increment; refreshMenu(); } }); addChangeListener(this); addMouseListener(this); } public void setInterval(final int interval) { timer.setDelay(interval); } @Override protected void processMouseEvent(MouseEvent e) { if (e.getButton() == MouseEvent.NOBUTTON) { //Ignore mouse clicks super.processMouseEvent(e); //Process mouse event like normal } } @Override public void mouseClicked(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { if (!isArmed()) { setArmed(true); } } @Override public void mouseExited(MouseEvent e) { if (isArmed()) { setArmed(false); } } @Override public void stateChanged(final ChangeEvent e) { if (isArmed() && !timer.isRunning()) { timer.start(); } if (!isArmed() && timer.isRunning()) { timer.stop(); } } } private static enum MenuIcon implements Icon { UP(7, 3, 7), DOWN(3, 7, 3); private final int[] xPoints = {1, 5, 9}; private final int[] yPoints; private final boolean bright; MenuIcon(final int... yPoints) { this.yPoints = yPoints; bright = ColorUtil.isBrightColor(new JPanel().getBackground()); } @Override public void paintIcon(final Component c, final Graphics g, final int x, final int y) { Dimension size = c.getSize(); Graphics g2 = g.create(size.width / 2 - 5, size.height / 2 - 5, 10, 10); if (bright) { if (c.isEnabled()) { g2.setColor(Color.BLACK); } else { g2.setColor(Color.LIGHT_GRAY); } } else { if (c.isEnabled()) { g2.setColor(Color.GRAY.brighter()); } else { g2.setColor(Color.GRAY.darker()); } } g2.fillPolygon(xPoints, yPoints, 3); if (bright) { if (c.isEnabled()) { g2.setColor(Color.DARK_GRAY); } else { g2.setColor(Color.LIGHT_GRAY); } } else { if (c.isEnabled()) { g2.setColor(Color.LIGHT_GRAY); } else { g2.setColor(Color.DARK_GRAY); } } g2.drawPolygon(xPoints, yPoints, 3); g2.dispose(); } @Override public int getIconWidth() { return 0; } @Override public int getIconHeight() { return 10; } } private static class MenuContainer { private final JPopupMenu jPopupMenu; private final JMenu jMenu; private final JComponent component; public MenuContainer(JPopupMenu jPopupMenu) { this.jPopupMenu = jPopupMenu; this.jMenu = null; this.component = jPopupMenu; } public MenuContainer(JMenu jMenu) { this.jPopupMenu = null; this.jMenu = jMenu; this.component = jMenu; } private int getComponentIndex(JMenuItem item) { if (jPopupMenu != null) { return jPopupMenu.getComponentIndex(item); } else { int ncomponents = jMenu.getComponentCount(); Component[] components = jMenu.getComponents(); for (int i = 0 ; i < ncomponents ; i++) { Component comp = components[i]; if (comp == item) return i; } return -1; } } private void setPreferredSize(Dimension preferredSize) { component.setPreferredSize(preferredSize); } private void removeAll() { component.removeAll(); } private void add(Component menuItem) { component.add(menuItem); } private Dimension getPreferredSize() { return component.getPreferredSize(); } private Component[] getComponents() { if (jPopupMenu != null) { return jPopupMenu.getComponents(); } else { return jMenu.getMenuComponents(); } } private void addListener(MenuScrollListener menuListener, MouseScrollListener mouseListener) { if (jPopupMenu != null) { jPopupMenu.addPopupMenuListener(menuListener); jPopupMenu.addMouseWheelListener(mouseListener); } else { jMenu.addMenuListener(menuListener); JPopupMenu popup = jMenu.getPopupMenu(); if (popup != null) { popup.addMouseWheelListener(mouseListener); } } } private void removeListener(MenuScrollListener menuListener, MouseScrollListener mouseListener) { if (jPopupMenu != null) { jPopupMenu.removePopupMenuListener(menuListener); jPopupMenu.removeMouseWheelListener(mouseListener); } else { jMenu.removeMenuListener(menuListener); JPopupMenu popup = jMenu.getPopupMenu(); if (popup != null) { popup.removeMouseWheelListener(mouseListener); } } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/NativeUtil.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import com.sun.jna.Native; import com.sun.jna.Platform; import com.sun.jna.platform.win32.WinDef.HWND; import static com.sun.jna.platform.win32.WinUser.SW_RESTORE; import static com.sun.jna.platform.win32.WinUser.SW_SHOWMINIMIZED; import com.sun.jna.platform.win32.WinUser.WINDOWPLACEMENT; import com.sun.jna.win32.StdCallLibrary; import java.io.IOException; public class NativeUtil { interface User32 extends StdCallLibrary { //FindWindowA: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-findwindowa HWND FindWindowA(String className, String windowName); //ShowWindow: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow boolean ShowWindow(HWND hWnd, int command); //SetForegroundWindow: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setforegroundwindow boolean SetForegroundWindow(HWND hWnd); //GetWindowPlacement: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowplacement //WINDOWPLACEMENT: https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-windowplacement boolean GetWindowPlacement(HWND hWnd, WINDOWPLACEMENT lpwndpl); } public static boolean focusEveOnline(String characterName) { final String windowName = "EVE - " + characterName; if (Platform.isWindows()) { final User32 user32 = Native.load("User32.dll", User32.class); HWND window = user32.FindWindowA(null, windowName); WINDOWPLACEMENT windowPlacement = new WINDOWPLACEMENT(); user32.GetWindowPlacement(window, windowPlacement); if (windowPlacement.showCmd == SW_SHOWMINIMIZED) { user32.ShowWindow(window, SW_RESTORE); } else { user32.SetForegroundWindow(window); } } else if (Platform.isLinux()) { try { Runtime runtime = Runtime.getRuntime(); String[] args = { "wmctrl", "-a", windowName}; runtime.exec(args); return true; } catch (IOException ex) { return false; } } else if (Platform.isMac()) { try { Runtime runtime = Runtime.getRuntime(); String[] args = { "osascript", "-e", "tell app \"" + windowName + "\" to activate" }; runtime.exec(args); return true; } catch (IOException ex) { return false; } } return false; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/StringComparators.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import java.util.Comparator; public class StringComparators { /** * //null compatible - contrary to String.CASE_INSENSITIVE_ORDER and GlazedLists.caseInsensitiveComparator() */ public static final Comparator CASE_INSENSITIVE = new CaseInsensitiveComparator(); /** * null compatible toString() comparator */ public static final Comparator TO_STRING = new ToStringComparator(); private static class CaseInsensitiveComparator implements Comparator { private CaseInsensitiveComparator() { } @Override public int compare(String o1, String o2) { if (o1 != null && o2 != null) { return o1.compareToIgnoreCase(o2); } // compare nulls if (o1 == null) { if (o2 == null) { return 0; } return -1; } else { return 1; } } } private static class ToStringComparator implements Comparator { private ToStringComparator() { } @Override public int compare(Object o1, Object o2) { if (o1 != null && o2 != null) { return o1.toString().compareToIgnoreCase(o2.toString()); } // compare nulls if (o1 == null) { if (o2 == null) { return 0; } return -1; } else { return 1; } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/TextImport.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog.SimpleTextImport; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog.TextReturn; import net.nikr.eve.jeveasset.i18n.GuiShared; public class TextImport & SimpleTextImport> { private final Program program; private final String toolName; private final JTextDialog jTextDialog; public TextImport(Program program, String toolName) { this.program = program; this.toolName = toolName; jTextDialog = new JTextDialog(program.getMainWindow().getFrame()); } public void importText(String text, T[] types, T selected, TextImportHandler handler) { //Get string from clipboard TextReturn textReturn = jTextDialog.importText(text, types, selected); String importText = textReturn.getText(); T importType = textReturn.getType(); if (importType != null) { Settings.lock("Import (" + toolName + ")"); Settings.get().putImportSettings(toolName, importType); Settings.unlock("Import (" + toolName + ")"); program.saveSettings("Import (" + toolName + ")"); } if (importText == null || importType == null) { return; //Cancelled } //Validate Input importText = importText.trim(); if (importText.isEmpty()) { //Empty sting JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), GuiShared.get().textEmpty(), GuiShared.get().textImport(), JOptionPane.PLAIN_MESSAGE); return; } handler.addItems(textReturn); } public static interface TextImportHandler { public void addItems(TextReturn textReturn); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/TextManager.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import com.sun.jna.Platform; import java.awt.Component; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.KeyStroke; import javax.swing.event.UndoableEditListener; import javax.swing.text.AbstractDocument; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.CompoundUndoManager; import net.nikr.eve.jeveasset.i18n.GuiShared; public final class TextManager { private enum CopyPopupAction { CUT, COPY, PASTE } private final JTextComponent component; private final JPopupMenu jPopupMenu; private final JMenuItem jCut; private final JMenuItem jCopy; private final JMenuItem jPaste; private final JMenuItem jUndo; private final JMenuItem jRedo; public static void installAll(final Container container) { for (Component component : container.getComponents()) { if (component instanceof Container) { installAll((Container) component); } if (component instanceof JTextComponent) { installTextComponent((JTextComponent) component); } } } public static void installTextComponent(final JTextComponent component) { //Make sure this component does not already have a UndoManager Document document = component.getDocument(); if (document instanceof AbstractDocument) { AbstractDocument abstractDocument = (AbstractDocument) document; for (UndoableEditListener editListener : abstractDocument.getUndoableEditListeners()) { if (editListener.getClass().equals(CompoundUndoManager.class)) { CompoundUndoManager undoManager = (CompoundUndoManager) editListener; undoManager.reset(); return; //already installed } } } new TextManager(component); } private TextManager(final JTextComponent component) { this.component = component; ListenerClass listener = new ListenerClass(); component.addMouseListener(listener); jPopupMenu = new JPopupMenu(); jCut = new JMenuItem(GuiShared.get().cut()); jCut.setIcon(Images.EDIT_CUT.getIcon()); if (Platform.isMac()) { jCut.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.META_DOWN_MASK)); } else { jCut.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_DOWN_MASK)); } jCut.setActionCommand(CopyPopupAction.CUT.name()); jCut.addActionListener(listener); jCopy = new JMenuItem(GuiShared.get().copy()); if (Platform.isMac()) { jCopy.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.META_DOWN_MASK)); } else { jCopy.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK)); } jCopy.setIcon(Images.EDIT_COPY.getIcon()); jCopy.setActionCommand(CopyPopupAction.COPY.name()); jCopy.addActionListener(listener); jPaste = new JMenuItem(GuiShared.get().paste()); jPaste.setIcon(Images.EDIT_PASTE.getIcon()); if (Platform.isMac()) { jPaste.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.META_DOWN_MASK)); } else { jPaste.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK)); } jPaste.setActionCommand(CopyPopupAction.PASTE.name()); jPaste.addActionListener(listener); CompoundUndoManager undoManager = new CompoundUndoManager(component); jUndo = new JMenuItem(undoManager.getUndoAction()); jUndo.setIcon(Images.EDIT_UNDO.getIcon()); jRedo = new JMenuItem(undoManager.getRedoAction()); jRedo.setIcon(Images.EDIT_REDO.getIcon()); } private void showPopupMenu(final MouseEvent e) { if (!component.isFocusable()) { //Don't show anything for unfocusable components return; } if (!component.hasFocus()) { component.requestFocus(); } jPopupMenu.removeAll(); String s = component.getSelectedText(); boolean canCopy = true; if (s == null) { canCopy = false; } else if (s.length() == 0) { canCopy = false; } if (component.isEditable()) { jCut.setEnabled(canCopy); jPopupMenu.add(jCut); } jCopy.setEnabled(canCopy); jPopupMenu.add(jCopy); if (component.isEditable()) { jPopupMenu.add(jPaste); jPopupMenu.addSeparator(); jPopupMenu.add(jUndo); jPopupMenu.add(jRedo); } jPopupMenu.show(e.getComponent(), e.getX(), e.getY()); } private class ListenerClass implements MouseListener, ActionListener { @Override public void mouseClicked(final MouseEvent e) { if (e.isPopupTrigger()) { showPopupMenu(e); } } @Override public void mousePressed(final MouseEvent e) { if (e.isPopupTrigger()) { showPopupMenu(e); } } @Override public void mouseReleased(final MouseEvent e) { if (e.isPopupTrigger()) { showPopupMenu(e); } } @Override public void mouseEntered(final MouseEvent e) { } @Override public void mouseExited(final MouseEvent e) { } @Override public void actionPerformed(final ActionEvent e) { if (CopyPopupAction.CUT.name().equals(e.getActionCommand())) { CopyHandler.cut(component); } if (CopyPopupAction.COPY.name().equals(e.getActionCommand())) { CopyHandler.toClipboard(component.getSelectedText()); } if (CopyPopupAction.PASTE.name().equals(e.getActionCommand())) { CopyHandler.paste(component); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/TreeSelectDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import java.awt.Dimension; import javax.swing.GroupLayout.Alignment; import javax.swing.*; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; public class TreeSelectDialog extends JDialogCentered { //Form components private JDialog dialog; private JLabel leafFilterLabel; private JTextField leafFilterTextField; private JLabel filterInfoLabel; private JLabel filterInfoResultLabel; private JLabel selectedLeafLabel; private JLabel selectedLeafValueLabel; private JButton cancelButton; private JButton addButton; private JTree tree; private JScrollPane treeScrollPane; public TreeSelectDialog(final Program program, final String title) { super(program, title); dialog = getDialog(); dialog.setResizable(true); dialog.setMinimumSize(new Dimension(300, 400)); leafFilterLabel = new JLabel(); leafFilterTextField = new JTextField(); filterInfoLabel = new JLabel(); filterInfoResultLabel = new JLabel(); selectedLeafLabel = new JLabel(); selectedLeafValueLabel = new JLabel(); cancelButton = new JButton(); addButton = new JButton(); tree = new JTree(); treeScrollPane = new JScrollPane(tree); layoutComponents(); } // /** * @return the leafFilterLabel */ public JLabel getLeafFilterLabel() { return leafFilterLabel; } /** * @return the leafFilterTextField */ public JTextField getLeafFilterTextField() { return leafFilterTextField; } /** * @return the filterInfoLabel */ public JLabel getFilterInfoLabel() { return filterInfoLabel; } /** * @return the filterInfoResultLabel */ public JLabel getFilterInfoResultLabel() { return filterInfoResultLabel; } /** * @return the selectedLeafLabel */ public JLabel getSelectedLeafLabel() { return selectedLeafLabel; } /** * @return the selectedLeafValueLabel */ public JLabel getSelectedLeafValueLabel() { return selectedLeafValueLabel; } /** * @return the cancelButton */ public JButton getCancelButton() { return cancelButton; } /** * @return the addButton */ public JButton getAddButton() { return addButton; } /** * @return the tree */ public JTree getTree() { return tree; } // private void layoutComponents() { layout.setHorizontalGroup( layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addComponent(getLeafFilterLabel()) .addComponent(getLeafFilterTextField()) ) .addGroup(layout.createSequentialGroup() .addComponent(getFilterInfoLabel()) .addComponent(getFilterInfoResultLabel()) ) .addComponent(treeScrollPane) .addGroup(layout.createSequentialGroup() .addComponent(getSelectedLeafLabel()) .addComponent(getSelectedLeafValueLabel()) ) .addGroup(layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) .addComponent(getAddButton()) .addComponent(getCancelButton()) ) ); layout.linkSize(SwingConstants.HORIZONTAL, getAddButton(), getCancelButton()); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup(Alignment.BASELINE) .addComponent(getLeafFilterLabel()) .addComponent(getLeafFilterTextField()) ) .addGroup(layout.createParallelGroup(Alignment.BASELINE) .addComponent(getFilterInfoLabel()) .addComponent(getFilterInfoResultLabel()) ) .addComponent(treeScrollPane) .addGroup(layout.createParallelGroup(Alignment.BASELINE) .addComponent(getSelectedLeafLabel()) .addComponent(getSelectedLeafValueLabel())) .addGroup(layout.createParallelGroup(Alignment.BASELINE) .addComponent(getAddButton()) .addComponent(getCancelButton()) ) ); } @Override protected JComponent getDefaultFocus() { return null; } @Override protected JButton getDefaultButton() { return null; } @Override protected void windowShown() { } @Override protected void save() { } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/Updatable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import java.util.Date; import net.nikr.eve.jeveasset.CliOptions; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateDialog.Updates; public class Updatable { private final Program program; public Updatable(final Program program) { this.program = program; } public boolean isUpdatable() { if (isUpdatable(program.getPriceDataGetter().getNextUpdate())) { return true; } for (OwnerType owner : program.getOwnerTypes()) { if (!owner.isShowOwner() || owner.isInvalid() || owner.isExpired()) { continue; } for (Updates update : Updates.values()) { if (update.isEnabled(owner) && isUpdatable(update.getNextUpdate(owner))) { return true; } } } return false; } public static boolean isUpdatable(Date nextUpdate) { Date now = Settings.getNow(); return nextUpdate != null && ((now.after(nextUpdate) || now.equals(nextUpdate) || CliOptions.get().isForceUpdate()) && !CliOptions.get().isForceNoUpdate()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/CheckBoxNode.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.util.ArrayList; import java.util.List; import net.nikr.eve.jeveasset.i18n.TabsTracker; public class CheckBoxNode implements Comparable{ private final String nodeId; private final String nodeName; private final String match; private final List children = new ArrayList<>(); private CheckBoxNode parent; private int childrenSelected = 0; private int childrenShown = 0; private boolean selected; private boolean shown; public CheckBoxNode(CheckBoxNode parent, CheckBoxNode clone) { this(parent, clone.nodeId, clone.nodeName, clone.selected); } public CheckBoxNode(CheckBoxNode parent, String nodeId, String nodeName, boolean selected) { this.nodeId = nodeId; this.nodeName = nodeName; this.match = nodeName.toLowerCase(); this.selected = selected; this.parent = parent; this.shown = true; if (parent != null) { parent.addChild(this); } } public boolean isShown() { return shown; } public void hide() { setShown(false); } public void show() { updateShown(true); } public boolean matches(String text) { if (match.contains(text)) { //Matches Self (include everything) shownParents(); updateShown(true); shownChildren(); return true; } if (matchesParent(text)) { //Matches Parent (include everything) shownParents(); updateShown(true); shownChildren(); return true; } if (matchesChildren(text)) { //Matches Child (include self and parent) shownParents(); updateShown(true); return true; } return false; } public CheckBoxNode getParent() { return parent; } public boolean isParent() { return !children.isEmpty(); } private boolean isOther() { return this.nodeName.equals(TabsTracker.get().other()); } public boolean isSelected() { return selected; } public boolean setSelected(boolean newValue) { boolean update = selected != newValue; if (!update) { //Nothing changed -> do nothing return false; } selected = newValue; if (isParent()) { //If have children -> Update Tree update = selectionToChildren(newValue) || update; } if (selected != newValue) { throw new RuntimeException(); } if (parent != null && isShown()) { if (selected) { parent.childSelected(); } else { parent.childDeselected(); } parent.updateSelection(); } return update; } public String getNodeID() { return nodeId; } public String getNodeName() { return nodeName; } private void addChild(CheckBoxNode child) { children.add(child); if (child.isSelected()) { childSelected(); } if (child.isShown()) { childShown(); } updateSelection(); } private void childShown() { childrenShown++; } private void childHidden() { childrenShown--; } private void childSelected() { childrenSelected++; } private void childDeselected() { childrenSelected--; } private boolean setShown(boolean newValue) { boolean updated = this.shown != newValue; this.shown = newValue; if (parent != null && updated) { if (shown) { //If shown: add shown and update parent.childShown(); if (selected) { //If selected -> add selection parent.childSelected(); } } else { //Remove parent.childHidden(); if (selected) { //If selected -> remove selection parent.childDeselected(); } } } return updated; } private void updateShown(boolean newValue) { if (setShown(newValue) && parent != null) { parent.updateSelection(); } } private boolean matchesParent(String text) { if (parent != null) { if (parent.match.contains(text)) { return true; } if (parent.matchesParent(text)) { return true; } } return false; } private boolean matchesChildren(String text) { for (CheckBoxNode node : children) { if (node.match.contains(text)) { return true; } if (node.matchesChildren(text)) { return true; } } return false; } private void shownParents() { if (parent != null) { parent.shownParents(); parent.updateShown(true); } } private void shownChildren() { for (CheckBoxNode child : children) { child.updateShown(true); child.shownChildren(); } } private boolean updateSelection() { if (!isParent()) { return false; } boolean oldValue = selected; selected = childrenSelected == childrenShown; selected = childrenSelected == childrenShown; boolean updated = oldValue != selected; if (updated && parent != null) { //Value changed -> Update Tree if (selected) { parent.childSelected(); } else { parent.childDeselected(); } updated = parent.updateSelection() || updated; } return updated; } private boolean selectionToChildren(boolean newValue) { boolean updated = false; for (CheckBoxNode node : children) { if (!node.isShown()) { continue; } if (node.isSelected() != newValue) { node.selected = newValue; if (newValue) { childSelected(); } else { childDeselected(); } updated = true; } node.selectionToChildren(newValue); } if (newValue) { if (childrenShown != childrenSelected) { throw new RuntimeException(); } } else { if (childrenSelected != 0) { throw new RuntimeException(); } } return updated; } @Override public String toString() { return nodeName; } @Override public int compareTo(CheckBoxNode o) { if (this.isOther() && o.isOther()) { return nodeId.compareToIgnoreCase(o.nodeId); } else if (this.isOther()) { return 1; } else if (o.isOther()) { return -1; } else { return nodeId.compareToIgnoreCase(o.nodeId); } } @Override public int hashCode() { int hash = 7; hash = 47 * hash + (this.nodeId != null ? this.nodeId.hashCode() : 0); hash = 47 * hash + (this.nodeName != null ? this.nodeName.hashCode() : 0); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final CheckBoxNode other = (CheckBoxNode) obj; if ((this.nodeId == null) ? (other.nodeId != null) : !this.nodeId.equals(other.nodeId)) { return false; } if ((this.nodeName == null) ? (other.nodeName != null) : !this.nodeName.equals(other.nodeName)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/CheckBoxNodeEditor.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import ca.odell.glazedlists.TreeList; import java.awt.Component; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseEvent; import java.util.EventObject; import javax.swing.AbstractCellEditor; import javax.swing.JCheckBox; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreeCellEditor; import javax.swing.tree.TreePath; public class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor { private final CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer(); private final JTree tree; public CheckBoxNodeEditor(JTree tree) { this.tree = tree; } private CheckBoxNode getCheckBoxNode() { return getCheckBoxNode(tree.getSelectionPath()); } private CheckBoxNode getCheckBoxNode(TreePath path) { Object value = path.getLastPathComponent(); Object userObject = null; if (value != null && value instanceof DefaultMutableTreeNode) { userObject = ((DefaultMutableTreeNode) value).getUserObject(); } if (value != null && value instanceof TreeList.Node) { userObject = ((TreeList.Node) value).getElement(); } if (userObject != null && userObject instanceof CheckBoxNode) { return (CheckBoxNode) userObject; } return null; } @Override public Object getCellEditorValue() { return getCheckBoxNode(); } @Override public boolean isCellEditable(EventObject event) { if (event instanceof MouseEvent) { MouseEvent mouseEvent = (MouseEvent) event; TreePath path = tree.getPathForLocation(mouseEvent.getX(), mouseEvent.getY()); return getCheckBoxNode(path) != null; } return false; } @Override public Component getTreeCellEditorComponent(final JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row) { Component editor = renderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true); // editor always selected / focused if (editor instanceof JCheckBox) { final JCheckBox checkBox = (JCheckBox) editor; checkBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (stopCellEditing()) { fireEditingStopped(); } CheckBoxNode checkBoxNode = getCheckBoxNode(); if (checkBoxNode != null) { boolean updated = checkBoxNode.setSelected(checkBox.isSelected()); if (updated) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { tree.repaint(); } }); } } checkBox.removeItemListener(this); } }); } return editor; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/CheckBoxNodeRenderer.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import ca.odell.glazedlists.TreeList; import java.awt.Color; import java.awt.Component; import java.awt.Font; import javax.swing.JCheckBox; import javax.swing.JTree; import javax.swing.UIManager; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreeCellRenderer; public class CheckBoxNodeRenderer implements TreeCellRenderer { private final JCheckBox leafRenderer = new JCheckBox(); private final Color selectionBorderColor, selectionForeground, selectionBackground, textForeground, textBackground; protected JCheckBox getLeafRenderer() { return leafRenderer; } public CheckBoxNodeRenderer() { Font fontValue; fontValue = UIManager.getFont("Tree.font"); if (fontValue != null) { leafRenderer.setFont(fontValue); } Boolean booleanValue = (Boolean) UIManager.get("Tree.drawsFocusBorderAroundIcon"); leafRenderer.setFocusPainted(booleanValue != null && booleanValue); selectionBorderColor = UIManager.getColor("Tree.selectionBorderColor"); selectionForeground = UIManager.getColor("Tree.selectionForeground"); selectionBackground = UIManager.getColor("Tree.selectionBackground"); textForeground = UIManager.getColor("Tree.textForeground"); textBackground = UIManager.getColor("Tree.textBackground"); } @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { String stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, false); leafRenderer.setText(stringValue); leafRenderer.setSelected(false); leafRenderer.setEnabled(tree.isEnabled()); if (selected) { leafRenderer.setForeground(selectionForeground); leafRenderer.setBackground(selectionBackground); } else { leafRenderer.setForeground(textForeground); leafRenderer.setBackground(textBackground); } Object userObject = null; if (value != null && value instanceof DefaultMutableTreeNode) { userObject = ((DefaultMutableTreeNode) value).getUserObject(); } if (value != null && value instanceof TreeList.Node) { userObject = ((TreeList.Node) value).getElement(); } if (userObject != null && userObject instanceof CheckBoxNode) { final CheckBoxNode node = (CheckBoxNode) userObject; leafRenderer.setText(node.getNodeName()); leafRenderer.setSelected(node.isSelected()); } return leafRenderer; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/CompoundUndoManager.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * Original code from https://tips4java.wordpress.com/2008/10/27/compound-undo-manager/ * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import com.sun.jna.Platform; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.UndoableEditEvent; import javax.swing.event.UndoableEditListener; import javax.swing.text.AbstractDocument; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; import javax.swing.undo.CompoundEdit; import javax.swing.undo.UndoManager; import javax.swing.undo.UndoableEdit; /* ** This class will merge individual edits into a single larger edit. ** That is, characters entered sequentially will be grouped together and ** undone as a group. Any attribute changes will be considered as part ** of the group and will therefore be undone when the group is undone. */ public class CompoundUndoManager extends UndoManager implements UndoableEditListener, DocumentListener { private final UndoManager undoManager; private final JTextComponent textComponent; private final UndoAction undoAction; private final RedoAction redoAction; private CompoundEdit compoundEdit; // These fields are used to help determine whether the edit is an // incremental edit. The offset and length should increase by 1 for // each character added or decrease by 1 for each character removed. private int lastOffset; private int lastLength; public CompoundUndoManager(JTextComponent component) { this.textComponent = component; undoManager = this; undoAction = new UndoAction(); redoAction = new RedoAction(); component.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK), "undoKeystroke"); component.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.META_DOWN_MASK), "undoKeystroke"); component.getActionMap().put("undoKeystroke", undoAction); component.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK), "redoKeystroke"); component.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.META_DOWN_MASK + InputEvent.SHIFT_DOWN_MASK), "redoKeystroke"); component.getActionMap().put("redoKeystroke", redoAction); component.addPropertyChangeListener("document", new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { Object oldValue = evt.getOldValue(); if (oldValue != null && oldValue instanceof Document) { //Remove old Document document = (Document) oldValue; document.removeUndoableEditListener(undoManager); } Object newValue = evt.getNewValue(); if (newValue != null && newValue instanceof Document) { //Remove old Document document = (Document) newValue; document.addUndoableEditListener(undoManager); //New document } } }); component.getDocument().addUndoableEditListener(this); //component.setBorder(BorderFactory.createLineBorder(Color.GREEN, 1)); } public void reset() { int limit = getLimit(); setLimit(0); setLimit(limit); compoundEdit = null; lastOffset = 0; lastLength = 0; undoAction.updateUndoState(); redoAction.updateRedoState(); } /* ** Add a DocumentLister before the undo is done so we can position ** the Caret correctly as each edit is undone. */ @Override public synchronized void undo() { textComponent.getDocument().addDocumentListener(this); super.undo(); textComponent.getDocument().removeDocumentListener(this); } /* ** Add a DocumentLister before the redo is done so we can position ** the Caret correctly as each edit is redone. */ @Override public synchronized void redo() { textComponent.getDocument().addDocumentListener(this); super.redo(); textComponent.getDocument().removeDocumentListener(this); } /* ** Whenever an UndoableEdit happens the edit will either be absorbed ** by the current compound edit or a new compound edit will be started */ @Override public void undoableEditHappened(UndoableEditEvent e) { // Start a new compound edit if (compoundEdit == null) { compoundEdit = startCompoundEdit(e.getEdit()); return; } int offsetChange = textComponent.getCaretPosition() - lastOffset; int lengthChange = textComponent.getDocument().getLength() - lastLength; // Check for an attribute change UndoableEdit edit = e.getEdit(); if (edit instanceof AbstractDocument.DefaultDocumentEvent) { AbstractDocument.DefaultDocumentEvent event = (AbstractDocument.DefaultDocumentEvent) e.getEdit(); if (event.getType().equals(DocumentEvent.EventType.CHANGE)) { if (offsetChange == 0) { compoundEdit.addEdit(e.getEdit()); return; } } } // Check for an incremental edit or backspace. // The Change in Caret position and Document length should both be // either 1 or -1. if (offsetChange == lengthChange && Math.abs(offsetChange) == 1) { compoundEdit.addEdit(e.getEdit()); lastOffset = textComponent.getCaretPosition(); lastLength = textComponent.getDocument().getLength(); return; } // Not incremental edit, end previous edit and start a new one compoundEdit.end(); compoundEdit = startCompoundEdit(e.getEdit()); } /* ** Each CompoundEdit will store a group of related incremental edits ** (ie. each character typed or backspaced is an incremental edit) */ private CompoundEdit startCompoundEdit(UndoableEdit anEdit) { // Track Caret and Document information of this compound edit lastOffset = textComponent.getCaretPosition(); lastLength = textComponent.getDocument().getLength(); // The compound edit is used to store incremental edits compoundEdit = new MyCompoundEdit(); compoundEdit.addEdit(anEdit); // The compound edit is added to the UndoManager. All incremental // edits stored in the compound edit will be undone/redone at once addEdit(compoundEdit); undoAction.updateUndoState(); redoAction.updateRedoState(); return compoundEdit; } /* * The Action to Undo changes to the Document. * The state of the Action is managed by the CompoundUndoManager */ public Action getUndoAction() { return undoAction; } /* * The Action to Redo changes to the Document. * The state of the Action is managed by the CompoundUndoManager */ public Action getRedoAction() { return redoAction; } // // Implement DocumentListener // /* * Updates to the Document as a result of Undo/Redo will cause the * Caret to be repositioned */ @Override public void insertUpdate(final DocumentEvent e) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { int offset = e.getOffset() + e.getLength(); offset = Math.min(offset, textComponent.getDocument().getLength()); textComponent.setCaretPosition(offset); } }); } @Override public void removeUpdate(DocumentEvent e) { textComponent.setCaretPosition(e.getOffset()); } @Override public void changedUpdate(DocumentEvent e) { } class MyCompoundEdit extends CompoundEdit { @Override public boolean isInProgress() { // in order for the canUndo() and canRedo() methods to work // assume that the compound edit is never in progress return false; } @Override public void undo() throws CannotUndoException { // End the edit so future edits don't get absorbed by this edit if (compoundEdit != null) { compoundEdit.end(); } super.undo(); // Always start a new compound edit after an undo compoundEdit = null; } } /* * Perform the Undo and update the state of the undo/redo Actions */ class UndoAction extends AbstractAction { public UndoAction() { putValue(Action.NAME, "Undo"); putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME)); putValue(Action.MNEMONIC_KEY, KeyEvent.VK_U); if (Platform.isMac()) { putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.META_DOWN_MASK)); } else { putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK)); } setEnabled(false); } @Override public void actionPerformed(ActionEvent e) { try { undoManager.undo(); textComponent.requestFocusInWindow(); } catch (CannotUndoException ex) { } updateUndoState(); redoAction.updateRedoState(); } private void updateUndoState() { setEnabled(undoManager.canUndo()); } } /* * Perform the Redo and update the state of the undo/redo Actions */ class RedoAction extends AbstractAction { public RedoAction() { putValue(Action.NAME, "Redo"); putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME)); putValue(Action.MNEMONIC_KEY, KeyEvent.VK_R); if (Platform.isMac()) { putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.META_DOWN_MASK + InputEvent.SHIFT_DOWN_MASK)); } else { putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK)); } setEnabled(false); } @Override public void actionPerformed(ActionEvent e) { try { undoManager.redo(); textComponent.requestFocusInWindow(); } catch (CannotRedoException ex) { } updateRedoState(); undoAction.updateUndoState(); } protected void updateRedoState() { setEnabled(undoManager.canRedo()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JAutoCompleteDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.GlazedLists; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.TextFilterator; import ca.odell.glazedlists.matchers.TextMatcherEditor; import ca.odell.glazedlists.swing.AutoCompleteSupport; import java.awt.Image; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collection; import java.util.Comparator; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.EventModels.ItemFilterator; import net.nikr.eve.jeveasset.gui.shared.table.EventModels.LocationFilterator; import net.nikr.eve.jeveasset.gui.shared.table.EventModels.SolarSystemFilterator; import net.nikr.eve.jeveasset.gui.shared.table.EventModels.StringFilterator; import net.nikr.eve.jeveasset.gui.shared.table.EventModels.ViewFilterator; import net.nikr.eve.jeveasset.gui.shared.table.View; import net.nikr.eve.jeveasset.gui.tabs.routing.SolarSystem; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JAutoCompleteDialog extends JDialogCentered { public static final AutoCompleteOptions STRING_OPTIONS = new AutoCompleteOptions() { @Override public Comparator getComparator() { return StringComparators.CASE_INSENSITIVE; } @Override public TextFilterator getFilterator() { return new StringFilterator(); } @Override public String getValue(Object object) { if (object instanceof String) { return (String) object; } else { return null; } } @Override public boolean isEmpty(String t) { return t.isEmpty(); } }; public static final AutoCompleteOptions LOCATION_OPTIONS = new AutoCompleteOptions() { @Override public Comparator getComparator() { return GlazedLists.comparableComparator(); } @Override public TextFilterator getFilterator() { return new LocationFilterator(); } @Override public MyLocation getValue(Object object) { if (object instanceof MyLocation) { return (MyLocation) object; } else { return null; } } @Override public boolean isEmpty(MyLocation t) { return false; } }; public static final AutoCompleteOptions VIEW_OPTIONS = new AutoCompleteOptions() { @Override public Comparator getComparator() { return GlazedLists.comparableComparator(); } @Override public TextFilterator getFilterator() { return new ViewFilterator(); } @Override public View getValue(Object object) { if (object instanceof View) { return (View) object; } else if (object instanceof String) { return new View((String) object); } else { return null; } } @Override public boolean isEmpty(View t) { return t.getName().isEmpty(); } }; public static final AutoCompleteOptions ITEM_OPTIONS = new AutoCompleteOptions() { @Override public Comparator getComparator() { return GlazedLists.comparableComparator(); } @Override public TextFilterator getFilterator() { return new ItemFilterator(); } @Override public Item getValue(Object object) { if (object instanceof Item) { return (Item) object; } else { return null; } } @Override public boolean isEmpty(Item t) { return false; } }; public static final AutoCompleteOptions SOLAR_SYSTEM_OPTIONS = new AutoCompleteOptions() { @Override public Comparator getComparator() { return new SystemComparator(); } @Override public TextFilterator getFilterator() { return new SolarSystemFilterator(); } @Override public SolarSystem getValue(Object object) { if (object instanceof SolarSystem) { return (SolarSystem) object; } else { return null; } } @Override public boolean isEmpty(SolarSystem t) { return false; } }; private static class SystemComparator implements Comparator { @Override public int compare(SolarSystem o1, SolarSystem o2) { return o1.getName().compareToIgnoreCase(o2.getName()); } } private enum AutoCompleteAction { OK, CANCEL } private final EventList eventList; private final AutoCompleteSupport autoComplete; private final JComboBox jItems; private final JButton jOK; private final AutoCompleteOptions autoCompleteOptions; private final boolean strict; private final boolean askOverwrite; private T value; public JAutoCompleteDialog(Program program, String title, Image image, String msg, boolean strict, AutoCompleteOptions autoCompleteOptions) { this(program, title, program.getMainWindow().getFrame(), image, msg, strict, true, autoCompleteOptions); } public JAutoCompleteDialog(Program program, String title, Window window, Image image, String msg, boolean strict, AutoCompleteOptions autoCompleteOptions) { this(program, title, window, image, msg, strict, true, autoCompleteOptions); } public JAutoCompleteDialog(Program program, String title, Image image, String msg, boolean strict, boolean askOverwrite, AutoCompleteOptions autoCompleteOptions) { this(program, title, program.getMainWindow().getFrame(), image, msg, strict, askOverwrite, autoCompleteOptions); } public JAutoCompleteDialog(Program program, String title, Window window, Image image, String msg, boolean strict, boolean askOverwrite, AutoCompleteOptions autoCompleteOptions) { super(program, title, window, image); this.strict = strict; this.askOverwrite = askOverwrite; this.autoCompleteOptions = autoCompleteOptions; ListenerClass listener = new ListenerClass(); JLabel jText = new JLabel(); if (msg != null) { jText.setText(msg); } else { jText.setVisible(false); } jItems = new JComboBox<>(); eventList = EventListManager.create(); eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList, autoCompleteOptions.getComparator()); eventList.getReadWriteLock().readLock().unlock(); autoComplete = AutoCompleteSupport.install(jItems, EventModels.createSwingThreadProxyList(sortedList), autoCompleteOptions.getFilterator()); if (!strict) { autoComplete.setFilterMode(TextMatcherEditor.CONTAINS); } autoComplete.setStrict(strict); jOK = new JButton(GuiShared.get().ok()); jOK.setActionCommand(AutoCompleteAction.OK.name()); jOK.addActionListener(listener); JButton jCancel = new JButton(GuiShared.get().cancel()); jCancel.setActionCommand(AutoCompleteAction.CANCEL.name()); jCancel.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jText) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jItems, 220, 220, 220) .addGroup(layout.createSequentialGroup() .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jText, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jItems, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } public final void updateData(Collection list) { boolean same = false; try { eventList.getReadWriteLock().readLock().lock(); same = eventList.equals(list); } finally { eventList.getReadWriteLock().readLock().unlock(); } if (!same) { try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(list); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } } public T show(T t) { jItems.getModel().setSelectedItem(t); value = null; setVisible(true); return value; } public T show() { autoComplete.removeFirstItem(); if (jItems.getModel().getSize() > 0) { jItems.setSelectedIndex(0); } if (!strict) { //No effect when strict (except a beep) jItems.getModel().setSelectedItem(""); } value = null; setVisible(true); return value; } protected boolean valid(T value) { if (value == null || autoCompleteOptions.isEmpty(value)) { JOptionPane.showMessageDialog(getDialog(), GuiShared.get().invalidMsg(), GuiShared.get().invalidTitle(), JOptionPane.PLAIN_MESSAGE); return false; } if (strict || !askOverwrite) { return true; } else { if (EventListManager.contains(eventList, value)) { int nReturn = JOptionPane.showConfirmDialog(getDialog(), GuiShared.get().overwrite(), GuiShared.get().overwriteTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE); if (nReturn == JOptionPane.NO_OPTION) { //Overwrite cancelled return false; } } return true; } } @Override protected JComponent getDefaultFocus() { return jItems; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { } @Override protected void save() { value = autoCompleteOptions.getValue(jItems.getSelectedItem()); if (valid(value)) { setVisible(false); } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (AutoCompleteAction.OK.name().equals(e.getActionCommand())) { save(); } if (AutoCompleteAction.CANCEL.name().equals(e.getActionCommand())) { value = null; setVisible(false); } } } public static interface AutoCompleteOptions { public Comparator getComparator(); public TextFilterator getFilterator(); public T getValue(Object object); public boolean isEmpty(T t); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JButtonComparable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import com.formdev.flatlaf.ui.FlatButtonBorder; import java.awt.Color; import java.awt.Component; import java.util.Objects; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.border.Border; public class JButtonComparable extends JButton implements Comparable { private boolean lock = false; public JButtonComparable() { this(null, null); } public JButtonComparable(Icon icon) { this(null, icon); } public JButtonComparable(String text) { this(text, null); } public JButtonComparable(String text, Icon icon) { super(text, icon); updateBorder(); lock(); } @Override public void setBackground(Color bg) { if (lock) { return; } super.setBackground(bg); } @Override public void setForeground(Color fg) { if (lock) { return; } super.setForeground(fg); } @Override public void setBorder(Border border) { if (lock) { return; } super.setBorder(border); } /** * Workaround for: https://github.com/JFormDesigner/FlatLaf/issues/331 */ private void updateBorder() { if (getBorder() instanceof FlatButtonBorder) { super.setBorder(new FlatButtonBorder() { @Override protected boolean isCellEditor(Component c) { return false; } }); } } private void lock() { this.lock = true; } @Override public int compareTo(Component o) { return 0; } @Override public String toString() { return getText(); } @Override public int hashCode() { int hash = 5; hash = 97 * hash + Objects.hashCode(this.getText()); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final JButtonComparable other = (JButtonComparable) obj; if (!Objects.equals(this.getText(), other.getText())) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JButtonNull.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.Component; import java.awt.Graphics; import javax.swing.JButton; public class JButtonNull extends JButton implements Comparable { public JButtonNull() { setBorderPainted(false); } @Override public int compareTo(Component o) { return 0; } @Override public void paintComponent(Graphics g) { g.setColor(getBackground()); g.fillRect(0, 0, getSize().width, getSize().height); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JCustomFileChooser.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.Component; import java.awt.HeadlessException; import java.io.File; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.UIManager; import javax.swing.filechooser.FileFilter; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.io.shared.FileUtil; public final class JCustomFileChooser { public static final int APPROVE_OPTION = JFileChooser.APPROVE_OPTION; private static OverwriteFileChooser FILE_CHOOSER = null; private List extensions; private File file = null; private boolean multiSelection = false; private int fileSelectionMode = JFileChooser.FILES_ONLY; private File currentDirectory = null; public JCustomFileChooser(String extension) { this(Collections.singletonList(extension)); } public JCustomFileChooser(List extensions) { this.extensions = extensions; if (FILE_CHOOSER == null) { //XXX - Workaround for https://bugs.openjdk.java.net/browse/JDK-8179014 UIManager.put("FileChooser.useSystemExtensionHiding", false); FILE_CHOOSER = new OverwriteFileChooser(); } } public void setSelectedFile(File file) { if (FILE_CHOOSER.getDialogType() != JFileChooser.OPEN_DIALOG && file != null) { String filename = file.getAbsolutePath(); if (filename.matches("(?i).*\\.\\w{0,4}$")) { //Already got a extension - remove it int end = filename.lastIndexOf("."); filename = filename.substring(0, end); } filename = filename + "." + extensions.get(0); file = new File(filename); } this.file = file; } private void loadSettings() { FILE_CHOOSER.setSelectedFile(file); FILE_CHOOSER.resetChoosableFileFilters(); FILE_CHOOSER.addChoosableFileFilter(new CustomFileFilter(extensions)); FILE_CHOOSER.setMultiSelectionEnabled(multiSelection); FILE_CHOOSER.setFileSelectionMode(fileSelectionMode); FILE_CHOOSER.setCurrentDirectory(currentDirectory); } public File getSelectedFile() { file = FILE_CHOOSER.getSelectedFile(); return file; } public int showDialog(Component parent, String approveButtonText) throws HeadlessException { loadSettings(); return FILE_CHOOSER.showDialog(parent, approveButtonText); } public int showSaveDialog(Component parent) throws HeadlessException { loadSettings(); return FILE_CHOOSER.showSaveDialog(parent); } public int showOpenDialog(Component parent) throws HeadlessException { loadSettings(); return FILE_CHOOSER.showOpenDialog(parent); } public void setExtension(String extension) { extensions = Collections.singletonList(extension); } public void setMultiSelectionEnabled(boolean b) { this.multiSelection = b; } public void setFileSelectionMode(int mode) { this.fileSelectionMode = mode; } public void setCurrentDirectory(File dir) { this.currentDirectory = dir; } public static class CustomFileFilter extends FileFilter { private final Set extensions = new HashSet<>(); private final String description; public CustomFileFilter(final List extensions) { StringBuilder builder = new StringBuilder(); boolean first = true; for (String extension : extensions) { if (first) { first = false; } else { builder.append("/"); } builder.append(extension.toUpperCase()); this.extensions.add(extension.toLowerCase()); } description = GuiShared.get().files(builder.toString()); } @Override public boolean accept(final File f) { if (f.isDirectory()) { return true; } String currentExtension = FileUtil.getExtension(f); return currentExtension != null && extensions.contains(currentExtension); } //The description of this filter @Override public String getDescription() { return description; } @Override public int hashCode() { int hash = 7; hash = 53 * hash + Objects.hashCode(this.extensions); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final CustomFileFilter other = (CustomFileFilter) obj; if (!Objects.equals(this.extensions, other.extensions)) { return false; } return true; } } private static class OverwriteFileChooser extends JFileChooser { private Component parent; public OverwriteFileChooser() { setAcceptAllFileFilterUsed(false); } @Override public int showDialog(Component parent, String approveButtonText) throws HeadlessException { this.parent = parent; return super.showDialog(parent, approveButtonText); } @Override public int showSaveDialog(Component parent) throws HeadlessException { this.parent = parent; return super.showSaveDialog(parent); } @Override public int showOpenDialog(Component parent) throws HeadlessException { this.parent = parent; return super.showOpenDialog(parent); } @Override public void approveSelection() { File selectedFile = this.getSelectedFile(); //Confirm Overwrite file if (getDialogType() != JFileChooser.OPEN_DIALOG && selectedFile != null && selectedFile.exists()) { int nReturn = JOptionPane.showConfirmDialog( parent, GuiShared.get().overwrite(), GuiShared.get().overwriteFile(), JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE ); if (nReturn == JOptionPane.NO_OPTION) { return; } } super.approveSelection(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JDateChooser.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import com.github.lgooddatepicker.components.DatePicker; import com.github.lgooddatepicker.components.DatePickerSettings; import com.github.lgooddatepicker.optionalusertools.DateChangeListener; import com.github.lgooddatepicker.zinternaltools.DateChangeEvent; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; import java.util.Locale; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JTextField; import javax.swing.SwingUtilities; import net.nikr.eve.jeveasset.data.settings.Colors; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.Formatter; public class JDateChooser extends DatePicker { public JDateChooser(boolean allowEmptyDates) { super(new DefaultDatePickerSettings(allowEmptyDates)); JTextField jTextField = getComponentDateTextField(); jTextField.setEditable(false); jTextField.setBorder(null); jTextField.setOpaque(false); jTextField.setBackground(Colors.COMPONENT_TRANSPARENT.getColor()); jTextField.setHorizontalAlignment(JTextField.CENTER); JButton jButton = getComponentToggleCalendarButton(); jButton.setIcon(Images.EDIT_DATE.getIcon()); jButton.setText(""); addDateChangeListener(new DateChangeListener() { @Override public void dateChanged(DateChangeEvent event) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { jTextField.setBackground(Colors.COMPONENT_TRANSPARENT.getColor()); } }); } }); } @Override public final JTextField getComponentDateTextField() { return super.getComponentDateTextField(); } @Override public final JButton getComponentToggleCalendarButton() { return super.getComponentToggleCalendarButton(); } public void setDate(Date date) { super.setDate(dateToLocalDate(date)); } public void clearDate() { super.setDate(null); } private LocalDate dateToLocalDate(Date date) { Instant instant = date.toInstant(); return LocalDateTime.ofInstant(instant, ZoneId.of("GMT")).toLocalDate(); } private static class DefaultDatePickerSettings extends DatePickerSettings { public DefaultDatePickerSettings(boolean allowEmptyDates) { super(Locale.ENGLISH); setAllowEmptyDates(allowEmptyDates); setFormatForDatesCommonEra(Formatter.COLUMN_DATE); setFormatForDatesBeforeCommonEra(Formatter.COLUMN_DATE); //Use UIManager default setColor(DatePickerSettings.DateArea.BackgroundOverallCalendarPanel, Colors.COMPONENT_BACKGROUND.getColor()); setColor(DatePickerSettings.DateArea.BackgroundClearLabel, Colors.BUTTON_BACKGROUND.getColor()); setColor(DatePickerSettings.DateArea.TextClearLabel, Colors.BUTTON_FOREGROUND.getColor()); setColor(DatePickerSettings.DateArea.BackgroundMonthAndYearMenuLabels, Colors.BUTTON_BACKGROUND.getColor()); setColor(DatePickerSettings.DateArea.TextMonthAndYearMenuLabels, Colors.BUTTON_FOREGROUND.getColor()); setColor(DatePickerSettings.DateArea.BackgroundTodayLabel, Colors.BUTTON_BACKGROUND.getColor()); setColor(DatePickerSettings.DateArea.TextTodayLabel, Colors.BUTTON_FOREGROUND.getColor()); setColor(DatePickerSettings.DateArea.DatePickerTextValidDate, new JLabel().getForeground()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JDefaultField.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import javax.swing.JTextField; public class JDefaultField extends JTextField { private String defaultValue; private boolean autoSelectAll; public JDefaultField(final String defaultValue) { this.defaultValue = defaultValue; autoSelectAll = false; ListenerClass listener = new ListenerClass(); addFocusListener(listener); } private void restoreDefault() { if (super.getText().isEmpty()) { super.setText(defaultValue); } } @Override public String getText() { restoreDefault(); return super.getText(); } @Override public void setText(final String t) { if (t.isEmpty()) { super.setText(defaultValue); } else { super.setText(t); } } public boolean isAutoSelectAll() { return autoSelectAll; } public void setAutoSelectAll(boolean autoSelectAll) { this.autoSelectAll = autoSelectAll; } private class ListenerClass implements FocusListener { @Override public void focusGained(final FocusEvent e) { if (autoSelectAll) { selectAll(); } } @Override public void focusLost(final FocusEvent e) { restoreDefault(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JDialogCentered.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.Component; import java.awt.Dimension; import java.awt.Image; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.WindowEvent; import java.awt.event.WindowFocusListener; import java.awt.event.WindowListener; import javax.swing.*; import javax.swing.text.DefaultEditorKit; import javax.swing.text.JTextComponent; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.shared.TextManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class JDialogCentered { private static final Logger LOG = LoggerFactory.getLogger(JDialogCentered.class); private enum DialogCenteredAction { OK, CANCEL } public static final int NO_RESTRICTIONS = 0; public static final int WORDS_ONLY = 1; public static final int INTEGERS_ONLY = 2; public static final int NUMBERS_ONLY = 3; protected Program program; protected Window parent; protected JPanel jPanel; protected GroupLayout layout; private JDialog dialog; private boolean firstActivating = false; private boolean firstFocus = false; /** * * @param load does nothing except change the signature. */ protected JDialogCentered(final boolean load) { } public JDialogCentered(final Program program, final String title) { this(program, title, program.getMainWindow().getFrame(), null); } public JDialogCentered(final Program program, final String title, final Image image) { this(program, title, program.getMainWindow().getFrame(), image); } public JDialogCentered(final Program program, final String title, final Window parent) { this(program, title, parent, null); } public JDialogCentered(final Program program, final String title, final Window parent, final Image image) { this.program = program; this.parent = parent; ListenerClass listener = new ListenerClass(); dialog = new JDialog(parent, JDialog.DEFAULT_MODALITY_TYPE); dialog.setTitle(title); dialog.setResizable(false); dialog.addWindowListener(listener); dialog.addWindowFocusListener(listener); if (image != null) { dialog.setIconImage(image); } jPanel = new JPanel(); layout = new GroupLayout(jPanel); jPanel.setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(true); dialog.add(jPanel); dialog.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), DialogCenteredAction.CANCEL.name()); dialog.getRootPane().getActionMap().put(DialogCenteredAction.CANCEL.name(), new HideAction(DialogCenteredAction.CANCEL.name())); dialog.getRootPane().getActionMap().put(DefaultEditorKit.insertBreakAction, new HideAction(DialogCenteredAction.OK.name())); } protected abstract JComponent getDefaultFocus(); protected abstract JButton getDefaultButton(); protected abstract void windowShown(); protected abstract void save(); public final JDialog getDialog() { return dialog; } public void setVisible(final boolean b) { if (b) { LOG.info("Showing: {} Dialog", dialog.getTitle()); dialog.pack(); if (dialog.isResizable()) { dialog.setMinimumSize(dialog.getSize()); } //Get the parent size Dimension screenSize = parent.getSize(); //Calculate the frame location int x = (screenSize.width - dialog.getWidth()) / 2; int y = (screenSize.height - dialog.getHeight()) / 2; //Set the new frame location dialog.setLocation(x, y); dialog.setLocationRelativeTo(parent); firstActivating = true; firstFocus = true; TextManager.installAll(dialog); } else { LOG.info("Hiding: {} Dialog", dialog.getTitle()); } dialog.setVisible(b); } //Find JTextComponent(s) and overwrite the default enter action private void fixTextComponents(final JComponent jComponent) { for (int i = 0; i < jComponent.getComponentCount(); i++) { Component c = jComponent.getComponent(i); if (c instanceof JTextComponent) { JTextComponent jTextComponent = (JTextComponent) c; if (!jTextComponent.isEditable()) { jTextComponent.getActionMap().put(DefaultEditorKit.insertBreakAction, new HideAction(DialogCenteredAction.OK.name())); } } if (c instanceof JComponent) { fixTextComponents((JComponent) c); } } } private class ListenerClass implements WindowListener, WindowFocusListener { @Override public void windowOpened(final WindowEvent e) { //Set default close button if (dialog.getRootPane().getDefaultButton() == null) { dialog.getRootPane().setDefaultButton(getDefaultButton()); } //Fix none editable JTextComponent(s) fixTextComponents(jPanel); } @Override public void windowClosing(final WindowEvent e) { LOG.info("Hiding: {} Dialog (close)", dialog.getTitle()); setVisible(false); } @Override public void windowClosed(final WindowEvent e) { } @Override public void windowIconified(final WindowEvent e) { } @Override public void windowDeiconified(final WindowEvent e) { } @Override public void windowActivated(final WindowEvent e) { if (firstActivating) { firstActivating = false; windowShown(); } } @Override public void windowGainedFocus(final WindowEvent e) { //We can not change focus before dialog have focus... JComponent defaultFocus = getDefaultFocus(); if (defaultFocus == null) { LOG.warn("No default focus for: {}", dialog.getTitle()); return; } if (firstFocus) { firstFocus = false; if (defaultFocus.isEnabled()) { defaultFocus.requestFocusInWindow(); } } } @Override public void windowLostFocus(final WindowEvent e) { } @Override public void windowDeactivated(final WindowEvent e) { } } private class HideAction extends AbstractAction { private static final long serialVersionUID = 1L; public HideAction(final String actionCommand) { this.putValue(Action.ACTION_COMMAND_KEY, actionCommand); } @Override public void actionPerformed(final ActionEvent e) { if (DialogCenteredAction.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); } if (DialogCenteredAction.OK.name().equals(e.getActionCommand())) { save(); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JDoubleField.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import net.nikr.eve.jeveasset.gui.shared.DocumentFactory; public class JDoubleField extends JDefaultField { public JDoubleField() { this("0", DocumentFactory.ValueFlag.ANY_NUMBER); } public JDoubleField(DocumentFactory.ValueFlag flag) { this("0", flag); } public JDoubleField(final String defaultValue) { this(defaultValue, DocumentFactory.ValueFlag.ANY_NUMBER); } public JDoubleField(final String defaultValue, DocumentFactory.ValueFlag flag) { super(defaultValue); this.setDocument(DocumentFactory.getDoublePlainDocument(flag)); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JDragTabbedPane.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * Original code by aterai (https://java-swing-tips.blogspot.com/2008/04/drag-and-drop-tabs-in-jtabbedpane.html) * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.dnd.InvalidDnDOperationException; import java.awt.event.ActionEvent; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.Icon; import javax.swing.JPanel; import javax.swing.JTabbedPane; import static javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT; import static javax.swing.SwingConstants.BOTTOM; import static javax.swing.SwingConstants.LEFT; import static javax.swing.SwingConstants.RIGHT; import static javax.swing.SwingConstants.TOP; import javax.swing.SwingUtilities; public class JDragTabbedPane extends JTabbedPane { private static final int LINEWIDTH = 3; private static final String NAME = "test"; private final GhostGlassPane glassPane = new GhostGlassPane(); private final Rectangle lineRect = new Rectangle(); private final Color lineColor = new Color(0, 100, 255); private int sourceTabIndex = -1; private final List tabMoveListeners = new ArrayList<>(); private final Set locked = new HashSet<>(); public void addTabMoveListeners(TabMoveListener tabMoveListener) { tabMoveListeners.add(tabMoveListener); } public void removeTabMoveListeners(TabMoveListener tabMoveListener) { tabMoveListeners.remove(tabMoveListener); } public void addDragLock(Integer index) { locked.add(index); } public void removeDragLock(Integer index) { locked.remove(index); } private void clickArrowButton(String actionKey) { ActionMap map = getActionMap(); if (map != null) { Action action = map.get(actionKey); if (action != null && action.isEnabled()) { action.actionPerformed(new ActionEvent( this, ActionEvent.ACTION_PERFORMED, null, 0, 0)); } } } private static Rectangle backward = new Rectangle(); private static Rectangle forward = new Rectangle(); private static final int RWH = 20; private static final int BUTTON_SIZE = 30;//XXX: magic number of scroll button size private void autoScrollTest(Point glassPt) { Rectangle r = getTabAreaBounds(); int placement = getTabPlacement(); if (placement == TOP || placement == BOTTOM) { backward.setBounds(r.x, r.y, RWH, r.height); forward.setBounds(r.x + r.width - RWH - BUTTON_SIZE, r.y, RWH + BUTTON_SIZE, r.height); } else if (placement == LEFT || placement == RIGHT) { backward.setBounds(r.x, r.y, r.width, RWH); forward.setBounds(r.x, r.y + r.height - RWH - BUTTON_SIZE, r.width, RWH + BUTTON_SIZE); } backward = SwingUtilities.convertRectangle(getParent(), backward, glassPane); forward = SwingUtilities.convertRectangle(getParent(), forward, glassPane); if (backward.contains(glassPt)) { clickArrowButton("scrollTabsBackwardAction"); } else if (forward.contains(glassPt)) { clickArrowButton("scrollTabsForwardAction"); } } public JDragTabbedPane() { super(); final DragSourceListener dsl = new DragSourceListener() { @Override public void dragEnter(DragSourceDragEvent e) { e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop); } @Override public void dragExit(DragSourceEvent e) { e.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop); lineRect.setRect(0, 0, 0, 0); glassPane.setPoint(new Point(-1000, -1000)); glassPane.repaint(); } @Override public void dragOver(DragSourceDragEvent e) { Point glassPt = e.getLocation(); SwingUtilities.convertPointFromScreen(glassPt, glassPane); if (isValidTarget(getTargetTabIndex(glassPt))) { e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop); glassPane.setCursor(DragSource.DefaultMoveDrop); } else { e.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop); glassPane.setCursor(DragSource.DefaultMoveNoDrop); } } @Override public void dragDropEnd(DragSourceDropEvent e) { lineRect.setRect(0, 0, 0, 0); sourceTabIndex = -1; glassPane.setVisible(false); if (hasGhost()) { glassPane.setVisible(false); glassPane.setImage(null); } } @Override public void dropActionChanged(DragSourceDragEvent e) { } }; final Transferable t = new Transferable() { private final DataFlavor FLAVOR = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType, NAME); @Override public Object getTransferData(DataFlavor flavor) { return JDragTabbedPane.this; } @Override public DataFlavor[] getTransferDataFlavors() { DataFlavor[] f = new DataFlavor[1]; f[0] = this.FLAVOR; return f; } @Override public boolean isDataFlavorSupported(DataFlavor flavor) { return flavor.getHumanPresentableName().equals(NAME); } }; final DragGestureListener dgl = new DragGestureListener() { @Override public void dragGestureRecognized(DragGestureEvent e) { if (getTabCount() <= 1) { return; } Point tabPt = e.getDragOrigin(); sourceTabIndex = indexAtLocation(tabPt.x, tabPt.y); //"disabled tab problem". if (sourceTabIndex < 0 || !isEnabledAt(sourceTabIndex) || locked.contains(sourceTabIndex)) { return; } initGlassPane(e.getComponent(), e.getDragOrigin()); try { e.startDrag(DragSource.DefaultMoveDrop, t, dsl); } catch (InvalidDnDOperationException idoe) { //No problem } } }; new DropTarget(glassPane, DnDConstants.ACTION_COPY_OR_MOVE, new CDropTargetListener(), true); new DragSource().createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, dgl); } class CDropTargetListener implements DropTargetListener { @Override public void dragEnter(DropTargetDragEvent e) { if (isDragAcceptable(e)) { e.acceptDrag(e.getDropAction()); } else { e.rejectDrag(); } } @Override public void dragExit(DropTargetEvent e) { } @Override public void dropActionChanged(DropTargetDragEvent e) { } private Point _glassPt = new Point(); @Override public void dragOver(final DropTargetDragEvent e) { Point glassPt = e.getLocation(); if (getTabPlacement() == JTabbedPane.TOP || getTabPlacement() == JTabbedPane.BOTTOM) { initTargetLeftRightLine(getTargetTabIndex(glassPt)); } else { initTargetTopBottomLine(getTargetTabIndex(glassPt)); } if (hasGhost()) { glassPane.setPoint(glassPt); } if (!_glassPt.equals(glassPt)) { glassPane.repaint(); } _glassPt = glassPt; autoScrollTest(glassPt); } @Override public void drop(DropTargetDropEvent e) { if (isDropAcceptable(e)) { int targetTabIndex = getTargetTabIndex(e.getLocation()); if (!locked.contains(targetTabIndex)) { convertTab(targetTabIndex); e.dropComplete(true); repaint(); return; //Moved } } e.dropComplete(false); repaint(); } private boolean isDragAcceptable(DropTargetDragEvent e) { Transferable t = e.getTransferable(); if (t == null) { return false; } DataFlavor[] f = e.getCurrentDataFlavors(); if (t.isDataFlavorSupported(f[0]) && sourceTabIndex >= 0) { return true; } return false; } private boolean isDropAcceptable(DropTargetDropEvent e) { Transferable t = e.getTransferable(); if (t == null) { return false; } DataFlavor[] f = t.getTransferDataFlavors(); if (t.isDataFlavorSupported(f[0]) && sourceTabIndex >= 0) { return true; } return false; } } private boolean hasGhost = true; public void setPaintGhost(boolean flag) { hasGhost = flag; } public boolean hasGhost() { return hasGhost; } private boolean isPaintScrollArea = true; public void setPaintScrollArea(boolean flag) { isPaintScrollArea = flag; } public boolean isPaintScrollArea() { return isPaintScrollArea; } private int getTargetTabIndex(Point glassPt) { Point tabPt = SwingUtilities.convertPoint(glassPane, glassPt, JDragTabbedPane.this); boolean isTB = getTabPlacement() == JTabbedPane.TOP || getTabPlacement() == JTabbedPane.BOTTOM; for (int i = 0; i < getTabCount(); i++) { Rectangle r = getBoundsAt(i); if (isTB) { r.setRect(r.x - r.width / 2, r.y, r.width, r.height); } else { r.setRect(r.x, r.y - r.height / 2, r.width, r.height); } if (r.contains(tabPt)) { return i; } } Rectangle r = getBoundsAt(getTabCount() - 1); if (isTB) { r.setRect(r.x + r.width / 2, r.y, r.width, r.height); } else { r.setRect(r.x, r.y + r.height / 2, r.width, r.height); } return r.contains(tabPt) ? getTabCount() : -1; } private void convertTab(int targetTabIndex) { if (targetTabIndex < 0 || sourceTabIndex == targetTabIndex) { return; } Component cmp = getComponentAt(sourceTabIndex); Component tab = getTabComponentAt(sourceTabIndex); String str = getTitleAt(sourceTabIndex); Icon icon = getIconAt(sourceTabIndex); String tip = getToolTipTextAt(sourceTabIndex); boolean flg = isEnabledAt(sourceTabIndex); int fixedTargetTabIndex = sourceTabIndex > targetTabIndex ? targetTabIndex : targetTabIndex - 1; remove(sourceTabIndex); insertTab(str, icon, cmp, tip, fixedTargetTabIndex); setEnabledAt(fixedTargetTabIndex, flg); //When you drag'n'drop a disabled tab, it finishes enabled and selected. //pointed out by dlorde if (flg) { setSelectedIndex(fixedTargetTabIndex); } //I have a component in all tabs (jlabel with an X to close the tab) //and when i move a tab the component disappear. //pointed out by Daniel Dario Morales Salas setTabComponentAt(fixedTargetTabIndex, tab); //Notify listeners for (TabMoveListener tabMoveListener : tabMoveListeners) { tabMoveListener.tabMoved(sourceTabIndex, fixedTargetTabIndex); } } private void initTargetLeftRightLine(int targetTabIndex) { if (isInvalidTarget(targetTabIndex)) { lineRect.setRect(0, 0, 0, 0); } else if (targetTabIndex == 0) { Rectangle r = SwingUtilities.convertRectangle( this, getBoundsAt(0), glassPane); lineRect.setRect(r.x - LINEWIDTH / 2, r.y, LINEWIDTH, r.height); } else { Rectangle r = SwingUtilities.convertRectangle( this, getBoundsAt(targetTabIndex - 1), glassPane); lineRect.setRect(r.x + r.width - LINEWIDTH / 2, r.y, LINEWIDTH, r.height); } } private void initTargetTopBottomLine(int targetTabIndex) { if (isInvalidTarget(targetTabIndex)) { lineRect.setRect(0, 0, 0, 0); } else if (targetTabIndex == 0) { Rectangle r = SwingUtilities.convertRectangle( this, getBoundsAt(0), glassPane); lineRect.setRect(r.x, r.y - LINEWIDTH / 2, r.width, LINEWIDTH); } else { Rectangle r = SwingUtilities.convertRectangle( this, getBoundsAt(targetTabIndex - 1), glassPane); lineRect.setRect(r.x, r.y + r.height - LINEWIDTH / 2, r.width, LINEWIDTH); } } private boolean isInvalidTarget(int targetTabIndex) { return !isValidTarget(targetTabIndex); } private boolean isValidTarget(int targetTabIndex) { return targetTabIndex >= 0 && targetTabIndex != sourceTabIndex && targetTabIndex != sourceTabIndex + 1 && !locked.contains(targetTabIndex); } private void initGlassPane(Component c, Point tabPt) { getRootPane().setGlassPane(glassPane); if (hasGhost()) { Rectangle rect = getBoundsAt(sourceTabIndex); BufferedImage image = new BufferedImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_INT_ARGB); Graphics g = image.getGraphics(); c.paint(g); rect.x = rect.x < 0 ? 0 : rect.x; rect.y = rect.y < 0 ? 0 : rect.y; image = image.getSubimage(rect.x, rect.y, rect.width, rect.height); glassPane.setImage(image); } Point glassPt = SwingUtilities.convertPoint(c, tabPt, glassPane); glassPane.setPoint(glassPt); glassPane.setVisible(true); } private Rectangle getTabAreaBounds() { Rectangle tabbedRect = getBounds(); //pointed out by daryl. NullPointerException: i.e. addTab("Tab",null) //Rectangle compRect = getSelectedComponent().getBounds(); Component comp = getSelectedComponent(); int idx = 0; while (comp == null && idx < getTabCount()) { comp = getComponentAt(idx++); } Rectangle compRect = (comp == null) ? new Rectangle() : comp.getBounds(); int placement = getTabPlacement(); if (placement == TOP) { tabbedRect.height = tabbedRect.height - compRect.height; } else if (placement == BOTTOM) { tabbedRect.y = tabbedRect.y + compRect.y + compRect.height; tabbedRect.height = tabbedRect.height - compRect.height; } else if (placement == LEFT) { tabbedRect.width = tabbedRect.width - compRect.width; } else if (placement == RIGHT) { tabbedRect.x = tabbedRect.x + compRect.x + compRect.width; tabbedRect.width = tabbedRect.width - compRect.width; } tabbedRect.grow(2, 2); return tabbedRect; } class GhostGlassPane extends JPanel { private final AlphaComposite composite; private Point location = new Point(0, 0); private BufferedImage draggingGhost = null; public GhostGlassPane() { setOpaque(false); composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f); //[JDK-6700748] Cursor flickering during D&D when using CellRendererPane with validation - Java Bug System //https://bugs.openjdk.java.net/browse/JDK-6700748 //setCursor(null); } public void setImage(BufferedImage draggingGhost) { this.draggingGhost = draggingGhost; } public void setPoint(Point location) { this.location = location; } @Override public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.setComposite(composite); if (isPaintScrollArea() && getTabLayoutPolicy() == SCROLL_TAB_LAYOUT) { g2.setPaint(Color.RED); g2.fill(backward); g2.fill(forward); } if (draggingGhost != null) { double xx = location.getX() - (draggingGhost.getWidth(this) / 2d); double yy = location.getY() - (draggingGhost.getHeight(this) / 2d); g2.drawImage(draggingGhost, (int) xx, (int) yy, null); } if (sourceTabIndex >= 0) { g2.setPaint(lineColor); g2.fill(lineRect); } } } public interface TabMoveListener { public void tabMoved(int from, int to); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JDropDownButton.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.Component; import java.awt.Dimension; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import net.nikr.eve.jeveasset.gui.shared.MenuScroller; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JDropDownButton extends JButton { private boolean showPopupMenuMouse = true; private boolean showPopupMenuKey = true; private boolean mouseOverThis = false; private boolean mousePressedThis = false; //private JButton jButton; private int popupHorizontalAlignment; private int popupVerticalAlignment; private final JPopupMenu jPopupMenu; private final MenuScroller menuScroller; public JDropDownButton() { this(GuiShared.get().emptyString(), null, LEFT, BOTTOM); } public JDropDownButton(final Icon icon) { this(GuiShared.get().emptyString(), icon, LEFT, BOTTOM); } public JDropDownButton(final Icon icon, final int popupHorizontalAlignment) { this(GuiShared.get().emptyString(), icon, popupHorizontalAlignment, BOTTOM); } public JDropDownButton(final String text) { this(text, null, LEFT, BOTTOM); } public JDropDownButton(final String text, final Icon icon) { this(text, icon, LEFT, BOTTOM); } public JDropDownButton(final int popupHorizontalAlignment) { this(GuiShared.get().emptyString(), null, popupHorizontalAlignment, BOTTOM); } public JDropDownButton(final int popupHorizontalAlignment, final int popupVerticalAlignment) { this(GuiShared.get().emptyString(), null, popupHorizontalAlignment, popupVerticalAlignment); } public JDropDownButton(final String text, final int popupHorizontalAlignment) { this(text, null, popupHorizontalAlignment, BOTTOM); } public JDropDownButton(final String text, final int popupHorizontalAlignment, final int popupVerticalAlignment) { this(text, null, popupHorizontalAlignment, popupVerticalAlignment); } public JDropDownButton(final String text, final Icon icon, final int popupHorizontalAlignment, final int popupVerticalAlignment) { super(text, icon); if (popupHorizontalAlignment != LEFT && popupHorizontalAlignment != RIGHT && popupHorizontalAlignment != CENTER) { throw new IllegalArgumentException("Must be SwingConstants.RIGHT, SwingConstants.LEFT, or SwingConstants.CENTER"); } if (popupVerticalAlignment != TOP && popupVerticalAlignment != BOTTOM && popupVerticalAlignment != CENTER) { throw new IllegalArgumentException("Must be SwingConstants.TOP, SwingConstants.BOTTOM, or SwingConstants.CENTER"); } ListenerClass listener = new ListenerClass(); this.popupHorizontalAlignment = popupHorizontalAlignment; this.popupVerticalAlignment = popupVerticalAlignment; this.setText(text); this.addMouseListener(listener); this.addKeyListener(listener); jPopupMenu = new JPopupMenu(); jPopupMenu.addPopupMenuListener(listener); menuScroller = new MenuScroller(jPopupMenu); } public JPopupMenu getPopupMenu() { return jPopupMenu; } @Override public void removeAll() { jPopupMenu.removeAll(); } public void addSeparator() { jPopupMenu.addSeparator(); } public Component add(final JMenuItem jMenuItem, boolean keepOpen) { if (keepOpen) { //jPopupMenu.setLightWeightPopupEnabled(true); jMenuItem.addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { showPopupMenu(); jMenuItem.setArmed(true); } @Override public void mouseEntered(MouseEvent e) { jMenuItem.setArmed(true); } @Override public void mouseExited(MouseEvent e) { jMenuItem.setArmed(false); } }); } return add(jMenuItem); } @Override public Component add(final Component component) { jPopupMenu.add(component); return component; } public int getPopupHorizontalAlignment() { return popupHorizontalAlignment; } public void setPopupHorizontalAlignment(final int popupHorizontalAlignment) { if (popupHorizontalAlignment != LEFT && popupHorizontalAlignment != RIGHT && popupHorizontalAlignment != CENTER) { throw new IllegalArgumentException("Must be SwingConstants.RIGHT, SwingConstants.LEFT, or SwingConstants.CENTER"); } this.popupHorizontalAlignment = popupHorizontalAlignment; } public int getPopupVerticalAlignment() { return popupVerticalAlignment; } public void setPopupVerticalAlignment(final int popupVerticalAlignment) { if (popupVerticalAlignment != TOP && popupVerticalAlignment != BOTTOM && popupVerticalAlignment != CENTER) { throw new IllegalArgumentException("Must be SwingConstants.TOP, SwingConstants.BOTTOM, or SwingConstants.CENTER"); } this.popupVerticalAlignment = popupVerticalAlignment; } public void keepVisible(final int index) { menuScroller.keepVisible(index); } public final void setTopFixedCount(final int topFixedCount) { menuScroller.setTopFixedCount(topFixedCount); } public final void setBottomFixedCount(final int bottomFixedCount) { menuScroller.setBottomFixedCount(bottomFixedCount); } public final void setInterval(final int interval) { menuScroller.setInterval(interval); } private void showPopupMenu() { if (!this.isEnabled()) { return; } ///XXX Workaround for BugID: 281 //https://eve.nikr.net/jeveassets/bugs/#bugid281 //https://eve.nikr.net/jeveassets/bugs/#bugid420 if (!this.isShowing()) { return; } int verticalPosition = this.getHeight(); int horizontalPosition = 0; Dimension popupMenuSize = jPopupMenu.getPreferredSize(); switch (popupHorizontalAlignment) { case LEFT: //OK horizontalPosition = 0; break; case RIGHT: //OK horizontalPosition = this.getWidth() - popupMenuSize.width; break; case CENTER: //OK horizontalPosition = (this.getWidth() / 2) - (popupMenuSize.width / 2); break; } switch (popupVerticalAlignment) { case TOP: //OK verticalPosition = -popupMenuSize.height + 2; break; case BOTTOM: //OK verticalPosition = this.getHeight() - 2; break; case CENTER: //OK verticalPosition = -(popupMenuSize.height / 2) + (this.getHeight() / 2); } jPopupMenu.show(this, horizontalPosition, verticalPosition); this.getModel().setRollover(true); } private class ListenerClass implements PopupMenuListener, MouseListener, KeyListener { @Override public void popupMenuWillBecomeVisible(final PopupMenuEvent e) { } @Override public void popupMenuWillBecomeInvisible(final PopupMenuEvent e) { } @Override public void popupMenuCanceled(final PopupMenuEvent e) { if (mouseOverThis) { showPopupMenuMouse = false; } else { showPopupMenuMouse = true; } getModel().setRollover(false); } @Override public void mouseClicked(final MouseEvent e) { } @Override public void mousePressed(final MouseEvent e) { mousePressedThis = true; } @Override public void mouseReleased(final MouseEvent e) { if (mousePressedThis) { if (showPopupMenuMouse) { showPopupMenu(); } else { showPopupMenuMouse = true; } return; } mousePressedThis = false; } @Override public void mouseEntered(final MouseEvent e) { mouseOverThis = true; } @Override public void mouseExited(final MouseEvent e) { mouseOverThis = false; if (jPopupMenu.isShowing()) { getModel().setRollover(true); } } @Override public void keyTyped(final KeyEvent e) { if (showPopupMenuKey) { showPopupMenu(); } } @Override public void keyPressed(final KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_SPACE || e.getKeyCode() == KeyEvent.VK_ENTER) { showPopupMenuKey = true; } } @Override public void keyReleased(final KeyEvent e) { showPopupMenuKey = false; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JFixedToolBar.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.Dimension; import javax.swing.AbstractButton; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JToolBar; import javax.swing.SwingConstants; import net.nikr.eve.jeveasset.Program; public class JFixedToolBar extends JToolBar { private Integer height = null; private final Orientation orientation; public static enum Orientation { HORIZONTAL, VERTICAL } public JFixedToolBar() { this(Orientation.HORIZONTAL); } public JFixedToolBar(Orientation orientation) { super(); //We don't need orientation as it's only used by DefaultToolBarLayout this.orientation = orientation; setLayout(new BoxLayout(this, orientation == Orientation.HORIZONTAL ? BoxLayout.LINE_AXIS : BoxLayout.PAGE_AXIS)); setFloatable(false); setRollover(true); getSize(); } public void addGlue() { add(Box.createGlue()); } public void addGlue(int width) { add(new Box.Filler(new Dimension(width, 0), new Dimension(width, 0), new Dimension(Short.MAX_VALUE, Short.MAX_VALUE))); } public void add(JCheckBox jCheckBox) { addSpace(5); jCheckBox.setBorder(null); super.add(jCheckBox); addSpace(5); } public void add(final JComponent jComponent, int width) { if (width > 0) { setSize(jComponent, width); } super.add(jComponent); } public void addPreferedSize(final JComponent jComponent) { int preferredWidth = jComponent.getPreferredSize().width; if (preferredWidth > 0) { setSize(jComponent, preferredWidth); } super.add(jComponent); } public void addComboBox(final JComboBox jComboBox, int width) { if (width > 0) { setSize(jComboBox, width); } super.add(jComboBox); } public void addLabelIcon(final JLabel jButton) { Dimension dimension = new Dimension(Program.getIconButtonsWidth(), Program.getButtonsHeight()); jButton.setPreferredSize(dimension); jButton.setMaximumSize(dimension); jButton.setHorizontalAlignment(SwingConstants.CENTER); super.add(jButton); } public void addButtonIcon(final AbstractButton jButton) { Dimension dimension = new Dimension(Program.getIconButtonsWidth(), Program.getButtonsHeight()); jButton.setPreferredSize(dimension); jButton.setMaximumSize(dimension); jButton.setHorizontalAlignment(SwingConstants.CENTER); super.add(jButton); } public void addButton(final AbstractButton jButton) { addButton(jButton, 100, SwingConstants.LEFT); } public void addButton(final AbstractButton jButton, final int width, final int alignment) { if (width > 0) { setSize(jButton, width); } jButton.setHorizontalAlignment(alignment); super.add(jButton); } public void addSpace(final int width) { super.add(Box.createRigidArea(new Dimension(width,0))); } private void setSize(JComponent jComponent, int width) { setSize(jComponent, width, Program.getButtonsHeight()); } private void setSize(final JComponent jComponent, final int width, final int height) { int preferredWidth = jComponent.getPreferredSize().width; Dimension dimension; if (preferredWidth > width) { dimension = new Dimension(preferredWidth, height); } else { dimension = new Dimension(width, height); } jComponent.setPreferredSize(dimension); jComponent.setMaximumSize(dimension); } @Override public Dimension getPreferredSize() { if (orientation == Orientation.VERTICAL) { return super.getPreferredSize(); } else { if (height == null) { height = getInsets().top + getInsets().bottom + Program.getButtonsHeight(); } Dimension preferredSize = super.getPreferredSize(); return new Dimension(preferredSize.width, height); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JGroupLayoutPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import javax.swing.GroupLayout; import javax.swing.JPanel; import net.nikr.eve.jeveasset.Program; public abstract class JGroupLayoutPanel { protected Program program; protected GroupLayout layout; private JPanel jPanel; public JGroupLayoutPanel(final Program program) { this.program = program; jPanel = new JPanel(); layout = new GroupLayout(jPanel); jPanel.setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(true); } /** * * @param load does nothing except change the signature. */ protected JGroupLayoutPanel(final boolean load) { } public JPanel getPanel() { return jPanel; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JImportDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JRadioButton; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JImportDialog extends JDialogCentered { private enum StockpileImportAction { OK, CANCEL } public enum ImportReturn { RENAME, RENAME_ALL, MERGE, MERGE_ALL, OVERWRITE, OVERWRITE_ALL, SKIP, SKIP_ALL, } private final JRadioButton jRename; private final JRadioButton jMerge; private final JRadioButton jOverwrite; private final JRadioButton jSkip; private final JLabel jName; private final JLabel jRenameLabel; private final JLabel jMergeLabel; private final JLabel jOverwriteLabel; private final JLabel jSkipLabel; private final JCheckBox jAll; private final JButton jOK; private final JButton jCancel; private final ListenerClass listenerClass; private final ImportOptions importOptions; private ImportReturn importReturn; public JImportDialog(Program program, ImportOptions importOptions) { super(program, GuiShared.get().importOptions()); this.importOptions = importOptions; listenerClass = new ListenerClass(); jName = new JLabel(); jName.setFont(new Font(jName.getFont().getName(), Font.BOLD, jName.getFont().getSize() + 1)); jRenameLabel = new JLabel(importOptions.getTextRenameHelp()); jRename = new JRadioButton(GuiShared.get().importOptionsRename()); jMergeLabel = new JLabel(importOptions.getTextMergeHelp()); jMerge = new JRadioButton(GuiShared.get().importOptionsMerge()); jOverwriteLabel = new JLabel(importOptions.getTextOverwriteHelp()); jOverwrite = new JRadioButton(GuiShared.get().importOptionsOverwrite()); jSkipLabel = new JLabel(importOptions.getTextSkipHelp()); jSkip = new JRadioButton(GuiShared.get().importOptionsSkip()); jRenameLabel.setVisible(importOptions.isRenameSupported()); jRename.setVisible(importOptions.isRenameSupported()); jMergeLabel.setVisible(importOptions.isMergeSupported()); jMerge.setVisible(importOptions.isMergeSupported()); jOverwriteLabel.setVisible(importOptions.isOverwriteSupported()); jOverwrite.setVisible(importOptions.isOverwriteSupported()); jSkipLabel.setVisible(importOptions.isSkipSupported()); jSkip.setVisible(importOptions.isSkipSupported()); ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(jRename); buttonGroup.add(jMerge); buttonGroup.add(jOverwrite); buttonGroup.add(jSkip); jAll = new JCheckBox(); jOK = new JButton(GuiShared.get().ok()); jOK.setActionCommand(StockpileImportAction.OK.name()); jOK.addActionListener(listenerClass); jCancel = new JButton(GuiShared.get().cancel()); jCancel.setActionCommand(StockpileImportAction.CANCEL.name()); jCancel.addActionListener(listenerClass); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jName) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jRename) .addComponent(jMerge) .addComponent(jOverwrite) .addComponent(jSkip) ) .addGap(20) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jRenameLabel) .addComponent(jMergeLabel) .addComponent(jOverwriteLabel) .addComponent(jSkipLabel) ) ) .addGroup(layout.createSequentialGroup() .addComponent(jAll) .addGap(0, 0, Integer.MAX_VALUE) ) .addGroup(layout.createSequentialGroup() .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jName, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jRename, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRenameLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jMerge, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jMergeLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jOverwrite, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOverwriteLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jSkip, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSkipLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(20) .addComponent(jAll, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGap(20) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } public void resetToDefault() { jRename.setSelected(true); jAll.setSelected(false); } public ImportReturn show(String name, int count) { jName.setText(name); jAll.setText(importOptions.getTextAll(count)); jAll.setEnabled(count > 1); setVisible(true); return importReturn; } @Override protected JComponent getDefaultFocus() { return jOK; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { } @Override protected void save() { selected(jRename, ImportReturn.RENAME, ImportReturn.RENAME_ALL); selected(jMerge, ImportReturn.MERGE, ImportReturn.MERGE_ALL); selected(jOverwrite, ImportReturn.OVERWRITE, ImportReturn.OVERWRITE_ALL); selected(jSkip, ImportReturn.SKIP, ImportReturn.SKIP_ALL); setVisible(false); } private void selected(JRadioButton jRadioButton, ImportReturn single, ImportReturn all) { if (jRadioButton.isSelected()) { if (jAll.isSelected()) { importReturn = all; } else { importReturn = single; } } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(ActionEvent e) { if (StockpileImportAction.OK.name().equals(e.getActionCommand())) { save(); } if (StockpileImportAction.CANCEL.name().equals(e.getActionCommand())) { importReturn = ImportReturn.SKIP_ALL; setVisible(false); } } } public static interface ImportOptions { public boolean isRenameSupported(); public boolean isMergeSupported(); public boolean isOverwriteSupported(); public boolean isSkipSupported(); public String getTextRenameHelp(); public String getTextMergeHelp(); public String getTextOverwriteHelp(); public String getTextSkipHelp(); public String getTextAll(int count); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JIntegerField.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import net.nikr.eve.jeveasset.gui.shared.DocumentFactory; import net.nikr.eve.jeveasset.gui.shared.DocumentFactory.ValueFlag; public class JIntegerField extends JDefaultField { public JIntegerField() { this("0", ValueFlag.ANY_NUMBER); } public JIntegerField(ValueFlag flag) { this("0", flag); } public JIntegerField(final String defaultValue) { this(defaultValue, ValueFlag.ANY_NUMBER); } public JIntegerField(final String defaultValue, ValueFlag flag) { super(defaultValue); this.setDocument(DocumentFactory.getIntegerPlainDocument(flag)); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JLabelMultiline.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import javax.swing.JLabel; import javax.swing.JTextArea; import net.nikr.eve.jeveasset.data.settings.Colors; public class JLabelMultiline extends JTextArea { public JLabelMultiline(String text) { this(text, text.trim().split("\r\n|\r|\n").length); } public JLabelMultiline(String text, int rows) { super(text); //Init JLabel jLabel = new JLabel(); setFont(jLabel.getFont()); setBackground(Colors.COMPONENT_TRANSPARENT.getColor()); setLineWrap(true); setWrapStyleWord(true); setFocusable(false); setEditable(false); setOpaque(false); setBorder(null); setRows(rows); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JLabelMultilineHtml.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.Font; import java.awt.Window; import javax.swing.JEditorPane; import javax.swing.JLabel; import net.nikr.eve.jeveasset.data.settings.Colors; import net.nikr.eve.jeveasset.io.shared.DesktopUtil; public class JLabelMultilineHtml extends JEditorPane { private static Font font; public JLabelMultilineHtml(String text) { this(null, text); } public JLabelMultilineHtml(Window parent) { this(parent, ""); } public JLabelMultilineHtml(Window parent, String text) { super("text/html", text); //jHelp.setLineWrap(true); //jHelp.setWrapStyleWord(true); addHyperlinkListener(DesktopUtil.getHyperlinkListener(parent)); setFont( getLabelFont()); setEditable(false); setOpaque(false); setBackground(Colors.COMPONENT_TRANSPARENT.getColor()); setFocusable(false); } private Font getLabelFont() { if (font == null) { font = new JLabel().getFont(); } return font; } @Override public void setText(final String text) { super.setText("" + text + ""); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JLockWindow.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.Dimension; import java.awt.Window; import java.util.concurrent.ExecutionException; import javax.swing.BorderFactory; import javax.swing.GroupLayout; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JWindow; import javax.swing.SwingWorker; public class JLockWindow { private final JWindow jWindow; private final JLabel jLabel; private final Window parent; private final JProgressBar jProgress; public JLockWindow(final Window parent) { this.parent = parent; jWindow = new JWindow(parent); jProgress = new JProgressBar(0, 100); JPanel jPanel = new JPanel(); jPanel.setBorder(BorderFactory.createRaisedBevelBorder()); GroupLayout layout = new GroupLayout(jPanel); jPanel.setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(true); jWindow.add(jPanel); jLabel = new JLabel(); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jLabel) .addComponent(jProgress) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jLabel) .addComponent(jProgress) ); } public void show(final String text, final LockWorker lockWorker) { jLabel.setText(text); jWindow.pack(); //Get the parent size Dimension parentSize = parent.getSize(); //Calculate the frame location int x = (parentSize.width - jWindow.getWidth()) / 2; int y = (parentSize.height - jWindow.getHeight()) / 2; //Set the new frame location jWindow.setLocation(x, y); jWindow.setLocationRelativeTo(parent); parent.setEnabled(false); jProgress.setIndeterminate(false); jProgress.setIndeterminate(true); jWindow.setVisible(true); //Does not block! Wait wait = new Wait(lockWorker); wait.execute(); } private void hide() { parent.setEnabled(true); jWindow.setVisible(false); } class Wait extends SwingWorker{ private final LockWorker worker; public Wait(LockWorker worker) { this.worker = worker; } @Override protected Void doInBackground() throws Exception { worker.task(); return null; } @Override protected void done() { worker.gui(); hide(); worker.hidden(); try { get(); } catch (InterruptedException | ExecutionException ex) { throw new RuntimeException(ex); } } } public static interface LockWorker { public void task(); public void gui(); public void hidden(); } public static class LockWorkerAdaptor implements LockWorker { @Override public void task() {} @Override public void gui() {} @Override public void hidden() {} } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JMainTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.gui.TableFormat; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import javax.swing.GroupLayout; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.ListSelectionModel; import javax.swing.table.TableModel; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.SettingsUpdateListener; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.JSeparatorTable; public abstract class JMainTab { private String title; private Icon icon; private boolean closeable; private final List statusbarLabels = new ArrayList<>(); protected Program program; protected JPanel jPanel; protected GroupLayout layout; private JAutoColumnTable jTable; private DefaultEventSelectionModel eventSelectionModel; private DefaultEventTableModel eventTableModel; private FilterControl filterControl; private TableComparatorChooser comparatorChooser; private List selected; private int[] selectedColumns; private String toolName; private Class clazz; private boolean sortLock = false; protected JMainTab(final boolean load) { } public JMainTab(final Program program, final String toolName, final String title, final Icon icon, final boolean closeable) { this.program = program; this.toolName = toolName; this.title = title; this.icon = icon; this.closeable = closeable; program.addMainTab(toolName, this); jPanel = new JPanel(); layout = new GroupLayout(jPanel); jPanel.setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(true); } public final & EnumTableColumn, Q> void installTableTool(final TableMenu tableMenu, EnumTableFormatAdaptor tableFormat, TableComparatorChooser comparatorChooser, DefaultEventTableModel tableModel, JAutoColumnTable jTable, EventList eventList, final Class clazz) { installTableTool(tableMenu, tableFormat, comparatorChooser, tableModel, jTable, eventList, null, clazz); } public final & EnumTableColumn, Q> void installTableTool(final TableMenu tableMenu, EnumTableFormatAdaptor tableFormat, TableComparatorChooser comparatorChooser, DefaultEventTableModel tableModel, JAutoColumnTable jTable, FilterControl filterControl, final Class clazz) { installTableTool(tableMenu, tableFormat, comparatorChooser, tableModel, jTable, filterControl.getEventList(), filterControl, clazz); } private & EnumTableColumn, Q> void installTableTool(final TableMenu tableMenu, EnumTableFormatAdaptor tableFormat, TableComparatorChooser comparatorChooser, DefaultEventTableModel tableModel, JAutoColumnTable jTable, EventList eventList, FilterControl filterControl, final Class clazz) { this.clazz = clazz; this.comparatorChooser = comparatorChooser; //Can be null MenuManager.install(program, tableMenu, jTable, new ColumnManager<>(program, toolName, tableFormat, tableModel, jTable, eventList, filterControl), clazz); if(filterControl != null && toolName != null && !toolName.isEmpty()) { filterControl.clearCurrentFilters(); filterControl.addFilters(Settings.get().getCurrentTableFilters(toolName)); filterControl.setFilterShown(Settings.get().getCurrentTableFiltersShown(toolName)); SettingsUpdateListener listener = new ListenerClass(); filterControl.getSettingsUpdateListenerList().add(listener); this.filterControl = filterControl; } if (comparatorChooser != null) { //Save current sorting comparatorChooser.addSortActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (sortLock) { return; } Settings.lock("Current Sorting"); Settings.get().getCurrentTableSorting().put(toolName, comparatorChooser.toString()); Settings.unlock("Current Sorting"); program.saveSettings("Current Sorting"); } }); } } /** * Restore sorting from settings */ public void loadCurrentSorting() { setSorting(Settings.get().getCurrentTableSorting(toolName), false); } /** * Set sorting - does not save the new sorting * @param sorting * @param save Save settings */ private void setSorting(String sorting, boolean save) { if (comparatorChooser != null && sorting != null && !sorting.isEmpty()) { //Load sorting try { sortLock = true; comparatorChooser.fromString(sorting); } finally { sortLock = false; } if (save) { Settings.lock("Set Sorting"); Settings.get().getCurrentTableSorting().put(toolName, comparatorChooser.toString()); Settings.unlock("SetSorting"); program.saveSettings("Set Sorting"); } } } /** * Supports sorting * @return */ public boolean isSortingSupported() { return comparatorChooser != null; } public void updateTableMenu() { MenuManager.update(program ,clazz); } public void createTableMenu() { MenuManager.create(program ,clazz); } public void tableStructureChanged() { if (eventTableModel != null && jTable != null) { eventTableModel.fireTableStructureChanged(); jTable.autoResizeColumns(); } } public void tableDataChanged() { beforeUpdateDataKeepCache(); if (eventTableModel != null) { eventTableModel.fireTableDataChanged(); } afterUpdateData(); } public void repaintTable() { if (jTable != null) { jTable.repaint(); } repaintFilters(); } public void repaintFilters() { if (filterControl != null) { filterControl.repaint(); } } public final void saveSettings() { //Save Settings if (eventTableModel != null && jTable != null && toolName != null) { TableFormat tableFormat = eventTableModel.getTableFormat(); if (tableFormat instanceof EnumTableFormatAdaptor) { EnumTableFormatAdaptor formatAdaptor = (EnumTableFormatAdaptor) tableFormat; Settings.get().getTableColumns().put(toolName, formatAdaptor.getColumns()); Settings.get().getTableResize().put(toolName, formatAdaptor.getResizeMode()); Settings.get().getTableColumnsWidth().put(toolName, jTable.getColumnsWidth()); if(filterControl != null) { Settings.get().getCurrentTableFilters().put(toolName, filterControl.getCurrentFilters()); } } } } public final synchronized void addStatusbarLabel(final JLabel jLabel) { statusbarLabels.add(jLabel); } public final synchronized void clearStatusbarLabels() { statusbarLabels.clear(); } public synchronized List getStatusbarLabels() { return new ArrayList<>(statusbarLabels); //Copy } public final void beforeUpdateData() { beforeUpdateData(true); } public final void beforeUpdateDataKeepCache() { beforeUpdateData(false); } private void beforeUpdateData(boolean resetFormulaCache) { if (eventSelectionModel != null) { selected = new ArrayList<>(eventSelectionModel.getSelected()); } if (jTable != null) { selectedColumns = jTable.getColumnModel().getSelectedColumns(); jTable.lock(); } else { selectedColumns = null; } if (jTable instanceof JSeparatorTable) { JSeparatorTable jSeparatorTable = (JSeparatorTable) jTable; jSeparatorTable.saveExpandedState(); } if (resetFormulaCache) { MenuManager.updateFormula(clazz); } else { MenuManager.lock(clazz); } } public final void afterUpdateData() { MenuManager.updateJumps(clazz); MenuManager.unlock(clazz); if (eventSelectionModel != null && eventTableModel != null && selected != null) { eventSelectionModel.setValueIsAdjusting(true); for (int i = 0; i < eventTableModel.getRowCount(); i++) { Object object = eventTableModel.getElementAt(i); if (selected.contains(object)) { eventSelectionModel.addSelectionInterval(i, i); } } eventSelectionModel.setValueIsAdjusting(false); selected = null; } if (selectedColumns != null && jTable != null) { for (int index : selectedColumns) { jTable.getColumnModel().getSelectionModel().addSelectionInterval(index, index); } } if (jTable != null) { jTable.unlock(); } if (jTable instanceof JSeparatorTable) { JSeparatorTable jSeparatorTable = (JSeparatorTable) jTable; jSeparatorTable.loadExpandedState(); } } public abstract void updateNames(Set itemIDs); public abstract void updateLocations(Set locationIDs); public abstract void updatePrices(Set typeIDs); public abstract void updateData(); public abstract void updateCache(); public abstract void clearData(); public abstract Collection getLocations(); public final Icon getIcon() { return icon; } public JPanel getPanel() { return jPanel; } public String getTitle() { return title; } public boolean isCloseable() { return closeable; } protected void addSeparator(final JComponent jComponent) { if (jComponent instanceof JMenu) { JMenu jMenu = (JMenu) jComponent; jMenu.addSeparator(); } if (jComponent instanceof JPopupMenu) { JPopupMenu jPopupMenu = (JPopupMenu) jComponent; jPopupMenu.addSeparator(); } if (jComponent instanceof JDropDownButton) { JDropDownButton jDropDownButton = (JDropDownButton) jComponent; jDropDownButton.addSeparator(); } } /** * Table automation * 1. Saving table settings (TableColumns, TableResize, TableColumnsWidth) * 2. Restore table selection after update * 3. Restore expanded state for JSeparatorTable after update * 4. Lock/unlock table doing update * * @param jTable */ protected final void installTable(final JAutoColumnTable jTable) { //Table Selection ListSelectionModel selectionModel = jTable.getSelectionModel(); if (selectionModel instanceof DefaultEventSelectionModel) { this.eventSelectionModel = (DefaultEventSelectionModel) selectionModel; } TableModel tableModel = jTable.getModel(); if (tableModel instanceof DefaultEventTableModel) { this.eventTableModel = (DefaultEventTableModel) tableModel; } //Table lock this.jTable = jTable; //Load Settings if (eventTableModel != null && toolName != null) { TableFormat tableFormat = eventTableModel.getTableFormat(); if (tableFormat instanceof EnumTableFormatAdaptor) { EnumTableFormatAdaptor formatAdaptor = (EnumTableFormatAdaptor) tableFormat; formatAdaptor.setColumns(Settings.get().getTableColumns().get(toolName)); formatAdaptor.setResizeMode(Settings.get().getTableResize().get(toolName)); jTable.setColumnsWidth(Settings.get().getTableColumnsWidth().get(toolName)); eventTableModel.fireTableStructureChanged(); } } } /*** * Inner class to define the listener for settings updates and perform actions when the event fires. */ private class ListenerClass implements SettingsUpdateListener { @Override public void settingChanged() { //Shows in a primitive so we need to update it before saving program.saveSettings("Save current filter change."); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JMainTabPrimary.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.util.Set; import javax.swing.Icon; import net.nikr.eve.jeveasset.Program; public abstract class JMainTabPrimary extends JMainTab { public JMainTabPrimary(Program program, final String toolName, String title, Icon icon, boolean closeable) { super(program, toolName, title, icon, closeable); } @Override public void updateNames(Set itemIDs) { } @Override public void updateLocations(Set locationIDs) { } @Override public void updatePrices(Set typeIDs) { } @Override public void updateData() { } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JMainTabSecondary.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.util.Set; import javax.swing.Icon; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTab; public abstract class JMainTabSecondary extends JMainTab { public JMainTabSecondary(Program program, final String toolName, String title, Icon icon, boolean closeable) { super(program, toolName, title, icon, closeable); } public JMainTabSecondary(final boolean load) { super(false); } @Override public void updateNames(Set itemIDs) { if (this instanceof TreeTab) { updateData(); } } @Override public void updateLocations(Set locationIDs) { updateData(); } @Override public void updatePrices(Set typeIDs) { updateData(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JManagerDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.SwingConstants; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.i18n.GuiShared; public abstract class JManagerDialog extends JDialogCentered { private enum ManageDialogAction { DONE, LOAD, EDIT, MERGE, COPY, RENAME, DELETE, EXPORT, IMPORT } private final DefaultListModel listModel; private final JList jList; private final JAutoCompleteDialog jSaveDialog; private final JButton jDelete; private final JButton jLoad; private final JButton jEdit; private final JButton jMerge; private final JButton jCopy; private final JButton jRename; private final JButton jExport; private final JButton jImport; private final JButton jClose; private final boolean mergeReplaceLoad; private final boolean mergeReplaceEdit; public JManagerDialog(Program program, JFrame jFrame, String title, boolean supportLoad, boolean supportEdit, boolean supportCopy, boolean supportMerge, boolean supportExport) { super(program, title, jFrame, Images.DIALOG_SETTINGS.getImage()); mergeReplaceLoad = supportLoad && supportMerge && !supportEdit; mergeReplaceEdit = !supportLoad && supportMerge && supportEdit; ListenerClass listener = new ListenerClass(); jSaveDialog = new JAutoCompleteDialog<>(program, "", getDialog(), Images.DIALOG_SETTINGS.getImage(), textEnterName(), false, false, JAutoCompleteDialog.STRING_OPTIONS); //Load jLoad = new JButton(GuiShared.get().managerLoad(), Images.FILTER_LOAD.getIcon()); jLoad.setActionCommand(ManageDialogAction.LOAD.name()); jLoad.addActionListener(listener); jLoad.setVisible(supportLoad); jLoad.setHorizontalAlignment(SwingConstants.LEFT); //Edit jEdit = new JButton(GuiShared.get().managerEdit(), Images.EDIT_EDIT.getIcon()); jEdit.setActionCommand(ManageDialogAction.EDIT.name()); jEdit.addActionListener(listener); jEdit.setVisible(supportEdit); jEdit.setHorizontalAlignment(SwingConstants.LEFT); //Merge jMerge = new JButton(GuiShared.get().managerMerge(), Images.EDIT_ADD.getIcon()); jMerge.setActionCommand(ManageDialogAction.MERGE.name()); jMerge.addActionListener(listener); jMerge.setVisible(supportMerge && !mergeReplaceLoad && !mergeReplaceEdit); jMerge.setHorizontalAlignment(SwingConstants.LEFT); //Copy jCopy = new JButton(GuiShared.get().managerCopy(), Images.EDIT_COPY.getIcon()); jCopy.setActionCommand(ManageDialogAction.COPY.name()); jCopy.addActionListener(listener); jCopy.setVisible(supportCopy); jCopy.setHorizontalAlignment(SwingConstants.LEFT); //Rename jRename = new JButton(GuiShared.get().managerRename(), Images.EDIT_RENAME.getIcon()); jRename.setActionCommand(ManageDialogAction.RENAME.name()); jRename.addActionListener(listener); jRename.setHorizontalAlignment(SwingConstants.LEFT); //Delete jDelete = new JButton(GuiShared.get().managerDelete(), Images.EDIT_DELETE.getIcon()); jDelete.setActionCommand(ManageDialogAction.DELETE.name()); jDelete.addActionListener(listener); jDelete.setHorizontalAlignment(SwingConstants.LEFT); //Export jExport = new JButton(GuiShared.get().managerExport(), Images.DIALOG_CSV_EXPORT.getIcon()); jExport.setActionCommand(ManageDialogAction.EXPORT.name()); jExport.addActionListener(listener); jExport.setVisible(supportExport); jExport.setHorizontalAlignment(SwingConstants.LEFT); //Import jImport = new JButton(GuiShared.get().managerImport(), Images.EDIT_IMPORT.getIcon()); jImport.setActionCommand(ManageDialogAction.IMPORT.name()); jImport.addActionListener(listener); jImport.setVisible(supportExport); jImport.setHorizontalAlignment(SwingConstants.LEFT); //Done jClose = new JButton(GuiShared.get().managerClose()); jClose.setActionCommand(ManageDialogAction.DONE.name()); jClose.addActionListener(listener); //List listModel = new DefaultListModel<>(); jList = new JList<>(listModel); jList.addMouseListener(listener); jList.addListSelectionListener(listener); JScrollPane jScrollPanel = new JScrollPane(jList); jPanel.add(jScrollPanel); layout.setHorizontalGroup( layout.createSequentialGroup() .addComponent(jScrollPanel, 175, 175, 175) .addGroup(layout.createParallelGroup() .addComponent(jLoad, 100, 100, 100) .addComponent(jEdit, 100, 100, 100) .addComponent(jMerge, 100, 100, 100) .addComponent(jCopy, 100, 100, 100) .addComponent(jRename, 100, 100, 100) .addComponent(jDelete, 100, 100, 100) .addComponent(jExport, 100, 100, 100) .addComponent(jImport, 100, 100, 100) .addComponent(jClose, 100, 100, 100) ) ); layout.setVerticalGroup( layout.createParallelGroup() .addComponent(jScrollPanel, 250, 250, 250) .addGroup(layout.createSequentialGroup() .addComponent(jLoad, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jEdit, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jMerge, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCopy, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRename, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDelete, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGap(15, 15, 15) .addComponent(jExport, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jImport, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGap(0, 0, Integer.MAX_VALUE) .addComponent(jClose, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } private String getSelectedString() { int selectedIndex = jList.getSelectedIndex(); if (selectedIndex != -1) { return listModel.get(jList.getSelectedIndex()); } else { return null; } } private void setEnabledAll(boolean b) { jLoad.setEnabled(b); jEdit.setEnabled(b); jMerge.setEnabled(b); jRename.setEnabled(b); jCopy.setEnabled(b); jDelete.setEnabled(b); jExport.setEnabled(b); } protected final void update(Collection list) { update(new ArrayList<>(list)); } protected final void update(List list) { jSaveDialog.updateData(list); listModel.clear(); Collections.sort(list, StringComparators.CASE_INSENSITIVE); for (String filter: list) { listModel.addElement(filter); } if (!listModel.isEmpty()) { if (getSelectedString() == null) { jList.setSelectedIndex(0); } setEnabledAll(true); } else { setEnabledAll(false); } } protected boolean validateName(final String name, final String oldName, final String title) { if (listModel.contains(name) && (oldName.isEmpty() || !oldName.equals(name))) { int nReturn = JOptionPane.showConfirmDialog(this.getDialog(), GuiShared.get().overwrite(), textOverwrite(), JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE); if (nReturn == JOptionPane.NO_OPTION) { //Overwrite cancelled return false; } } return true; } @Override protected JComponent getDefaultFocus() { return jList; } @Override protected JButton getDefaultButton() { return jClose; } @Override protected void windowShown() { } @Override protected void save() { this.setVisible(false); } protected abstract void load(final String name); protected abstract void edit(final String name); protected abstract void merge(final String name, final List list); protected abstract void copy(final String fromName, final String toName); protected abstract void rename(final String name, final String oldName); protected abstract void delete(final List list); protected abstract void export(final List list); protected abstract void importData(); protected abstract String textDeleteMultipleMsg(int size); protected abstract String textDelete(); protected abstract String textEnterName(); protected abstract String textMerge(); protected abstract String textRename(); protected abstract String textOverwrite(); private void delete() { List list = new ArrayList<>(); for (int index : jList.getSelectedIndices()) { String filterName = listModel.get(index); list.add(filterName); } int value; if (list.size() > 1) { value = JOptionPane.showConfirmDialog(this.getDialog(), textDeleteMultipleMsg(list.size()), textDelete(), JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE); } else if (list.size() == 1) { value = JOptionPane.showConfirmDialog(this.getDialog(), list.get(0), textDelete(), JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE); } else { return; } if (value == JOptionPane.YES_OPTION) { delete(list); } } private void export() { List list = new ArrayList<>(); for (int index : jList.getSelectedIndices()) { String filterName = listModel.get(index); list.add(filterName); } export(list); } private void load() { String name = getSelectedString(); if (name == null) { return; } load(name); } private void edit() { String name = getSelectedString(); if (name == null) { return; } edit(name); } private void merge() { String name = showNameDialog("", "", textMerge()); if (name == null) { return; } List list = new ArrayList<>(); for (int index : jList.getSelectedIndices()) { String filterName = listModel.get(index); list.add(filterName); } merge(name, list); } private void copy() { String fromName = getSelectedString(); if (fromName == null) { return; } String toName = showNameDialog("", "", textEnterName()); if (toName == null) { return; } copy(fromName, toName); } private String showNameDialog(final String oldValue, final String oldName, final String title) { //Show dialog jSaveDialog.getDialog().setTitle(title); String name = jSaveDialog.show(oldValue); if (name == null) { //Cancel (do nothing) return null; } if (!validateName(name, oldName, title)) { return showNameDialog(name, oldName, title); } return name; } private void rename() { //Get selected filter name String selectedName = getSelectedString(); if (selectedName == null) { return; } String name = showNameDialog(selectedName, selectedName, textRename()); if (name == null) { return; } rename(name, selectedName); } private class ListenerClass implements ActionListener, MouseListener, ListSelectionListener { @Override public void actionPerformed(final ActionEvent e) { if (ManageDialogAction.DONE.name().equals(e.getActionCommand())) { save(); } else if (ManageDialogAction.LOAD.name().equals(e.getActionCommand())) { load(); } else if (ManageDialogAction.EDIT.name().equals(e.getActionCommand())) { edit(); } else if (ManageDialogAction.MERGE.name().equals(e.getActionCommand())) { merge(); } else if (ManageDialogAction.COPY.name().equals(e.getActionCommand())) { copy(); } else if (ManageDialogAction.RENAME.name().equals(e.getActionCommand())) { rename(); } else if (ManageDialogAction.DELETE.name().equals(e.getActionCommand())) { delete(); } else if (ManageDialogAction.EXPORT.name().equals(e.getActionCommand())) { export(); } else if (ManageDialogAction.IMPORT.name().equals(e.getActionCommand())) { importData(); } } @Override public void mouseClicked(final MouseEvent e) { Object o = e.getSource(); if (o instanceof JList && e.getClickCount() == 2 && !e.isControlDown() && !e.isShiftDown()) { load(); } } @Override public void mousePressed(final MouseEvent e) { } @Override public void mouseReleased(final MouseEvent e) { } @Override public void mouseEntered(final MouseEvent e) { } @Override public void mouseExited(final MouseEvent e) { } @Override public void valueChanged(final ListSelectionEvent e) { boolean greatThanZero = jList.getSelectedIndices().length > 0; boolean greatThanOne = jList.getSelectedIndices().length > 1; boolean equalToOne = jList.getSelectedIndices().length == 1; jLoad.setEnabled(equalToOne); jEdit.setEnabled(equalToOne); jMerge.setEnabled(greatThanOne); jCopy.setEnabled(equalToOne); jRename.setEnabled(equalToOne); jDelete.setEnabled(greatThanZero); jExport.setEnabled(greatThanZero); if (mergeReplaceLoad) { jMerge.setVisible(greatThanOne); jLoad.setVisible(!greatThanOne); } if (mergeReplaceEdit) { jMerge.setVisible(greatThanOne); jEdit.setVisible(!greatThanOne); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JMultiSelectionDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.swing.AbstractListModel; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JScrollPane; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JMultiSelectionDialog extends JDialogCentered { private enum MultiSelectionActions { OK, CANCEL, CHECK_ALL, SUBSET } //GUI private final JCheckBox jAll; private final JCheckBox jSubset; private final JMultiSelectionList jList; private final JButton jOK; //Data private List data; private List list; private List list2; private boolean emptyAllowed; public JMultiSelectionDialog(final Program program, String title) { super(program, title); ListenerClass listener = new ListenerClass(); jAll = new JCheckBox(GuiShared.get().all()); jAll.setActionCommand(MultiSelectionActions.CHECK_ALL.name()); jAll.addActionListener(listener); jSubset = new JCheckBox(); jSubset.setActionCommand(MultiSelectionActions.SUBSET.name()); jSubset.addActionListener(listener); jList = new JMultiSelectionList<>(); jList.addListSelectionListener(listener); JScrollPane jListScroll = new JScrollPane(jList); jOK = new JButton(GuiShared.get().ok()); jOK.setActionCommand(MultiSelectionActions.OK.name()); jOK.addActionListener(listener); jOK.setEnabled(false); JButton jCancel = new JButton(GuiShared.get().cancel()); jCancel.setActionCommand(MultiSelectionActions.CANCEL.name()); jCancel.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jAll) .addGap(0, 0, Integer.MAX_VALUE) .addComponent(jSubset) ) .addComponent(jListScroll, 300, 300, 300) .addGroup(layout.createSequentialGroup() .addGap(0, 0, Integer.MAX_VALUE) .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jAll, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSubset, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jListScroll, 200, 200, 200) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } @Override protected JComponent getDefaultFocus() { return jOK; } @Override protected JButton getDefaultButton() { return jOK; } public List show(Collection items, boolean emptyAllowed) { return show(items, new ArrayList<>(), null, null, emptyAllowed); } public List show(Collection items, Collection selected, boolean emptyAllowed) { return show(items, selected, null, null, emptyAllowed); } public List show(Collection items, Collection other, String otherTitle, boolean emptyAllowed) { return show(items, new ArrayList<>(), other, otherTitle, emptyAllowed); } public List show(Collection items, Collection selected, Collection other, String otherTitle, boolean emptyAllowed) { this.emptyAllowed = emptyAllowed; list = new ArrayList<>(items); if (other != null && otherTitle != null) { list2 = new ArrayList<>(other); jSubset.setText(otherTitle); jSubset.setSelected(false); jSubset.setVisible(true); } else { list2 = null; jSubset.setVisible(false); } jList.setModel(new DataListModel<>(list)); for (T item : selected) { int index = list.indexOf(item); if (index >= 0) { jList.addSelectionInterval(index, index); } } jAll.setSelected(jList.getSelectedIndices().length == list.size()); this.data = null; this.setVisible(true); return this.data; } @Override protected void windowShown() { } @Override protected void save() { data = new ArrayList<>(jList.getSelectedValuesList()); this.setVisible(false); } private class ListenerClass implements ListSelectionListener, ActionListener { @Override public void valueChanged(final ListSelectionEvent e) { jOK.setEnabled(emptyAllowed || jList.getSelectedIndices().length > 0); jAll.setSelected(jList.getSelectedIndices().length == jList.getModel().getSize()); } @Override public void actionPerformed(final ActionEvent e) { if (MultiSelectionActions.OK.name().equals(e.getActionCommand())) { save(); } else if (MultiSelectionActions.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); } else if (MultiSelectionActions.CHECK_ALL.name().equals(e.getActionCommand())) { if (jAll.isSelected()) { jList.selectAll(); } else { jList.clearSelection(); } } else if (MultiSelectionActions.SUBSET.name().equals(e.getActionCommand())) { if (jSubset.isSelected() && list2 != null) { List selected = jList.getSelectedValuesList(); jList.clearSelection(); jList.setModel(new DataListModel<>(list2)); for (T item : selected) { int index = list.indexOf(item); if (index >= 0) { jList.addSelectionInterval(index, index); } } } else { List selected = jList.getSelectedValuesList(); jList.clearSelection(); jList.setModel(new DataListModel<>(list)); for (T item : selected) { int index = list.indexOf(item); if (index >= 0) { jList.addSelectionInterval(index, index); } } } } } } private static class DataListModel extends AbstractListModel { private final List data; public DataListModel(final List data) { this.data = data; } @Override public int getSize() { return data.size(); } @Override public T getElementAt(final int index) { return data.get(index); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JMultiSelectionList.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.event.*; import java.util.ArrayList; import java.util.List; import javax.swing.*; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; public class JMultiSelectionList extends JList { private List selectedList; private ListenerClass listener = new ListenerClass(); public JMultiSelectionList() { this(new DefaultListModel()); } public JMultiSelectionList(final List listData) { this ( new AbstractListModel() { @Override public int getSize() { return listData.size(); } @Override public T getElementAt(final int i) { return listData.get(i); } } ); } public JMultiSelectionList(final ListModel model) { super(model); model.addListDataListener(listener); selectedList = new ArrayList<>(); this.addMouseListener(listener); this.addKeyListener(listener); this.addMouseMotionListener(listener); this.setDragEnabled(false); this.setSelectionModel(new DefaultListSelectionModel()); } @Override public void clearSelection() { super.clearSelection(); selectedList.clear(); } @Override public void setSelectedIndex(final int index) { super.setSelectedIndex(index); selectedList.clear(); selectedList.add((Integer) index); } @Override public void setSelectedIndices(final int[] indices) { super.setSelectedIndices(indices); selectedList.clear(); for (int i = 0; i < indices.length; i++) { selectedList.add((Integer) indices[i]); } } @Override public void setSelectedValue(final Object anObject, final boolean shouldScrool) { super.setSelectedValue(anObject, shouldScrool); selectedList.clear(); selectedList.add((Integer) getSelectedIndex()); } @Override public void addSelectionInterval(final int anchor, final int lead) { super.addSelectionInterval(anchor, lead); int start; int end; if (anchor < lead) { start = anchor; end = lead; } else { start = lead; end = anchor; } for (int i = start; i <= end; i++) { if (!selectedList.contains((Integer) i)) { selectedList.add((Integer) i); } } } @Override public void removeSelectionInterval(final int index0, final int index1) { super.removeSelectionInterval(index0, index1); int start; int end; if (index0 < index1) { start = index0; end = index1; } else { start = index1; end = index0; } for (int i = start; i <= end; i++) { if (!selectedList.contains((Integer) i)) { selectedList.add((Integer) i); } } } @Override public void setModel(final ListModel model) { super.setModel(model); model.addListDataListener(listener); } private class ListenerClass implements MouseListener, KeyListener, ListDataListener, MouseMotionListener { //MouseListener @Override public void mouseClicked(final MouseEvent e) { } @Override public void mouseReleased(final MouseEvent e) { } @Override public void mouseEntered(final MouseEvent e) { } @Override public void mouseExited(final MouseEvent e) { } @Override public void mousePressed(final MouseEvent e) { int index = locationToIndex(e.getPoint()); if (e.getButton() == MouseEvent.BUTTON1) { toggleSelectedIndex(index); e.consume(); } } //KeyListener @Override public void keyTyped(final KeyEvent e) { } @Override public void keyReleased(final KeyEvent e) { } @Override public void keyPressed(final KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_A && e.isControlDown()) { toggleSelectAll(); } if (e.getKeyCode() == KeyEvent.VK_UP) { setAnchor(getAnchorSelectionIndex() - 1); } if (e.getKeyCode() == KeyEvent.VK_DOWN) { setAnchor(getAnchorSelectionIndex() + 1); } if (e.getKeyCode() == KeyEvent.VK_SPACE || e.getKeyCode() == KeyEvent.VK_ENTER) { int index = getAnchorSelectionIndex(); toggleSelectedIndex(index); } e.consume(); } //MouseMotionListener @Override public void mouseMoved(final MouseEvent e) { } @Override public void mouseDragged(final MouseEvent e) { updateSelections(); } //ListDataListener @Override public void contentsChanged(final ListDataEvent e) { } @Override public void intervalAdded(final ListDataEvent e) { int index0 = e.getIndex0(); int index1 = e.getIndex1(); if (index0 == index1) { updateList(index0, 1); } } @Override public void intervalRemoved(final ListDataEvent e) { int index0 = e.getIndex0(); int index1 = e.getIndex1(); if (index0 == index1) { selectedList.remove((Integer) index0); updateList(index0, -1); } else { selectedList.clear(); } ensureIndexIsVisible(index1); } } //Public Methods public void addSelection(final int index, final boolean bSelected) { Integer indexObj = index; //is this selected? if so remove it. if (selectedList.contains(indexObj) && !bSelected) { selectedList.remove(indexObj); } if (!selectedList.contains(indexObj) && bSelected) { selectedList.add(indexObj); } //set selected indices updateSelections(); setAnchor(index); } public void toggleSelectAll() { if (!isEnabled()) { return; } //Ingnore update when disabled if (selectedList.size() != this.getModel().getSize()) { selectAll(); } else { clearSelection(); } } public void selectAll() { setValueIsAdjusting(true); ListModel lm = this.getModel(); selectedList.clear(); for (int i = 0; i < lm.getSize(); i++) { selectedList.add(i); } setSelectionInterval(0, lm.getSize() - 1); setAnchor(0); } //Private Methods private void updateList(final int index, final int fix) { List fixedIndices = new ArrayList<>(selectedList.size()); for (int i = 0; i < selectedList.size(); i++) { int item = selectedList.get(i); if (item >= index) { item = item + fix; fixedIndices.add(item); } else { fixedIndices.add(item); } } selectedList = fixedIndices; } private void setAnchor(final int nAnchor) { setValueIsAdjusting(true); ListSelectionModel sm = this.getSelectionModel(); ListModel lm = this.getModel(); if (nAnchor >= 0 && nAnchor < lm.getSize()) { if (this.isSelectedIndex(nAnchor)) { sm.removeSelectionInterval(nAnchor, nAnchor); sm.addSelectionInterval(nAnchor, nAnchor); } else { sm.addSelectionInterval(nAnchor, nAnchor); sm.removeSelectionInterval(nAnchor, nAnchor); } ensureIndexIsVisible(nAnchor); } setValueIsAdjusting(false); } private void toggleSelectedIndex(final int index) { if (!isEnabled()) { return; } //Ingnore update when disabled Integer indexObj = index; //is this selected? if so remove it. if (selectedList.contains(indexObj)) { selectedList.remove(indexObj); } else { //otherwise add it to our list selectedList.add(indexObj); } //set selected indices updateSelections(); setAnchor(index); } private void updateSelections() { //copy to an int array int[] arr = new int[selectedList.size()]; for (int i = 0; i < arr.length; i++) { int item = selectedList.get(i); arr[i] = item; } //set selected indices setSelectedIndices(arr); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JOptionsDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.GroupLayout.Group; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JRadioButton; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JOptionsDialog extends JDialogCentered { private enum StockpileImportAction { OK, CANCEL } private static final CancelOption CANCEL_OPTION = new CancelOption(); private final JLabel jName; private final JCheckBox jAll; private final JButton jOK; private final JButton jCancel; private final List containers = new ArrayList<>(); private final ListenerClass listenerClass; private OptionEnum option = null; public JOptionsDialog(Program program) { super(program, GuiShared.get().importOptions()); listenerClass = new ListenerClass(); jName = new JLabel(); jName.setFont(jName.getFont().deriveFont(Font.BOLD)); jAll = new JCheckBox(); jOK = new JButton(GuiShared.get().ok()); jOK.setActionCommand(StockpileImportAction.OK.name()); jOK.addActionListener(listenerClass); jCancel = new JButton(GuiShared.get().cancel()); jCancel.setActionCommand(StockpileImportAction.CANCEL.name()); jCancel.addActionListener(listenerClass); } private void doLayout(List options, OptionEnum defaultOption, boolean showAll) { jPanel.removeAll(); containers.clear(); Group optionHorizontalGroup = layout.createParallelGroup(GroupLayout.Alignment.LEADING); Group helpHorizontalGroup = layout.createParallelGroup(GroupLayout.Alignment.LEADING); Group horizontalGroup = layout.createParallelGroup(GroupLayout.Alignment.CENTER); Group verticalGroup = layout.createSequentialGroup(); //Name if (!jName.getText().isEmpty()) { verticalGroup.addComponent(jName, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()); horizontalGroup.addComponent(jName); } //Options if (defaultOption == null && !options.isEmpty()) { defaultOption = options.get(0); } ButtonGroup buttonGroup = new ButtonGroup(); for (OptionEnum optionEnum : options) { OptionsContainer optionsContainer = new OptionsContainer(optionEnum); containers.add(optionsContainer); buttonGroup.add(optionsContainer.getRadioButton()); optionHorizontalGroup.addComponent(optionsContainer.getRadioButton()); helpHorizontalGroup.addComponent(optionsContainer.getLabel()); optionsContainer.getRadioButton().setSelected(defaultOption == optionEnum); verticalGroup.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(optionsContainer.getRadioButton(), Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(optionsContainer.getLabel(), Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } horizontalGroup .addGroup(layout.createSequentialGroup() .addGroup(optionHorizontalGroup) .addGap(20) .addGroup(helpHorizontalGroup) ); verticalGroup.addGap(20); //All if (showAll) { horizontalGroup .addGroup(layout.createSequentialGroup() .addComponent(jAll) .addGap(0, 0, Integer.MAX_VALUE) ); verticalGroup .addComponent(jAll, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGap(20); } //OK/Cancel verticalGroup.addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); horizontalGroup.addGroup(layout.createSequentialGroup() .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ); layout.setHorizontalGroup(horizontalGroup); layout.setVerticalGroup(verticalGroup); } public OptionEnum show(String heading, String title, String all, boolean enableAll, boolean showAll, List options, OptionEnum defaultOption) { option = null; jName.setText(heading); getDialog().setTitle(title); doLayout(options, defaultOption, showAll); jAll.setSelected(false); jAll.setText(all); jAll.setEnabled(enableAll); setVisible(true); return option; } @Override protected JComponent getDefaultFocus() { return jOK; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { } @Override protected void save() { for (OptionsContainer container : containers) { if (container.getRadioButton().isSelected()) { option = container.getOption(); option.setAll(jAll.isSelected()); break; } } setVisible(false); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(ActionEvent e) { if (StockpileImportAction.OK.name().equals(e.getActionCommand())) { save(); } if (StockpileImportAction.CANCEL.name().equals(e.getActionCommand())) { option = CANCEL_OPTION; setVisible(false); } } } public static interface OptionEnum { public String getText(); public String getHelp(); public boolean isAll(); public void setAll(boolean all); } private static class CancelOption implements OptionEnum { @Override public String getText() { return ""; } @Override public String getHelp() { return ""; } @Override public boolean isAll() { return true; } @Override public void setAll(boolean all) { } } private static class OptionsContainer { private final OptionEnum option; private final JRadioButton jRadioButton; private final JLabel jLabel; public OptionsContainer(OptionEnum option) { this.option = option; option.setAll(false); //Reset jRadioButton = new JRadioButton(option.getText()); jLabel = new JLabel(option.getHelp()); } public OptionEnum getOption() { return option; } public JRadioButton getRadioButton() { return jRadioButton; } public JLabel getLabel() { return jLabel; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JSelectionDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collection; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JSelectionDialog extends JDialogCentered { private enum ContainerDialogAction { OK, CANCEL } private final JComboBox jLocations; private final JButton jOK; private T selected = null; public JSelectionDialog(Program program) { super(program, ""); ListenerClass listenerClass = new ListenerClass(); jLocations = new JComboBox<>(); jOK = new JButton(GuiShared.get().ok()); jOK.setActionCommand(ContainerDialogAction.OK.name()); jOK.addActionListener(listenerClass); JButton jCancel = new JButton(GuiShared.get().cancel()); jCancel.setActionCommand(ContainerDialogAction.CANCEL.name()); jCancel.addActionListener(listenerClass); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jLocations, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, 600) .addGroup(layout.createSequentialGroup() .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jLocations, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } public T show(String title, Collection data) { if (data.size() == 1) { return data.iterator().next(); } getDialog().setTitle(title); selected = null; jLocations.setModel(new ListComboBoxModel<>(data)); setVisible(true); return selected; } @Override protected JComponent getDefaultFocus() { return jLocations; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() {} @Override protected void save() { selected = jLocations.getItemAt(jLocations.getSelectedIndex()); setVisible(false); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(ActionEvent e) { if (ContainerDialogAction.OK.name().equals(e.getActionCommand())) { save(); } if (ContainerDialogAction.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JTextAreaPlaceholder.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Insets; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import javax.swing.BorderFactory; import javax.swing.JTextArea; import javax.swing.border.Border; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; /** * JTextArea with information text displayed when empty. */ public class JTextAreaPlaceholder extends JTextArea { /** * Placeholder font. */ private Font placeholderFont = null; /** * Placeholder italic font. */ private boolean italic = true; /** * Placeholder mock used for painting. */ private JTextArea jPlaceholder; /** * Text to display when empty. */ private String placeholderText; /** * Paint placeholder. */ private boolean paintPlaceholder; /** * Create a textfield with hint. */ public JTextAreaPlaceholder() { this(null, null); } public JTextAreaPlaceholder(String placeholder) { this(null, placeholder); } /** * Create a textfield with hint. * * @param text * @param placeholder Text displayed when empty */ public JTextAreaPlaceholder(String text, String placeholder) { super(text); if (placeholder == null) { placeholder = ""; } this.placeholderText = placeholder; getMock().setOpaque(false); getMock().setBackground(new Color(0,0,0,0)); //Nimbus LaF getMock().setForeground(getDisabledTextColor()); placeholderFont = getFont(); updatePlaceholderBorder(); updatePlaceholderFont(); addFocusListener(new FocusListener() { @Override public void focusLost(FocusEvent e) { updateShown(); } @Override public void focusGained(FocusEvent e) { updateShown(); } }); getDocument().addDocumentListener(new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { updateShown(); } @Override public void removeUpdate(DocumentEvent e) { updateShown(); } @Override public void changedUpdate(DocumentEvent e) { updateShown(); } }); addComponentListener(new ComponentListener() { @Override public void componentResized(ComponentEvent e) { updateSize(); } @Override public void componentMoved(ComponentEvent e) { } @Override public void componentShown(ComponentEvent e) { updateSize(); } @Override public void componentHidden(ComponentEvent e) { } }); } private JTextArea getMock() { if (jPlaceholder == null) { jPlaceholder = new JTextArea(); } return jPlaceholder; } @Override public void setFont(Font f) { placeholderFont = f; updatePlaceholderFont(); super.setFont(f); } @Override public void setColumns(int columns) { getMock().setColumns(columns); super.setColumns(columns); } @Override public void setRows(int rows) { getMock().setRows(rows); super.setRows(rows); } @Override public void setTabSize(int size) { getMock().setTabSize(size); super.setTabSize(size); } @Override public void setWrapStyleWord(boolean word) { getMock().setWrapStyleWord(word); super.setWrapStyleWord(word); } @Override public void setLineWrap(boolean wrap) { getMock().setLineWrap(wrap); super.setLineWrap(wrap); } @Override public void setBorder(Border border) { super.setBorder(border); updatePlaceholderBorder(); } private void updatePlaceholderBorder() { Insets insets = getInsets(); getMock().setBorder(BorderFactory.createEmptyBorder(insets.top, insets.left, insets.bottom, insets.right)); revalidate(); repaint(); } private void updateShown() { updateShown(false); } private void updateShown(boolean forceRepaint) { boolean paint = getText().isEmpty() && placeholderText != null && !placeholderText.isEmpty(); boolean repaint = forceRepaint || paint != paintPlaceholder; getMock().setText(placeholderText); paintPlaceholder = paint; if (repaint) { revalidate(); repaint(); } } private void updateSize() { Dimension size = getSize(); boolean repaint = getMock().getSize() != size; getMock().setSize(size); if (repaint) { revalidate(); repaint(); } } public void setPlaceholderText(String placeholder) { this.placeholderText = placeholder; updateShown(true); } public void setPlaceholderForeground(Color fg) { getMock().setForeground(fg); revalidate(); repaint(); } public boolean isPlaceholderItalic() { return italic; } public void setPlaceholderFont(Font f) { placeholderFont = f; updatePlaceholderFont(); } public void setPlaceholderItalic(boolean italic) { this.italic = italic; updatePlaceholderFont(); } private void updatePlaceholderFont() { if (italic) { getMock().setFont(placeholderFont.deriveFont(Font.ITALIC)); } else { getMock().setFont(placeholderFont); } revalidate(); repaint(); } @Override public void paint(Graphics g) { if (paintPlaceholder) { super.paint(g); getMock().paint(g); } else { super.paint(g); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JTextDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.Color; import java.awt.Component; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListCellRenderer; import javax.swing.GroupLayout; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.ListCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Colors; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.CopyHandler; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JTextDialog extends JDialogCentered { private enum TextDialogAction { IMPORT_TYPE, TO_CLIPBOARD, TO_FILE, FROM_CLIPBOARD, FROM_FILE, CANCEL, OK } private final JTextAreaPlaceholder jText; private final JComboBox jImportTypes; private final JButton jToClipboard; private final JButton jFromClipboard; private final JButton jToFile; private final JButton jFromFile; private final JButton jOK; private final JButton jCancel; private final Color importColor; private final JCustomFileChooser jFileChooser; private String returnValue = null; public JTextDialog(Window window) { super(null, "", window, null); jFileChooser = new JCustomFileChooser("txt"); jFileChooser.setMultiSelectionEnabled(false); jFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); ListenerClass listener = new ListenerClass(); jImportTypes = new JComboBox<>(); jImportTypes.setRenderer(new TextImportListRenderer()); jImportTypes.setActionCommand(TextDialogAction.IMPORT_TYPE.name()); jImportTypes.addActionListener(listener); jToClipboard = new JButton(GuiShared.get().textToClipboard(), Images.EDIT_COPY.getIcon()); jToClipboard.setActionCommand(TextDialogAction.TO_CLIPBOARD.name()); jToClipboard.addActionListener(listener); jToFile = new JButton(GuiShared.get().textToFile(), Images.FILTER_SAVE.getIcon()); jToFile.setActionCommand(TextDialogAction.TO_FILE.name()); jToFile.addActionListener(listener); jFromClipboard = new JButton(GuiShared.get().textFromClipboard(), Images.EDIT_PASTE.getIcon()); jFromClipboard.setActionCommand(TextDialogAction.FROM_CLIPBOARD.name()); jFromClipboard.addActionListener(listener); jFromFile = new JButton(GuiShared.get().textFromFile(), Images.FILTER_LOAD.getIcon()); jFromFile.setActionCommand(TextDialogAction.FROM_FILE.name()); jFromFile.addActionListener(listener); jOK = new JButton(); jOK.setActionCommand(TextDialogAction.OK.name()); jOK.addActionListener(listener); jCancel = new JButton(GuiShared.get().cancel()); jCancel.setActionCommand(TextDialogAction.CANCEL.name()); jCancel.addActionListener(listener); jText = new JTextAreaPlaceholder(); jText.setTabSize(4); jText.setLineWrap(true); jText.setEditable(false); jText.setFont(jPanel.getFont()); importColor = jText.getBackground(); JScrollPane jTextScroll = new JScrollPane(jText); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jImportTypes) .addComponent(jToClipboard) .addComponent(jToFile) .addComponent(jFromClipboard) .addComponent(jFromFile) ) .addComponent(jTextScroll, 500, 500, Integer.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addGap(0, 0, Integer.MAX_VALUE) .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jImportTypes, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jToClipboard, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jToFile, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFromClipboard, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFromFile, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jTextScroll, 400, 400, Integer.MAX_VALUE) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } @Override protected JComponent getDefaultFocus() { return jText; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { } @Override protected void save() { } public void setLineWrap(boolean wrap) { jText.setLineWrap(wrap); } public String importText() { return importText("", ""); } public String importText(String text) { return importText(text, ""); } public String importText(String text, String example) { return importText(text, example, null, null).getText(); } public TextReturn importText(E[] imports) { return importText("", "", imports, null); } public TextReturn importText(E[] imports, E selected) { return importText("", "", imports, selected); } public TextReturn importText(String text, E[] imports) { return importText(text, "", imports, null); } public TextReturn importText(String text, E[] imports, E selected) { return importText(text, "", imports, selected); } public TextReturn importText(String text, String example, E[] imports, E selected) { getDialog().setTitle(GuiShared.get().textImport()); if (imports == null || imports.length < 1) { jImportTypes.removeAllItems(); jImportTypes.setVisible(false); } else { jImportTypes.setModel(new DefaultComboBoxModel<>(imports)); if (selected != null) { jImportTypes.setSelectedItem(selected); } else { jImportTypes.setSelectedIndex(0); } example = jImportTypes.getItemAt(jImportTypes.getSelectedIndex()).getExample(); jImportTypes.setVisible(true); } jText.setEditable(true); jText.setOpaque(true); jText.setBackground(importColor); jText.setText(text); if (example == null) { example = ""; //null not allowed! } jText.setPlaceholderText(example); jOK.setText(GuiShared.get().ok()); jCancel.setVisible(true); jFromClipboard.setVisible(true); jFromFile.setVisible(true); jToClipboard.setVisible(false); jToFile.setVisible(false); returnValue = null; setVisible(true); if (imports == null) { return new TextReturn<>(returnValue, null); } else { return new TextReturn<>(returnValue, imports[jImportTypes.getSelectedIndex()]); } } public void exportText(String text) { getDialog().setTitle(GuiShared.get().textExport()); jText.setEditable(false); jText.setOpaque(false); jText.setBackground(Colors.COMPONENT_TRANSPARENT.getColor()); jText.setText(text); jOK.setText(GuiShared.get().textClose()); jCancel.setVisible(false); jFromClipboard.setVisible(false); jFromFile.setVisible(false); jImportTypes.setVisible(false); jToClipboard.setVisible(true); jToFile.setVisible(true); setVisible(true); } private void toFile() { int showSaveDialog = jFileChooser.showSaveDialog(getDialog()); if (showSaveDialog == JCustomFileChooser.APPROVE_OPTION) { BufferedWriter writer = null; try { writer = new BufferedWriter(new FileWriter(jFileChooser.getSelectedFile())); writer.write(jText.getText()); writer.close(); } catch (IOException ex) { JOptionPane.showMessageDialog(getDialog(), GuiShared.get().textSaveFailMsg(), GuiShared.get().textSaveFailTitle(), JOptionPane.WARNING_MESSAGE); } finally { if (writer != null) { try { writer.close(); } catch (IOException ex) { //Ohh well we tried our best } } } } } private void fromFile() { int showSaveDialog = jFileChooser.showOpenDialog(getDialog()); if (showSaveDialog == JCustomFileChooser.APPROVE_OPTION) { BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(jFileChooser.getSelectedFile())); String line; StringBuilder builder = new StringBuilder(); while ((line = reader.readLine()) != null) { builder.append(line); builder.append("\r\n"); } jText.setText(builder.toString()); } catch (IOException e) { JOptionPane.showMessageDialog(getDialog(), GuiShared.get().textLoadFailMsg(), GuiShared.get().textLoadFailTitle(), JOptionPane.WARNING_MESSAGE); } finally { try { if (reader != null) { reader.close(); } } catch (IOException ex) { //Ohh well we tried our best } } } } public static interface SimpleTextImport { public String getExample(); public Icon getIcon(); public String getType(); } public static class TextReturn { private final String text; private final E type; public TextReturn(String text, E type) { this.text = text; this.type = type; } public String getText() { return text; } public E getType() { return type; } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (TextDialogAction.TO_CLIPBOARD.name().equals(e.getActionCommand())) { CopyHandler.toClipboard(jText.getText()); } else if (TextDialogAction.TO_FILE.name().equals(e.getActionCommand())) { toFile(); } else if (TextDialogAction.FROM_CLIPBOARD.name().equals(e.getActionCommand())) { CopyHandler.paste(jText); } else if (TextDialogAction.FROM_FILE.name().equals(e.getActionCommand())) { fromFile(); } else if (TextDialogAction.OK.name().equals(e.getActionCommand())) { returnValue = jText.getText(); setVisible(false); } else if (TextDialogAction.CANCEL.name().equals(e.getActionCommand())) { returnValue = null; setVisible(false); } else if (TextDialogAction.IMPORT_TYPE.name().equals(e.getActionCommand())) { SimpleTextImport textImport = jImportTypes.getItemAt(jImportTypes.getSelectedIndex()); jText.setPlaceholderText(textImport.getExample()); } } } class TextImportListRenderer implements ListCellRenderer { private final DefaultListCellRenderer renderer; public TextImportListRenderer() { renderer = new DefaultListCellRenderer(); } @Override public Component getListCellRendererComponent(JList list, SimpleTextImport value, int index, boolean isSelected, boolean cellHasFocus) { JLabel label = (JLabel) renderer.getListCellRendererComponent(list, value.getType(), index, isSelected, cellHasFocus); // Set icon to display for value label.setIcon(value.getIcon()); return label; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JTreemap.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Point; import java.awt.RenderingHints; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import javax.swing.JComponent; import javax.swing.SwingUtilities; import javax.swing.UIManager; import net.nikr.eve.jeveasset.gui.shared.Formatter; public class JTreemap extends JComponent { public interface SelectionListener { void itemSelected(String name); } private static final double GAP = 1.0; private static final double MAX_TILE_ASPECT_RATIO = 4.0; private static final int MIN_TILE_SIZE = 6; private static final int LABEL_PADDING = 4; private static final int AMBIENT_LIGHT = 30; private static final double LIGHT_X = 0.09759; private static final double LIGHT_Y = 0.19518; private static final double LIGHT_Z = 0.9759; private static final double CUSHION_HEIGHT = 0.35; private final SelectionListener selectionListener; private final List tiles = new ArrayList<>(); private Dimension lastSize; private boolean layoutDirty = true; private Tile hovered; private final Font labelFont; public JTreemap(final SelectionListener selectionListener) { this.selectionListener = selectionListener; setOpaque(true); Color background = UIManager.getColor("Panel.background"); if (background != null) { setBackground(background); } labelFont = UIManager.getFont("Label.font"); setToolTipText(""); addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { layoutDirty = true; repaint(); } }); addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseMoved(MouseEvent e) { Tile tile = findTile(e.getPoint()); if (tile != hovered) { hovered = tile; repaint(); } } }); addMouseListener(new MouseAdapter() { @Override public void mouseExited(MouseEvent e) { if (hovered != null) { hovered = null; repaint(); } } @Override public void mouseClicked(MouseEvent e) { if (!SwingUtilities.isLeftMouseButton(e)) { return; } Tile tile = findTile(e.getPoint()); if (tile != null && selectionListener != null) { selectionListener.itemSelected(tile.name); } } }); } public void setItems(final Map valuesByName) { tiles.clear(); hovered = null; if (valuesByName != null) { for (Map.Entry entry : valuesByName.entrySet()) { String name = entry.getKey(); if (name == null || name.isEmpty()) { name = "Unknown"; } double value = entry.getValue() == null ? 0.0 : entry.getValue(); if (value <= 0) { continue; } tiles.add(new Tile(name, value)); } } Collections.sort(tiles, new Comparator() { @Override public int compare(Tile o1, Tile o2) { return Double.compare(o2.value, o1.value); } }); layoutDirty = true; repaint(); } @Override public String getToolTipText(MouseEvent event) { Tile tile = findTile(event.getPoint()); if (tile == null) { return null; } return "" + escapeHtml(tile.name) + "
" + Formatter.iskFormat(tile.value) + ""; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); if (tiles.isEmpty()) { return; } Graphics2D g2 = (Graphics2D) g.create(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); updateLayoutIfNeeded(); for (Tile tile : tiles) { if (tile.rect == null || tile.rect.width <= 0 || tile.rect.height <= 0) { continue; } Rectangle2D.Double paintRect = inset(tile.rect, GAP); if (paintRect.width <= 0 || paintRect.height <= 0) { continue; } paintCushion(g2, tile, paintRect); g2.setColor(tile.borderColor); g2.draw(paintRect); paintLabel(g2, tile, paintRect); } if (hovered != null && hovered.rect != null) { Rectangle2D.Double paintRect = inset(hovered.rect, GAP); g2.setColor(hovered.highlightColor); g2.draw(paintRect); } g2.dispose(); } private void updateLayoutIfNeeded() { Dimension size = getSize(); if (size.width <= 0 || size.height <= 0) { return; } if (!layoutDirty && lastSize != null && lastSize.equals(size)) { return; } lastSize = size; layoutDirty = false; layoutTiles(size); } private void layoutTiles(Dimension size) { double total = 0.0; for (Tile tile : tiles) { total += tile.value; tile.rect = null; } if (total <= 0) { return; } Insets insets = getInsets(); double x = insets.left; double y = insets.top; double width = size.getWidth() - insets.left - insets.right; double height = size.getHeight() - insets.top - insets.bottom; if (width <= 0 || height <= 0) { return; } double aspect = width / height; if (aspect > MAX_TILE_ASPECT_RATIO) { double newWidth = height * MAX_TILE_ASPECT_RATIO; x += (width - newWidth) / 2.0; width = newWidth; } else if ((1.0 / aspect) > MAX_TILE_ASPECT_RATIO) { double newHeight = width * MAX_TILE_ASPECT_RATIO; y += (height - newHeight) / 2.0; height = newHeight; } double area = width * height; double scale = area / total; if (!Double.isFinite(scale) || scale <= 0) { return; } double minValue = MIN_TILE_SIZE / scale; List layoutTiles = new ArrayList<>(); for (Tile tile : tiles) { if (tile.value >= minValue) { layoutTiles.add(tile); } } if (layoutTiles.isEmpty()) { return; } Rectangle2D.Double remaining = new Rectangle2D.Double(x, y, width, height); int index = 0; while (index < layoutTiles.size()) { List row = squarifyRow(layoutTiles, index, remaining, scale); if (row.isEmpty()) { break; } Rectangle2D.Double next = layoutRow(remaining, scale, row); if (next == null) { break; } index += row.size(); remaining = next; } } private List squarifyRow(List tiles, int startIndex, Rectangle2D.Double rect, double scale) { List row = new ArrayList<>(); double length = Math.max(rect.width, rect.height); if (length <= 0 || scale <= 0) { return row; } double scaledLengthSquare = (length * length) / scale; double sum = 0.0; double lastWorst = -1.0; for (int i = startIndex; i < tiles.size(); i++) { Tile tile = tiles.get(i); double nextSum = sum + tile.value; if (nextSum <= 0 || tile.value <= 0) { break; } double sumSquare = nextSum * nextSum; double worst = row.isEmpty() ? Math.max(scaledLengthSquare * tile.value / sumSquare, sumSquare / (scaledLengthSquare * tile.value)) : Math.max(scaledLengthSquare * row.get(0).value / sumSquare, sumSquare / (scaledLengthSquare * tile.value)); if (lastWorst >= 0.0 && worst > lastWorst) { break; } lastWorst = worst; row.add(tile); sum = nextSum; } if (row.isEmpty() || lastWorst > MAX_TILE_ASPECT_RATIO) { row.clear(); } return row; } private Rectangle2D.Double layoutRow(Rectangle2D.Double rect, double scale, List row) { if (row.isEmpty()) { return null; } double sum = sumValues(row); if (sum <= 0) { return null; } double primary = Math.max(rect.width, rect.height); if (primary <= 0) { return null; } double secondary = (sum * scale) / primary; if (secondary < MIN_TILE_SIZE) { return null; } boolean horizontal = rect.width >= rect.height; double offset = 0.0; double remaining = primary; for (int i = 0; i < row.size(); i++) { Tile tile = row.get(i); double childSize = tile.value / sum * primary; if (childSize > remaining) { childSize = remaining; } remaining -= childSize; if (childSize >= MIN_TILE_SIZE) { if (horizontal) { tile.rect = new Rectangle2D.Double(rect.x + offset, rect.y, childSize, secondary); } else { tile.rect = new Rectangle2D.Double(rect.x, rect.y + offset, secondary, childSize); } offset += childSize; } } if (horizontal) { return new Rectangle2D.Double(rect.x, rect.y + secondary, rect.width, rect.height - secondary); } return new Rectangle2D.Double(rect.x + secondary, rect.y, rect.width - secondary, rect.height); } private double sumValues(List tiles) { double sum = 0.0; for (Tile tile : tiles) { sum += tile.value; } return sum; } private Tile findTile(Point point) { updateLayoutIfNeeded(); for (Tile tile : tiles) { if (tile.rect != null && tile.rect.contains(point)) { return tile; } } return null; } private void paintLabel(Graphics2D g2, Tile tile, Rectangle2D.Double rect) { if (labelFont != null) { g2.setFont(labelFont); } FontMetrics metrics = g2.getFontMetrics(); int maxWidth = (int) (rect.width - LABEL_PADDING * 2); int maxHeight = (int) (rect.height - LABEL_PADDING * 2); if (maxWidth <= 10 || maxHeight < metrics.getHeight()) { return; } g2.setColor(tile.textColor); String name = truncate(tile.name, metrics, maxWidth); if (!name.isEmpty()) { int x = (int) (rect.x + LABEL_PADDING); int y = (int) (rect.y + LABEL_PADDING + metrics.getAscent()); g2.drawString(name, x, y); } if (maxHeight >= metrics.getHeight() * 2 + 2) { String value = Formatter.iskFormat(tile.value); String valueText = truncate(value, metrics, maxWidth); if (!valueText.isEmpty()) { int x = (int) (rect.x + LABEL_PADDING); int y = (int) (rect.y + LABEL_PADDING + metrics.getAscent() + metrics.getHeight() + 2); g2.drawString(valueText, x, y); } } } private void paintCushion(Graphics2D g2, Tile tile, Rectangle2D.Double rect) { int width = (int) Math.round(rect.width); int height = (int) Math.round(rect.height); if (width < 2 || height < 2) { g2.setColor(tile.color); g2.fill(rect); return; } BufferedImage cushion = getCushion(tile, width, height); if (cushion == null) { g2.setColor(tile.color); g2.fill(rect); return; } int x = (int) Math.round(rect.x); int y = (int) Math.round(rect.y); g2.drawImage(cushion, x, y, width, height, null); } private BufferedImage getCushion(Tile tile, int width, int height) { if (tile.cushion != null && tile.cushionWidth == width && tile.cushionHeight == height) { return tile.cushion; } BufferedImage cushion = renderCushion(tile, width, height); tile.cushion = cushion; tile.cushionWidth = width; tile.cushionHeight = height; return cushion; } private BufferedImage renderCushion(Tile tile, int width, int height) { if (width <= 0 || height <= 0) { return null; } double xx2 = 0.0; double xx1 = 0.0; double yy2 = 0.0; double yy1 = 0.0; if (width > 1) { xx2 = squareRidge(xx2, CUSHION_HEIGHT, 0, width - 1); xx1 = linearRidge(xx1, CUSHION_HEIGHT, 0, width - 1); } if (height > 1) { yy2 = squareRidge(yy2, CUSHION_HEIGHT, 0, height - 1); yy1 = linearRidge(yy1, CUSHION_HEIGHT, 0, height - 1); } BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); int maxRed = Math.max(0, tile.color.getRed() - AMBIENT_LIGHT); int maxGreen = Math.max(0, tile.color.getGreen() - AMBIENT_LIGHT); int maxBlue = Math.max(0, tile.color.getBlue() - AMBIENT_LIGHT); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { double nx = 2.0 * xx2 * x + xx1; double ny = 2.0 * yy2 * y + yy1; double denom = Math.sqrt(nx * nx + ny * ny + 1.0); double cosa = (nx * LIGHT_X + ny * LIGHT_Y + LIGHT_Z) / denom; int red = (int) (maxRed * cosa + 0.5); int green = (int) (maxGreen * cosa + 0.5); int blue = (int) (maxBlue * cosa + 0.5); if (red < 0) { red = 0; } if (green < 0) { green = 0; } if (blue < 0) { blue = 0; } red = Math.min(255, red + AMBIENT_LIGHT); green = Math.min(255, green + AMBIENT_LIGHT); blue = Math.min(255, blue + AMBIENT_LIGHT); int rgb = (0xFF << 24) | (red << 16) | (green << 8) | blue; image.setRGB(x, y, rgb); } } return image; } private double squareRidge(double squareCoefficient, double height, int x1, int x2) { if (x2 != x1) { squareCoefficient -= 4.0 * height / (x2 - x1); } return squareCoefficient; } private double linearRidge(double linearCoefficient, double height, int x1, int x2) { if (x2 != x1) { linearCoefficient += 4.0 * height * (x2 + x1) / (x2 - x1); } return linearCoefficient; } private Rectangle2D.Double inset(Rectangle2D.Double rect, double inset) { double value = inset / 2.0; double x = rect.x + value; double y = rect.y + value; double width = rect.width - inset; double height = rect.height - inset; return new Rectangle2D.Double(x, y, width, height); } private String truncate(String text, FontMetrics metrics, int maxWidth) { if (text == null) { return ""; } if (metrics.stringWidth(text) <= maxWidth) { return text; } String ellipsis = "..."; int ellipsisWidth = metrics.stringWidth(ellipsis); int available = maxWidth - ellipsisWidth; if (available <= 0) { return ""; } int length = text.length(); while (length > 0 && metrics.stringWidth(text.substring(0, length)) > available) { length--; } if (length <= 0) { return ""; } return text.substring(0, length) + ellipsis; } private String escapeHtml(String text) { if (text == null) { return ""; } return text.replace("&", "&").replace("<", "<").replace(">", ">"); } private static Color colorForName(String name) { int hash = name.hashCode(); float hue = ((hash >>> 16) & 0xFF) / 255f; float saturation = 0.45f + ((hash >>> 8) & 0x7F) / 255f * 0.35f; float brightness = 0.85f; return Color.getHSBColor(hue, saturation, brightness); } private static Color darken(Color color, double factor) { int r = (int) Math.max(0, color.getRed() * factor); int g = (int) Math.max(0, color.getGreen() * factor); int b = (int) Math.max(0, color.getBlue() * factor); return new Color(r, g, b, color.getAlpha()); } private static boolean isDark(Color color) { double luminance = (0.299 * color.getRed() + 0.587 * color.getGreen() + 0.114 * color.getBlue()) / 255.0; return luminance < 0.5; } private static class Tile { private final String name; private final double value; private final Color color; private final Color borderColor; private final Color highlightColor; private final Color textColor; private Rectangle2D.Double rect; private BufferedImage cushion; private int cushionWidth; private int cushionHeight; private Tile(String name, double value) { this.name = name; this.value = value; this.color = colorForName(name); this.borderColor = darken(color, 0.85); this.highlightColor = darken(color, 0.65); this.textColor = isDark(color) ? Color.WHITE : Color.BLACK; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/JWorking.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import javax.swing.JPanel; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.images.Images; public class JWorking extends JPanel { private static final int IMG_FRAMES = 24; private static final int IMG_WIDTH = 32; private static final int IMG_HEIGHT = 32; private final BufferedImage[] loadingImages; private int currentLoadingImage = 0; private Worker worker; public JWorking() { this.setMinimumSize(new Dimension(IMG_WIDTH, IMG_HEIGHT)); this.setPreferredSize(new Dimension(IMG_WIDTH, IMG_HEIGHT)); this.setMaximumSize(new Dimension(IMG_WIDTH, IMG_HEIGHT)); this.setDoubleBuffered(true); loadingImages = new BufferedImage[IMG_FRAMES]; for (int i = 0; i < IMG_FRAMES; i++) { String number; if ((i + 1) < 10) { number = "0" + (i + 1); } else { number = "" + (i + 1); } loadingImages[i] = Images.getBufferedImage("working" + number + ".png"); } ListenerClass listenerClass = new ListenerClass(); addAncestorListener(listenerClass); } private void start() { if (worker == null || worker.isStopped()) { //Only start if not already running worker = new Worker(this); worker.start(); } } private void end() { if (worker != null) { worker.stopASAP(); } } @Override protected void paintComponent(final Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; if (loadingImages[currentLoadingImage] != null) { g2.drawImage(loadingImages[currentLoadingImage], 0, 0, null); } } private class ListenerClass implements AncestorListener { @Override public void ancestorAdded(AncestorEvent event) { start(); } @Override public void ancestorRemoved(AncestorEvent event) { end(); } @Override public void ancestorMoved(AncestorEvent event) { } } public class Worker extends Thread { private static final int UPDATE_DELAY = 100; private final JWorking jWorking; private boolean run = true; public Worker(final JWorking jWorking) { this.jWorking = jWorking; currentLoadingImage = 0; } @Override public void run() { while (isRun()) { currentLoadingImage++; if (currentLoadingImage >= IMG_FRAMES) { currentLoadingImage = 0; } try { Program.ensureEDT(new Runnable() { @Override public void run() { jWorking.repaint(); } }); } catch (RuntimeException e) { break; } try { synchronized(this) { wait(UPDATE_DELAY); } } catch (InterruptedException e) { break; } } } private synchronized boolean isRun() { return run; } public synchronized void stopASAP() { run = false; } public synchronized boolean isStopped() { return !run; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/components/ListComboBoxModel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.util.Collection; import javax.swing.DefaultComboBoxModel; public class ListComboBoxModel extends DefaultComboBoxModel { public ListComboBoxModel() {} public ListComboBoxModel(Collection items) { super(); for (E e : items) { addElement(e); } } public ListComboBoxModel(E[] items) { super(items); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/ColumnCache.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import java.util.Map; public interface ColumnCache { public Map getCache(); public void addCache(E e, String haystack); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/ExportDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import ca.odell.glazedlists.EventList; import java.awt.CardLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.AbstractListModel; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JSlider; import javax.swing.JTextField; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ExportSettings; import net.nikr.eve.jeveasset.data.settings.ExportSettings.ColumnSelection; import net.nikr.eve.jeveasset.data.settings.ExportSettings.DecimalSeparator; import net.nikr.eve.jeveasset.data.settings.ExportSettings.ExportFormat; import net.nikr.eve.jeveasset.data.settings.ExportSettings.FilterSelection; import net.nikr.eve.jeveasset.data.settings.ExportSettings.LineDelimiter; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.DocumentFactory; import net.nikr.eve.jeveasset.gui.shared.components.JCustomFileChooser; import net.nikr.eve.jeveasset.gui.shared.components.JDefaultField; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.shared.components.JMultiSelectionList; import net.nikr.eve.jeveasset.gui.shared.components.ListComboBoxModel; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.View; import net.nikr.eve.jeveasset.i18n.DialoguesExport; public class ExportDialog extends JDialogCentered { private enum ExportAction { OK, CANCEL, DEFAULT, FILTER_CHANGED, VIEW_CHANGED, FORMAT_CHANGED } //Filter private final JRadioButton jNoFilter; private final JRadioButton jSavedFilter; private final JRadioButton jCurrentFilter; private final JComboBox jFilters; //Columns private final JRadioButton jViewCurrent; private final JRadioButton jViewSelect; private final JRadioButton jViewSaved; private final JComboBox jViews; private final JMultiSelectionList> jColumnSelection; private final JButton jViewSelectAll; //Format private final JRadioButton jCsv; private final JRadioButton jHtml; private final JRadioButton jSql; //Options private final CardLayout cardLayout; private final JPanel jOptionPanel; //CSV private final JComboBox jLineDelimiter; private final JComboBox jDecimalSeparator; //Html private final JCheckBox jHtmlStyle; private final JCheckBox jHtmlIGB; private final JSlider jHtmlHeaderRepeat; //SQL private final JTextField jTableName; private final JCheckBox jDropTable; private final JCheckBox jCreateTable; private final JCheckBox jExtendedInserts; private final JButton jOK; private final JCustomFileChooser jFileChooser; private final String toolName; private final ColumnCache columnCache; private final SimpleFilterControl filterControl; private final SimpleTableFormat tableFormat; private final EventList eventList; private final Map> columns = new HashMap<>(); private final List> columnIndex = new ArrayList<>(); public ExportDialog(final JFrame jFrame, final String toolName, ColumnCache columnCache, final SimpleFilterControl filterControl, SimpleTableFormat tableFormat, final EventList eventList) { super(null, DialoguesExport.get().export(), jFrame, Images.DIALOG_CSV_EXPORT.getImage()); this.toolName = toolName; this.columnCache = columnCache; this.filterControl = filterControl; this.tableFormat = tableFormat; this.eventList = eventList; ListenerClass listener = new ListenerClass(); layout.setAutoCreateContainerGaps(false); jFileChooser = new JCustomFileChooser(Settings.get().getExportSettings(toolName).getExportFormat().getExtension()); //Format JPanel jFormatPanel = new JPanel(); jFormatPanel.setBorder(BorderFactory.createTitledBorder(DialoguesExport.get().format())); GroupLayout formatLayout = new GroupLayout(jFormatPanel); jFormatPanel.setLayout(formatLayout); formatLayout.setAutoCreateGaps(true); formatLayout.setAutoCreateContainerGaps(true); jCsv = new JRadioButton(DialoguesExport.get().csv()); jCsv.setActionCommand(ExportAction.FORMAT_CHANGED.name()); jCsv.addActionListener(listener); jHtml = new JRadioButton(DialoguesExport.get().html()); jHtml.setActionCommand(ExportAction.FORMAT_CHANGED.name()); jHtml.addActionListener(listener); jSql = new JRadioButton(DialoguesExport.get().sql()); jSql.setActionCommand(ExportAction.FORMAT_CHANGED.name()); jSql.addActionListener(listener); ButtonGroup jFormatButtonGroup = new ButtonGroup(); jFormatButtonGroup.add(jCsv); jFormatButtonGroup.add(jHtml); jFormatButtonGroup.add(jSql); formatLayout.setHorizontalGroup( formatLayout.createSequentialGroup() .addComponent(jCsv) .addComponent(jHtml) .addComponent(jSql) ); formatLayout.setVerticalGroup( formatLayout.createParallelGroup() .addComponent(jCsv, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jHtml, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSql, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); //Options cardLayout = new CardLayout(); jOptionPanel = new JPanel(cardLayout); //Csv JOptionPanel jCsvPanel = new JOptionPanel(); jOptionPanel.add(jCsvPanel, ExportFormat.CSV.name()); JLabel jLineDelimiterLabel = new JLabel(DialoguesExport.get().linesTerminated()); jLineDelimiter = new JComboBox<>(LineDelimiter.values()); jCsvPanel.add(jLineDelimiterLabel); jCsvPanel.add(jLineDelimiter); //Sql JOptionPanel jSqlPanel = new JOptionPanel(); jOptionPanel.add(jSqlPanel, ExportFormat.SQL.name()); JLabel jTableNameLabel = new JLabel(DialoguesExport.get().tableName()); jTableName = new JDefaultField(ExportSettings.getDefaultTableName(toolName)); jTableName.setDocument(DocumentFactory.getWordPlainDocument()); jSqlPanel.add(jTableNameLabel); jSqlPanel.add(jTableName); jDropTable = new JCheckBox(DialoguesExport.get().dropTable()); jSqlPanel.add(jDropTable); jCreateTable = new JCheckBox(DialoguesExport.get().createTable()); jSqlPanel.add(jCreateTable); jExtendedInserts = new JCheckBox(DialoguesExport.get().extendedInserts()); jSqlPanel.add(jExtendedInserts); //Html JOptionPanel jHtmlPanel = new JOptionPanel(); jOptionPanel.add(jHtmlPanel, ExportFormat.HTML.name()); jHtmlStyle = new JCheckBox(DialoguesExport.get().htmlStyled()); jHtmlPanel.add(jHtmlStyle); jHtmlIGB = new JCheckBox(DialoguesExport.get().htmlIGB()); jHtmlPanel.add(jHtmlIGB); JLabel jHtmlHeaderRepeatLabel = new JLabel(DialoguesExport.get().htmlHeaderRepeat()); jHtmlHeaderRepeat = new JSlider(JSlider.HORIZONTAL, 0, 50, 0); jHtmlHeaderRepeat.setMajorTickSpacing(10); jHtmlHeaderRepeat.setMinorTickSpacing(5); jHtmlHeaderRepeat.setSnapToTicks(true); jHtmlHeaderRepeat.setPaintTicks(true); jHtmlHeaderRepeat.setPaintLabels(true); jHtmlPanel.add(jHtmlHeaderRepeatLabel); jHtmlPanel.add(jHtmlHeaderRepeat); //Decimal JPanel jDecimalPanel = new JPanel(); jDecimalPanel.setBorder(BorderFactory.createTitledBorder(DialoguesExport.get().decimalSeparator())); GroupLayout decimalLayout = new GroupLayout(jDecimalPanel); jDecimalPanel.setLayout(decimalLayout); decimalLayout.setAutoCreateGaps(true); decimalLayout.setAutoCreateContainerGaps(true); jDecimalSeparator = new JComboBox<>(DecimalSeparator.values()); jDecimalPanel.add(jDecimalSeparator); decimalLayout.setHorizontalGroup( decimalLayout.createParallelGroup() .addComponent(jDecimalSeparator) ); decimalLayout.setVerticalGroup( decimalLayout.createSequentialGroup() .addComponent(jDecimalSeparator, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); //Filters JPanel jFilterPanel = new JPanel(); jFilterPanel.setBorder(BorderFactory.createTitledBorder(DialoguesExport.get().filters())); GroupLayout filterLayout = new GroupLayout(jFilterPanel); jFilterPanel.setLayout(filterLayout); filterLayout.setAutoCreateGaps(true); filterLayout.setAutoCreateContainerGaps(true); jNoFilter = new JRadioButton(DialoguesExport.get().noFilter()); jNoFilter.setActionCommand(ExportAction.FILTER_CHANGED.name()); jNoFilter.addActionListener(listener); jNoFilter.setSelected(true); jCurrentFilter = new JRadioButton(DialoguesExport.get().currentFilter()); jCurrentFilter.setActionCommand(ExportAction.FILTER_CHANGED.name()); jCurrentFilter.addActionListener(listener); jSavedFilter = new JRadioButton(DialoguesExport.get().savedFilter()); jSavedFilter.setActionCommand(ExportAction.FILTER_CHANGED.name()); jSavedFilter.addActionListener(listener); ButtonGroup jFilterButtonGroup = new ButtonGroup(); jFilterButtonGroup.add(jNoFilter); jFilterButtonGroup.add(jSavedFilter); jFilterButtonGroup.add(jCurrentFilter); jFilters = new JComboBox<>(); filterLayout.setHorizontalGroup( filterLayout.createParallelGroup() .addComponent(jNoFilter) .addComponent(jCurrentFilter) .addComponent(jSavedFilter) .addGroup(filterLayout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addGroup(filterLayout.createSequentialGroup() .addGap(20) .addComponent(jFilters, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) ) ) ); filterLayout.setVerticalGroup( filterLayout.createSequentialGroup() .addComponent(jNoFilter, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCurrentFilter, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSavedFilter, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFilters, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); //Columns JPanel jColumnPanel = new JPanel(); jColumnPanel.setBorder(BorderFactory.createTitledBorder(DialoguesExport.get().columns())); GroupLayout columnLayout = new GroupLayout(jColumnPanel); jColumnPanel.setLayout(columnLayout); columnLayout.setAutoCreateGaps(true); columnLayout.setAutoCreateContainerGaps(true); jViewCurrent = new JRadioButton(DialoguesExport.get().viewCurrent()); jViewCurrent.setActionCommand(ExportAction.VIEW_CHANGED.name()); jViewCurrent.addActionListener(listener); jViewCurrent.setSelected(true); jViewSaved = new JRadioButton(DialoguesExport.get().viewSaved()); jViewSaved.setActionCommand(ExportAction.VIEW_CHANGED.name()); jViewSaved.addActionListener(listener); jViews = new JComboBox<>(); jViewSelect = new JRadioButton(DialoguesExport.get().viewSelect()); jViewSelect.setActionCommand(ExportAction.VIEW_CHANGED.name()); jViewSelect.addActionListener(listener); final List> enumColumns = tableFormat.getAllColumns(); columnIndex.addAll(enumColumns); for (EnumTableColumn column : enumColumns) { columns.put(column.name(), column); } jViewSelectAll = new JButton(DialoguesExport.get().viewSelectAll()); jViewSelectAll.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jColumnSelection.toggleSelectAll(); } }); jViewSelectAll.setEnabled(false); jColumnSelection = new JMultiSelectionList<>(columnIndex); jColumnSelection.clearSelection(); jColumnSelection.setEnabled(false); JScrollPane jColumnSelectionPanel = new JScrollPane(jColumnSelection); ButtonGroup jViewButtonGroup = new ButtonGroup(); jViewButtonGroup.add(jViewCurrent); jViewButtonGroup.add(jViewSaved); jViewButtonGroup.add(jViewSelect); columnLayout.setHorizontalGroup( columnLayout.createParallelGroup() .addComponent(jViewCurrent) .addComponent(jViewSaved) .addComponent(jViewSelect) .addGroup(columnLayout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addGroup(columnLayout.createSequentialGroup() .addGap(20) .addGroup(columnLayout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jViews, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jViewSelectAll, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jColumnSelectionPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) ) ) ) ); columnLayout.setVerticalGroup( columnLayout.createSequentialGroup() .addComponent(jViewCurrent, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jViewSaved, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jViews, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jViewSelect, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jColumnSelectionPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jViewSelectAll, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); //Buttons JSeparator jButtonSeparator = new JSeparator(); jOK = new JButton(DialoguesExport.get().ok()); jOK.setActionCommand(ExportAction.OK.name()); jOK.addActionListener(listener); JButton jDefault = new JButton(DialoguesExport.get().defaultSettings()); jDefault.setActionCommand(ExportAction.DEFAULT.name()); jDefault.addActionListener(listener); JButton jCancel = new JButton(DialoguesExport.get().cancel()); jCancel.setActionCommand(ExportAction.CANCEL.name()); jCancel.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) //Format .addComponent(jFormatPanel, 250, 250, 250) .addComponent(jOptionPanel, 250, 250, 250) .addComponent(jDecimalPanel, 250, 250, 250) .addComponent(jFilterPanel, 250, 250, 250) ) .addGap(10) .addComponent(jColumnPanel, 250, 250, 250) .addContainerGap() ) .addComponent(jButtonSeparator) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jDefault, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addContainerGap() ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addComponent(jFormatPanel) .addComponent(jOptionPanel) .addComponent(jDecimalPanel) .addComponent(jFilterPanel) ) .addComponent(jColumnPanel) ) .addComponent(jButtonSeparator, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDefault, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addContainerGap() ); } private void updateColumns() { final List> enumColumns = tableFormat.getAllColumns(); columns.clear(); columnIndex.clear(); columnIndex.addAll(enumColumns); for (EnumTableColumn column : enumColumns) { columns.put(column.name(), column); } jColumnSelection.setModel(new AbstractListModel>() { @Override public int getSize() { return columnIndex.size(); } @Override public EnumTableColumn getElementAt(int index) { return columnIndex.get(index); } }); } private List getExportColumns() { List selectedColumns = new ArrayList<>(); for (EnumTableColumn column : jColumnSelection.getSelectedValuesList()) { selectedColumns.add(column.name()); } return selectedColumns; } private boolean browse() { File file = new File(Settings.get().getExportSettings(toolName).getFilename()); File path = new File(Settings.get().getExportSettings(toolName).getPath()); if (path.exists()) { jFileChooser.setCurrentDirectory(path); jFileChooser.setSelectedFile(file); } else { jFileChooser.setCurrentDirectory(new File(Settings.get().getExportSettings(toolName).getDefaultPath())); jFileChooser.setSelectedFile(new File(Settings.get().getExportSettings(toolName).getDefaultFilename())); } int bFound = jFileChooser.showDialog(getDialog(), DialoguesExport.get().ok()); if (bFound == JCustomFileChooser.APPROVE_OPTION) { file = jFileChooser.getSelectedFile(); Settings.get().getExportSettings(toolName).setFilename(file.getAbsolutePath()); return true; } else { return false; } } private void saveSettings() { Settings.lock("Export Settings (Save)"); //Lock for Export Settings (Save) //Decimal Settings.get().getExportSettings(toolName).setDecimalSeparator((DecimalSeparator) jDecimalSeparator.getSelectedItem()); //CSV Settings.get().getExportSettings(toolName).setCsvLineDelimiter((LineDelimiter) jLineDelimiter.getSelectedItem()); //SQL Settings.get().getExportSettings(toolName).setSqlTableName(jTableName.getText()); Settings.get().getExportSettings(toolName).setSqlDropTable(jDropTable.isSelected()); Settings.get().getExportSettings(toolName).setSqlCreateTable(jCreateTable.isSelected()); Settings.get().getExportSettings(toolName).setSqlExtendedInserts(jExtendedInserts.isSelected()); //HTML Settings.get().getExportSettings(toolName).setHtmlStyled(jHtmlStyle.isSelected()); Settings.get().getExportSettings(toolName).setHtmlIGB(jHtmlIGB.isSelected()); Settings.get().getExportSettings(toolName).setHtmlRepeatHeader(jHtmlHeaderRepeat.getValue()); //Format ExportFormat exportFormat = ExportFormat.CSV; if (jCsv.isSelected()) { exportFormat = ExportFormat.CSV; } else if (jHtml.isSelected()) { exportFormat = ExportFormat.HTML; } else if (jSql.isSelected()) { exportFormat = ExportFormat.SQL; } Settings.get().getExportSettings(toolName).setExportFormat(exportFormat); //Filter FilterSelection filterSelection = FilterSelection.NONE; if (jNoFilter.isSelected()) { filterSelection = FilterSelection.NONE; } else if (jCurrentFilter.isSelected()) { filterSelection = FilterSelection.CURRENT; } else if (jSavedFilter.isSelected()) { filterSelection = FilterSelection.SAVED; } Settings.get().getExportSettings(toolName).setFilterSelection(filterSelection); //View ColumnSelection columnSelection = ColumnSelection.SHOWN; if (jViewCurrent.isSelected()) { columnSelection = ColumnSelection.SHOWN; } else if (jViewSaved.isSelected()) { columnSelection = ColumnSelection.SAVED; } else if (jViewSelect.isSelected()) { columnSelection = ColumnSelection.SELECTED; } Settings.get().getExportSettings(toolName).setColumnSelection(columnSelection); //Columns if (jColumnSelection.getSelectedIndices().length == columns.size()) { //All is selected - nothing worth saving... Settings.get().getExportSettings(toolName).putTableExportColumns(null); //null = all } else { Settings.get().getExportSettings(toolName).putTableExportColumns(getExportColumns()); } //Filter Name (Make sure there is a selected item and that it is not the filler text for empty list) if (jFilters.getSelectedItem() != null && !DialoguesExport.get().noSavedFilter().equals(jFilters.getSelectedItem())) { Settings.get().getExportSettings(toolName).setFilterName((String) jFilters.getSelectedItem()); } else { Settings.get().getExportSettings(toolName).setFilterName(null); } //View Name (Make sure there is a selected item and that is is not filler text for empty list) if (jViews.getSelectedItem() != null && !DialoguesExport.get().viewNoSaved().equals(jViews.getSelectedItem())) { Settings.get().getExportSettings(toolName).setViewName((String) jViews.getSelectedItem()); } else { Settings.get().getExportSettings(toolName).setViewName(null); } Settings.unlock("Export Settings (Save)"); //Unlock for Export Settings (Save) filterControl.saveSettings("Export Settings (Save)"); } private void loadSettings() { //Decimal jDecimalSeparator.setSelectedItem(Settings.get().getExportSettings(toolName).getDecimalSeparator()); //CSV jLineDelimiter.setSelectedItem(Settings.get().getExportSettings(toolName).getCsvLineDelimiter()); //SQL jTableName.setText(Settings.get().getExportSettings(toolName).getSqlTableName()); jDropTable.setSelected(Settings.get().getExportSettings(toolName).isSqlDropTable()); jCreateTable.setSelected(Settings.get().getExportSettings(toolName).isSqlCreateTable()); jExtendedInserts.setSelected(Settings.get().getExportSettings(toolName).isSqlExtendedInserts()); //HTML jHtmlStyle.setSelected(Settings.get().getExportSettings(toolName).isHtmlStyled()); jHtmlIGB.setSelected(Settings.get().getExportSettings(toolName).isHtmlIGB()); jHtmlHeaderRepeat.setValue(Settings.get().getExportSettings(toolName).getHtmlRepeatHeader()); //Filename ExportFormat exportFormat = Settings.get().getExportSettings(toolName).getExportFormat(); jFileChooser.setExtension(exportFormat.getExtension()); //Columns (Shared) jColumnSelection.clearSelection(); List selectedColumns = Settings.get().getExportSettings(toolName).getTableExportColumns(); if (selectedColumns.isEmpty()) { jColumnSelection.selectAll(); } else { List selections = new ArrayList<>(); for (String column : selectedColumns) { try { EnumTableColumn enumColumn = tableFormat.valueOf(column); if (enumColumn != null) { int index = columnIndex.indexOf(enumColumn); selections.add(index); } } catch (IllegalArgumentException ex) { //ignore missing columns... } } int[] indices = new int[selections.size()]; for (int i = 0; i < selections.size(); i++) { indices[i] = selections.get(i); } jColumnSelection.setSelectedIndices(indices); } String filterName = Settings.get().getExportSettings(toolName).getFilterName(); List filterNames = new ArrayList<>(filterControl.getAllFilters().keySet()); if (!filterNames.isEmpty()) { Collections.sort(filterNames, StringComparators.CASE_INSENSITIVE); jFilters.setModel(new ListComboBoxModel<>(filterNames)); if(hasItem(jFilters, filterName)) { jFilters.setSelectedItem(filterName); } } else { jFilters.setModel(new ListComboBoxModel<>()); } String viewName = Settings.get().getExportSettings(toolName).getViewName(); List viewNames = new ArrayList<>(Settings.get().getTableViews(toolName).keySet()); if (!viewNames.isEmpty()) { Collections.sort(viewNames, StringComparators.CASE_INSENSITIVE); jViews.setModel(new ListComboBoxModel<>(viewNames)); if (hasItem(jViews, viewName)) { jViews.setSelectedItem(viewName); } } else { jViews.setModel(new ListComboBoxModel<>()); } updateDisplayElements(); } private void resetSettings() { Settings.lock("Export Settings (Reset)"); //Lock for Export Settings (Reset) ExportSettings oldSettings = Settings.get().getExportSettings(toolName); ExportSettings newSettings = new ExportSettings(toolName); newSettings.putTableExportColumns(oldSettings.getTableExportColumns()); Settings.get().getExportSettings().put(toolName, newSettings); Settings.unlock("Export Settings (Reset)"); //Unlock for Export Settings (Reset) loadSettings(); } /*** *Updates the UI elements that are displayed based on the current data. This will hide or show panels. Enable *combo boxes. Etc. */ public void updateDisplayElements() { ExportFormat exportFormat = Settings.get().getExportSettings(toolName).getExportFormat(); cardLayout.show(jOptionPanel, exportFormat.name()); if (exportFormat == ExportFormat.HTML) { jHtml.setSelected(true); jOptionPanel.setBorder(BorderFactory.createTitledBorder(DialoguesExport.get().html())); } else if (exportFormat == ExportFormat.SQL) { jSql.setSelected(true); jOptionPanel.setBorder(BorderFactory.createTitledBorder(DialoguesExport.get().sql())); } else { //CSV and Default jCsv.setSelected(true); jOptionPanel.setBorder(BorderFactory.createTitledBorder(DialoguesExport.get().csv())); } FilterSelection filterSelection = Settings.get().getExportSettings(toolName).getFilterSelection(); String filterName = Settings.get().getExportSettings(toolName).getFilterName(); if (filterSelection == FilterSelection.NONE) { jNoFilter.setSelected(true); jFilters.setEnabled(false); } else if (filterSelection == FilterSelection.CURRENT && !filterControl.isFiltersEmpty()) { jCurrentFilter.setSelected(true); jFilters.setEnabled(false); } else if (filterSelection == FilterSelection.SAVED && hasItem(jFilters, filterName)) { jSavedFilter.setSelected(true); jFilters.setEnabled(true); } else { //If we got here then the filter selection didn't match the data and we had to default, so reset the value //in the settings. jNoFilter.setSelected(true); jFilters.setEnabled(false); Settings.get().getExportSettings(toolName).setFilterSelection(FilterSelection.NONE); } //Filters current if (filterControl.isFiltersEmpty()) { jCurrentFilter.setEnabled(false); } else { jCurrentFilter.setEnabled(true); } //Filters saved if (filterControl.getAllFilters().isEmpty()) { jSavedFilter.setEnabled(false); jFilters.getModel().setSelectedItem(DialoguesExport.get().noSavedFilter()); } else { jSavedFilter.setEnabled(true); } ColumnSelection columnSelection = Settings.get().getExportSettings(toolName).getColumnSelection(); String viewName = Settings.get().getExportSettings(toolName).getViewName(); if (columnSelection == ColumnSelection.SHOWN) { jViewCurrent.setSelected(true); jViews.setEnabled(false); jColumnSelection.setEnabled(false); jViewSelectAll.setEnabled(false); } else if (columnSelection == ColumnSelection.SAVED && hasItem(jViews, viewName)) { jViewSaved.setSelected(true); jViews.setEnabled(true); jColumnSelection.setEnabled(false); jViewSelectAll.setEnabled(false); } else if (columnSelection == ColumnSelection.SELECTED) { jViewSelect.setSelected(true); jViews.setEnabled(false); jColumnSelection.setEnabled(true); jViewSelectAll.setEnabled(true); } else { //If we got here then the column selection didn't match the data and we had to default, so reset the value //in the settings. jViewCurrent.setSelected(true); jViews.setEnabled(false); Settings.get().getExportSettings(toolName).setColumnSelection(ColumnSelection.SHOWN); } //Views Map tableViews = Settings.get().getTableViews(toolName); if (tableViews.isEmpty()) { jViewSaved.setEnabled(false); jViews.getModel().setSelectedItem(DialoguesExport.get().viewNoSaved()); } else { jViewSaved.setEnabled(true); } } @Override public void setVisible(final boolean b) { if (b) { //Columns updateColumns(); //Settings loadSettings(); } super.setVisible(b); } @Override protected JComponent getDefaultFocus() { return jOK; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { } @Override protected void save() { //Bad options if (jColumnSelection.isEnabled() && jColumnSelection.getSelectedIndices().length == 0) { JOptionPane.showMessageDialog(getDialog(), DialoguesExport.get().noColumnsSelected(), DialoguesExport.get().export(), JOptionPane.PLAIN_MESSAGE); return; } //Save location boolean ok = browse(); if (!ok) { return; } //Save settings saveSettings(); //Save file boolean saved = ExportTableData.exportAuto(eventList, columnCache, tableFormat, toolName, Settings.get().getExportSettings(toolName)); if (!saved) { JOptionPane.showMessageDialog(getDialog(), DialoguesExport.get().failedToSave(), DialoguesExport.get().export(), JOptionPane.PLAIN_MESSAGE); } setVisible(false); } /*** * Helper function to return if the comboBox has the item. Null string or item will return false. * @param comboBox The combo box to look for the item in. * @param item The item to look for int he combo box. * @return True if the item is found (case sensitive). False if it is not found or either parameter is null. */ private boolean hasItem(JComboBox comboBox, String item) { if (comboBox == null || item == null) { return false; } for (int i = 0; i < comboBox.getModel().getSize(); i++) { String comboItem = comboBox.getModel().getElementAt(i); if (item.equals(comboItem)) { return true; } } return false; } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (ExportAction.OK.name().equals(e.getActionCommand())) { save(); } else if (ExportAction.DEFAULT.name().equals(e.getActionCommand())) { resetSettings(); } else if (ExportAction.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); saveSettings(); } else if (ExportAction.FORMAT_CHANGED.name().equals(e.getActionCommand())) { ExportFormat exportFormat = ExportFormat.CSV; if (jCsv.isSelected()) { exportFormat = ExportFormat.CSV; jOptionPanel.setBorder(BorderFactory.createTitledBorder(DialoguesExport.get().csv())); } else if (jHtml.isSelected()) { exportFormat = ExportFormat.HTML; jOptionPanel.setBorder(BorderFactory.createTitledBorder(DialoguesExport.get().html())); } else if (jSql.isSelected()) { exportFormat = ExportFormat.SQL; jOptionPanel.setBorder(BorderFactory.createTitledBorder(DialoguesExport.get().sql())); } Settings.get().getExportSettings(toolName).setExportFormat(exportFormat); cardLayout.show(jOptionPanel, exportFormat.name()); jFileChooser.setExtension(exportFormat.getExtension()); } else if (ExportAction.FILTER_CHANGED.name().equals(e.getActionCommand())) { jFilters.setEnabled(jSavedFilter.isSelected()); FilterSelection filterSelection = FilterSelection.NONE; if (jNoFilter.isSelected()) { filterSelection = FilterSelection.NONE; } else if (jCurrentFilter.isSelected()) { filterSelection = FilterSelection.CURRENT; } else if (jSavedFilter.isSelected()) { filterSelection = FilterSelection.SAVED; } Settings.get().getExportSettings(toolName).setFilterSelection(filterSelection); } else if (ExportAction.VIEW_CHANGED.name().equals(e.getActionCommand())) { jViews.setEnabled(jViewSaved.isSelected()); jColumnSelection.setEnabled(jViewSelect.isSelected()); jViewSelectAll.setEnabled(jViewSelect.isSelected()); ColumnSelection columnSelection = ColumnSelection.SHOWN; if (jViewCurrent.isSelected()) { columnSelection = ColumnSelection.SHOWN; } else if (jViewSaved.isSelected()) { columnSelection = ColumnSelection.SAVED; } else if (jViewSelect.isSelected()) { columnSelection = ColumnSelection.SELECTED; } Settings.get().getExportSettings(toolName).setColumnSelection(columnSelection); } } } public static class JOptionPanel extends JPanel { protected final GroupLayout layout; private final List components = new ArrayList<>(); private JOptionPanel() { layout = new GroupLayout(this); this.setLayout(layout); layout.setAutoCreateGaps(false); layout.setAutoCreateContainerGaps(true); } public void add(JComponent comp) { components.add(comp); createLayout(); } protected void createLayout() { this.removeAll(); GroupLayout.ParallelGroup horizontalGroup = layout.createParallelGroup(); GroupLayout.SequentialGroup verticalGroup = layout.createSequentialGroup(); for (JComponent jComponent : components) { horizontalGroup.addComponent(jComponent); if (jComponent instanceof JLabel || jComponent instanceof JButton || jComponent instanceof JCheckBox || jComponent instanceof JTextField || jComponent instanceof JComboBox) { verticalGroup.addComponent(jComponent, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()); } else { verticalGroup.addComponent(jComponent); } } layout.setHorizontalGroup( layout.createSequentialGroup() .addGroup(horizontalGroup) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(verticalGroup) ); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/ExportTableData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.matchers.Matcher; import java.io.File; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TreeSet; import net.nikr.eve.jeveasset.data.settings.ExportSettings; import net.nikr.eve.jeveasset.data.settings.ExportSettings.DecimalSeparator; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog.Formula; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuJumps.Jump; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager.FormulaColumn; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager.JumpColumn; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.SimpleColumn; import net.nikr.eve.jeveasset.gui.shared.table.View; import net.nikr.eve.jeveasset.gui.shared.table.containers.HierarchyColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.NumberValue; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeAsset; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTab; import net.nikr.eve.jeveasset.io.local.CsvWriter; import net.nikr.eve.jeveasset.io.local.HtmlWriter; import net.nikr.eve.jeveasset.io.local.SqlWriter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.supercsv.prefs.CsvPreference; public class ExportTableData { private static final Logger LOG = LoggerFactory.getLogger(ExportTableData.class); private static final DecimalFormat INTEGER_DOT_FORMAT = new DecimalFormat("###0", new DecimalFormatSymbols(new Locale("en"))); private static final DecimalFormat INTEGER_COMMA_FORMAT = new DecimalFormat("###0", new DecimalFormatSymbols(new Locale("da"))); private static final DecimalFormat DECIMAL_HTML_DOT_FORMAT = new DecimalFormat("#,##0.00##", new DecimalFormatSymbols(new Locale("en"))); private static final DecimalFormat DECIMAL_HTML_COMMA_FORMAT = new DecimalFormat("#,##0.00##", new DecimalFormatSymbols(new Locale("da"))); private static final DecimalFormat DECIMAL_CSV_DOT_FORMAT = new DecimalFormat("###0.00##", new DecimalFormatSymbols(new Locale("en"))); private static final DecimalFormat DECIMAL_CSV_COMMA_FORMAT = new DecimalFormat("###0.00##", new DecimalFormatSymbols(new Locale("da"))); /** * Get Filters and Views from Settings (No Column Cache). * @param * @param eventList * @param tableFormat * @param toolName * @param exportSettings * @return */ public static boolean exportAutoNoCache(EventList eventList, final SimpleTableFormat tableFormat, String toolName, ExportSettings exportSettings) { return exportAuto(eventList, null, tableFormat, toolName, exportSettings); } /** * Get Filters and Views from Settings (With Column Cache) * @param * @param eventList * @param columnCache * @param tableFormat * @param toolName * @param exportSettings * @return */ public static boolean exportAuto(EventList eventList, ColumnCache columnCache, final SimpleTableFormat tableFormat, String toolName, ExportSettings exportSettings) { return export(eventList, columnCache, tableFormat, toolName, Settings.get().getTableViews(toolName), Settings.get().getTableFilters(toolName), Settings.get().getDefaultTableFilters(toolName), Settings.get().getCurrentTableFilters(toolName), exportSettings); } /** * No Filters and Views from Settings * @param * @param eventList * @param tableFormat * @param toolName * @param exportSettings * @return */ public static boolean exportEmpty(EventList eventList, final SimpleTableFormat tableFormat, String toolName, ExportSettings exportSettings) { return export(eventList, null, tableFormat, toolName, new HashMap<>(), new HashMap<>(), new HashMap<>(), new ArrayList<>(), exportSettings); } /** * * @param * @param eventList * @param columnCache * @param tableFormat * @param toolName * @param views * @param filters * @param currentFilters * @param exportSettings * @return */ private static boolean export(EventList eventList, ColumnCache columnCache, final SimpleTableFormat tableFormat, String toolName, Map views, Map> filters, Map> defaultFilters, List currentFilters, ExportSettings exportSettings) { //Filter final List filter; switch (exportSettings.getFilterSelection()) { case NONE: filter = new ArrayList<>(); break; case CURRENT: filter = currentFilters; break; case SAVED: String filterName = exportSettings.getFilterName(); if (filterName == null) { LOG.error(toolName + " -> Filter name is null"); return false; } List f = filters.get(filterName); if (f != null) { filter = f; } else { filter = defaultFilters.get(filterName); if (filter == null) { LOG.error(toolName + " -> No such filter: " + filterName); return false; } } break; default: LOG.error(toolName + " -> Unknown FilterSelection: " + exportSettings.getFilterSelection()); return false; } //Columns + Header Map> columns = new HashMap<>(); //Column lookup for (EnumTableColumn column : tableFormat.getAllColumns()) { columns.put(column.name(), column); } final List> header; switch (exportSettings.getColumnSelection()) { case SELECTED: //Selected/All columns List selectedColumns = exportSettings.getTableExportColumns(); if (!selectedColumns.isEmpty()) { //Selected columns header = new ArrayList<>(); for (String selectedColumn : selectedColumns) { EnumTableColumn column = columns.get(selectedColumn); if (column != null) { header.add(column); } } } else { //All columns header = new ArrayList<>(tableFormat.getAllColumns()); //Copy (Otherwise added columns to the tableformat will also add it to the header) } break; case SHOWN: //Current shown columns in order header = new ArrayList<>(); for (SimpleColumn simpleColumn : Settings.get().getTableColumns().get(toolName)) { if (simpleColumn.isShown()) { EnumTableColumn column = columns.get(simpleColumn.getEnumName()); if (column != null) { header.add(column); } } } break; case SAVED: //Saved View String viewName = exportSettings.getViewName(); if (viewName == null) { LOG.error(toolName + " -> View name is null"); return false; } View view = views.get(viewName); if (view == null) { LOG.error(toolName + " -> No such view: " + viewName); return false; } header = new ArrayList<>(); for (SimpleColumn simpleColumn : view.getColumns()) { if (simpleColumn.isShown()) { EnumTableColumn column = columns.get(simpleColumn.getEnumName()); if (column != null) { header.add(column); } } } break; default: LOG.error(toolName + " -> Unknown ColumnSelection: " + exportSettings.getColumnSelection()); return false; } if (header.isEmpty()) { LOG.error(toolName + " -> No columns selected for ColumnSelection: " + exportSettings.getColumnSelection()); return false; } //Formula for (Formula formula : Settings.get().getTableFormulas(toolName)) { FormulaColumn formulaColumn = new FormulaColumn<>(formula); tableFormat.addColumn(formulaColumn); //Add the column for filters if (exportSettings.isFormulas()) { header.add(formulaColumn); //Export } } //Jump for (Jump jump : Settings.get().getTableJumps(toolName)) { JumpColumn jumpColumn = new JumpColumn<>(jump); tableFormat.addColumn(jumpColumn); //Add the column for filters if (exportSettings.isJumps()) { header.add(jumpColumn); //Export } } //Apply Filters List items = new ArrayList<>(); try { eventList.getReadWriteLock().readLock().lock(); FilterList filterList = new FilterList<>(eventList, new FilterLogicalMatcher<>(tableFormat, columnCache, filter)); if (!eventList.isEmpty() && eventList.get(0) instanceof TreeAsset) { FilterList treeFilterList = new FilterList<>(eventList, new TreeMatcher<>(filterList)); items.addAll(treeFilterList); } else { items.addAll(filterList); } } finally { eventList.getReadWriteLock().readLock().unlock(); } //File String filename = exportSettings.getFilename(); File dir = new File(filename).getParentFile(); if (dir.isFile()) { //If parent dir is a file, cancel return false; } else if (!dir.exists()) { //If parent dir dosn't exsit, create it dir.mkdirs(); } if (exportSettings.isCsv()) { //CSV //Create data List headerStrings = new ArrayList<>(header.size()); List headerKeys = new ArrayList<>(header.size()); for (EnumTableColumn column : header) { headerStrings.add(column.getColumnName()); headerKeys.add(column.name()); } List> rows = new ArrayList<>(); for (Q e : items) { Map row = new HashMap<>(); for (EnumTableColumn column : header) { row.put(column.name(), format(tableFormat.getColumnValue(e, column.name()), exportSettings.getDecimalSeparator(), false)); } rows.add(row); } //Save data return CsvWriter.save(exportSettings.getFilename(), rows, headerStrings.toArray(new String[headerStrings.size()]), headerKeys.toArray(new String[headerKeys.size()]), new CsvPreference.Builder('\"', exportSettings.getCsvFieldDelimiter().getValue(), exportSettings.getCsvLineDelimiter().getValue()).build()); } else if (exportSettings.isHtml()) { //HTML //Create data List, String>> rows = new ArrayList<>(); for (Q e : items) { Map, String> row = new HashMap<>(); for (EnumTableColumn column : header) { row.put(column, format(tableFormat.getColumnValue(e, column.name()), exportSettings.getDecimalSeparator(), true)); } rows.add(row); } //Save data return HtmlWriter.save(exportSettings.getFilename(), rows, new ArrayList<>(header), exportSettings.isHtmlIGB() ? new ArrayList<>(items) : null, exportSettings.isHtmlStyled(), exportSettings.getHtmlRepeatHeader(), toolName.equals(TreeTab.NAME)); } else if (exportSettings.isSql()) { //SQL //Create data List, Object>> rows = new ArrayList<>(); for (Q e : items) { Map, Object> row = new HashMap<>(); for (EnumTableColumn column : header) { row.put(column, tableFormat.getColumnValue(e, column.name())); } rows.add(row); } //Save data return SqlWriter.save(exportSettings.getFilename(), rows, new ArrayList<>(header), exportSettings.getSqlTableName(), exportSettings.isSqlDropTable(), exportSettings.isSqlCreateTable(), exportSettings.isSqlExtendedInserts()); } else { return false; } } private static class TreeMatcher implements Matcher { private final EventList eventList; private final Set parentTree = new HashSet<>(); public TreeMatcher(EventList eventList) { this.eventList = eventList; Set items = new TreeSet<>(new TreeTab.AssetTreeComparator()); for (E e : eventList) { if (e instanceof TreeAsset) { TreeAsset tree = (TreeAsset) e; items.add(tree); parentTree.addAll(tree.getTree()); } } for (TreeAsset treeAsset : parentTree) { treeAsset.resetValues(); if (treeAsset.isItem()) { items.add(treeAsset); } } for (TreeAsset treeAsset : items) { treeAsset.updateParents(); } } @Override public boolean matches(E item) { //XXX - Expensive if (item instanceof TreeAsset) { TreeAsset treeAsset = (TreeAsset) item; if (treeAsset.isParent()) { return parentTree.contains(treeAsset); } } return eventList.contains(item); } } private static String format(Object object, final DecimalSeparator decimalSeparator, final boolean html) { if (object != null && object instanceof NumberValue && !(object instanceof Percent)) { //Unpack NumberValue object = ((NumberValue)object).getNumber(); } if (object == null) { return ""; } else if (object instanceof HierarchyColumn) { HierarchyColumn column = (HierarchyColumn) object; return column.getExport(); } else if (object instanceof Percent) { Percent percent = (Percent) object; return percent.toString(); } else if (object instanceof Number) { Number number = (Number) object; if (object instanceof Integer || object instanceof Long) { if (decimalSeparator == DecimalSeparator.DOT) { return INTEGER_DOT_FORMAT.format(number); } else { return INTEGER_COMMA_FORMAT.format(number); } } else { if (html) { if (decimalSeparator == DecimalSeparator.DOT) { return DECIMAL_HTML_DOT_FORMAT.format(number); } else { return DECIMAL_HTML_COMMA_FORMAT.format(number); } } else { if (decimalSeparator == DecimalSeparator.DOT) { return DECIMAL_CSV_DOT_FORMAT.format(number); } else { return DECIMAL_CSV_COMMA_FORMAT.format(number); } } } } else if (object instanceof Tags && html) { Tags tags = (Tags) object; return tags.getHtml(); } else if (object instanceof Date) { return Formatter.columnDate(object); } else { return object.toString(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/Filter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import java.util.Comparator; import javax.swing.Icon; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.GuiShared; public class Filter { public static class AllColumn implements EnumTableColumn { public static final AllColumn ALL = new AllColumn<>(); @Override public Class getType() { return Object.class; } @Override public Comparator getComparator() { return null; } @Override public String getColumnName() { return GuiShared.get().filterAll(); } @Override public Object getColumnValue(T from) { return null; } @Override public String name() { return "ALL"; } @Override public String toString() { return GuiShared.get().filterAll(); } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final AllColumn other = (AllColumn) obj; return this.name().equals(other.name()); } @Override public int hashCode() { int hash = 5; return hash; } } public enum CompareType { CONTAINS(Images.FILTER_CONTAIN.getIcon()) { @Override String getI18N() { return GuiShared.get().filterContains(); } }, CONTAINS_NOT(Images.FILTER_NOT_CONTAIN.getIcon()) { @Override String getI18N() { return GuiShared.get().filterContainsNot(); } }, EQUALS(Images.FILTER_EQUAL.getIcon()) { @Override String getI18N() { return GuiShared.get().filterEquals(); } }, EQUALS_NOT(Images.FILTER_NOT_EQUAL.getIcon()) { @Override String getI18N() { return GuiShared.get().filterEqualsNot(); } }, REGEX(Images.FILTER_REGEX.getIcon()) { @Override String getI18N() { return GuiShared.get().filterRegex(); } }, GREATER_THAN(Images.FILTER_GREATER_THAN.getIcon()) { @Override String getI18N() { return GuiShared.get().filterGreaterThan(); } }, LESS_THAN(Images.FILTER_LESS_THAN.getIcon()) { @Override String getI18N() { return GuiShared.get().filterLessThan(); } }, EQUALS_DATE(Images.FILTER_EQUAL_DATE.getIcon()) { @Override String getI18N() { return GuiShared.get().filterEqualsDate(); } }, EQUALS_NOT_DATE(Images.FILTER_NOT_EQUAL_DATE.getIcon()) { @Override String getI18N() { return GuiShared.get().filterEqualsNotDate(); } }, BEFORE(Images.FILTER_BEFORE.getIcon()) { @Override String getI18N() { return GuiShared.get().filterBefore(); } }, AFTER(Images.FILTER_AFTER.getIcon()) { @Override String getI18N() { return GuiShared.get().filterAfter(); } }, LAST_DAYS(Images.FILTER_LAST_DAYS.getIcon()) { @Override String getI18N() { return GuiShared.get().filterLastDays(); } }, NEXT_DAYS(Images.FILTER_NEXT_DAYS.getIcon()) { @Override String getI18N() { return GuiShared.get().filterNextDays(); } }, LAST_HOURS(Images.FILTER_LAST_HOURS.getIcon()) { @Override String getI18N() { return GuiShared.get().filterLastHours(); } }, NEXT_HOURS(Images.FILTER_NEXT_HOURS.getIcon()) { @Override String getI18N() { return GuiShared.get().filterNextHours(); } }, CONTAINS_COLUMN(Images.FILTER_CONTAIN_COLUMN.getIcon()) { @Override String getI18N() { return GuiShared.get().filterContainsColumn(); } }, CONTAINS_NOT_COLUMN(Images.FILTER_NOT_CONTAIN_COLUMN.getIcon()) { @Override String getI18N() { return GuiShared.get().filterContainsNotColumn(); } }, EQUALS_COLUMN(Images.FILTER_EQUAL_COLUMN.getIcon()) { @Override String getI18N() { return GuiShared.get().filterEqualsColumn(); } }, EQUALS_NOT_COLUMN(Images.FILTER_NOT_EQUAL_COLUMN.getIcon()) { @Override String getI18N() { return GuiShared.get().filterEqualsNotColumn(); } }, GREATER_THAN_COLUMN(Images.FILTER_GREATER_THAN_COLUMN.getIcon()) { @Override String getI18N() { return GuiShared.get().filterGreaterThanColumn(); } }, LESS_THAN_COLUMN(Images.FILTER_LESS_THAN_COLUMN.getIcon()) { @Override String getI18N() { return GuiShared.get().filterLessThanColumn(); } }, BEFORE_COLUMN(Images.FILTER_BEFORE_COLUMN.getIcon()) { @Override String getI18N() { return GuiShared.get().filterBeforeColumn(); } }, AFTER_COLUMN(Images.FILTER_AFTER_COLUMN.getIcon()) { @Override String getI18N() { return GuiShared.get().filterAfterColumn(); } }; private static final CompareType[] VALUES_ALL = new CompareType[] {CONTAINS, CONTAINS_NOT, EQUALS, EQUALS_NOT, REGEX, }; private static final CompareType[] VALUES_STRING = new CompareType[] {CONTAINS, CONTAINS_NOT, EQUALS, EQUALS_NOT, REGEX, CONTAINS_COLUMN, CONTAINS_NOT_COLUMN, EQUALS_COLUMN, EQUALS_NOT_COLUMN }; private static final CompareType[] VALUES_NUMERIC = new CompareType[] {CONTAINS, CONTAINS_NOT, EQUALS, EQUALS_NOT, REGEX, GREATER_THAN, LESS_THAN, CONTAINS_COLUMN, CONTAINS_NOT_COLUMN, EQUALS_COLUMN, EQUALS_NOT_COLUMN, GREATER_THAN_COLUMN, LESS_THAN_COLUMN, }; private static final CompareType[] VALUES_DATE = new CompareType[] {CONTAINS, CONTAINS_NOT, EQUALS, EQUALS_NOT, REGEX, EQUALS_DATE, EQUALS_NOT_DATE, BEFORE, AFTER, LAST_DAYS, NEXT_DAYS, LAST_HOURS, NEXT_HOURS, //CONTAINS_COLUMN, //CONTAINS_NOT_COLUMN, EQUALS_COLUMN, EQUALS_NOT_COLUMN, BEFORE_COLUMN, AFTER_COLUMN, }; private final Icon icon; private CompareType(final Icon icon) { this.icon = icon; } public Icon getIcon() { return icon; } abstract String getI18N(); @Override public String toString() { return getI18N(); } public static CompareType[] valuesAll() { return VALUES_ALL; } public static CompareType[] valuesString() { return VALUES_STRING; } public static CompareType[] valuesNumeric() { return VALUES_NUMERIC; } public static CompareType[] valuesDate() { return VALUES_DATE; } public static boolean isRegexCompare(final CompareType compareType) { return compareType == CompareType.REGEX; } public static boolean isColumnCompare(final CompareType compareType) { return compareType == CompareType.GREATER_THAN_COLUMN || compareType == CompareType.LESS_THAN_COLUMN || compareType == CompareType.EQUALS_COLUMN || compareType == CompareType.EQUALS_NOT_COLUMN || compareType == CompareType.CONTAINS_COLUMN || compareType == CompareType.CONTAINS_NOT_COLUMN || compareType == CompareType.BEFORE_COLUMN || compareType == CompareType.AFTER_COLUMN; } public static boolean isNumericCompare(final CompareType compareType) { return compareType == CompareType.GREATER_THAN_COLUMN || compareType == CompareType.LESS_THAN_COLUMN || compareType == CompareType.GREATER_THAN || compareType == CompareType.LESS_THAN; } public static boolean isDateCompare(final CompareType compareType) { return compareType == CompareType.BEFORE || compareType == CompareType.AFTER || compareType == CompareType.EQUALS_DATE || compareType == CompareType.EQUALS_NOT_DATE || compareType == CompareType.BEFORE_COLUMN || compareType == CompareType.AFTER_COLUMN; } } public enum LogicType { AND() { @Override public String getI18N() { return GuiShared.get().filterAnd(); } }, OR() { @Override public String getI18N() { return GuiShared.get().filterOr(); } }; abstract String getI18N(); @Override public String toString() { return getI18N(); } } private final int group; private final LogicType logic; private final EnumTableColumn column; private final CompareType compare; private final String text; private final boolean enabled; /** * Legacy support * @param logic * @param column * @param compare * @param text */ public Filter(final LogicType logic, final EnumTableColumn column, final CompareType compare, final String text) { this(1, logic, column, compare, text, true); } public Filter(int group, final String logic, final EnumTableColumn column, final String compare, final String text) { this(group, LogicType.valueOf(logic), column, CompareType.valueOf(compare), text, true); } public Filter(int group, final String logic, final EnumTableColumn column, final String compare, final String text, final boolean enabled) { this(group, LogicType.valueOf(logic), column, CompareType.valueOf(compare), text, enabled); } public Filter(int group, final LogicType logic, final EnumTableColumn column, final CompareType compare, final String text, final boolean enabled) { if (logic == LogicType.AND) { this.group = 0; } else { this.group = group; } this.logic = logic; this.column = column; this.compare = compare; this.text = text; this.enabled = enabled; } public int getGroup() { return group; } public EnumTableColumn getColumn() { return column; } public CompareType getCompareType() { return compare; } public boolean isAnd() { return logic == LogicType.AND; } public LogicType getLogic() { return logic; } public boolean isEmpty() { return text.isEmpty(); } public boolean isEnabled() { return enabled; } public String getText() { return text; } @Override public String toString() { return text; } @Override public boolean equals(final Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Filter other = (Filter) obj; if (this.logic != other.logic) { return false; } if (!this.column.equals(other.column)) { return false; } if (this.compare != other.compare) { return false; } return !((this.text == null) ? (other.text != null) : !this.text.equals(other.text)); } @Override public int hashCode() { int hash = 5; hash = 43 * hash + (this.logic != null ? this.logic.hashCode() : 0); hash = 43 * hash + (this.column != null ? this.column.hashCode() : 0); hash = 43 * hash + (this.compare != null ? this.compare.hashCode() : 0); hash = 43 * hash + (this.text != null ? this.text.hashCode() : 0); return hash; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/FilterControl.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.Icon; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JTable; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.SettingsUpdateListener; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.AllColumn; import net.nikr.eve.jeveasset.gui.shared.filter.FilterMenu.SimpleFilter; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.NumberValue; import net.nikr.eve.jeveasset.io.shared.DesktopUtil.HelpLink; public abstract class FilterControl implements ColumnCache, SimpleFilterControl { private final JFrame jFrame; private final String toolName; private final SimpleTableFormat tableFormat; private final EventList eventList; private final EventList exportEventList; private final List settingsUpdateListenerList = new ArrayList<>(); private final FilterList filterList; private final Map> filters; private final Map> defaultFilters; private final FilterGui gui; private final Map cache; /** Do not use this constructor - it's here only for test purposes. */ protected FilterControl() { jFrame = null; toolName = null; tableFormat = null; eventList = null; exportEventList = null; filterList = null; filters = null; defaultFilters = null; gui = null; cache = new HashMap<>(); } protected FilterControl(final JFrame jFrame, final String toolName, SimpleTableFormat tableFormat, final EventList eventList, final EventList exportEventList, final FilterList filterList) { this.jFrame = jFrame; this.toolName = toolName; this.tableFormat = tableFormat; this.eventList = eventList; this.exportEventList = exportEventList; this.filterList = filterList; this.filters = Settings.get().getTableFilters(toolName); this.defaultFilters = Settings.get().getDefaultTableFilters(toolName); eventList.addListEventListener(new ListEventListener() { @Override @SuppressWarnings("deprecation") public void listChanged(ListEvent listChanges) { try { eventList.getReadWriteLock().readLock().lock(); List delete = new ArrayList<>(); List update = new ArrayList<>(); while(listChanges.next()) { switch (listChanges.getType()) { case ListEvent.DELETE: addSafe(delete, listChanges.getOldValue()); break; case ListEvent.UPDATE: addSafe(eventList, update, listChanges.getIndex()); break; } } cacheDelete(delete); cacheUpdate(update); } finally { eventList.getReadWriteLock().readLock().unlock(); } } }); ListenerClass listener = new ListenerClass(); filterList.addListEventListener(listener); gui = new FilterGui<>(jFrame, this, tableFormat); cache = new HashMap<>(); } public void clearCache() { cache.clear(); } public void createCache() { cacheRebuild(); } public void refilter() { gui.refilter(); } public void repaint() { gui.repaint(); } @Override public Map getCache() { return cache; } @Override public void addCache(E e, String haystack) { cache.put(e, haystack); } private void cacheDelete(List update) { if (update.isEmpty()) { return; } for (E e : update) { cache.remove(e); //Remove deleted cache } } private void cacheUpdate(List update) { if (update.isEmpty()) { return; } for (E e : update) { cache.put(e, FilterMatcher.buildItemCache(tableFormat, e)); //Update outdated cache } } private void cacheRebuild() { cache.clear(); try { getEventList().getReadWriteLock().readLock().lock(); for (E e : getEventList()) { String s = FilterMatcher.buildItemCache(tableFormat, e); cache.put(e, s); } } finally { getEventList().getReadWriteLock().readLock().unlock(); } } private void addSafe(final EventList eventList, List list, int index) { if (index >= 0 && index < eventList.size()) { list.add(eventList.get(index)); } } private void addSafe(List list, E e) { if (e != null) { list.add(e); } } public void updateColumns(boolean rebuildCache) { gui.updateColumns(); if (rebuildCache) { cacheRebuild(); //Add or Remove column means everything have to be rebuild... refilter(); } } public List getCurrentFilters() { return gui.getFilters(); } @Override public boolean isFiltersEmpty() { return gui.isFiltersEmpty(); } public void clearCurrentFilters() { gui.clear(); } public void addFilter(final Filter filter) { gui.addFilter(filter); } public void addFilters(final List filters) { gui.addFilters(filters); } public String getCurrentFilterName() { return gui.getCurrentFilterName(); } public JPanel getPanel() { return gui.getPanel(); } public void addExportOption(final JMenuItem jMenuItem) { gui.addExportOption(jMenuItem); } public void setManualLink(final HelpLink helpLink, Icon icon) { gui.setManualLink(helpLink, icon); } public JMenu getMenu(final JTable jTable, final List items) { boolean isNumeric = false; boolean isDate = false; int columnIndex = jTable.getSelectedColumn(); Set simpleFilters = new HashSet<>(); if (jTable.getSelectedColumnCount() == 1 //Single cell (column) //&& jTable.getSelectedRowCount() == 1 //Single cell (row) && !items.isEmpty() //Single element && !(items.get(0) instanceof SeparatorList.Separator) //Not Separator && columnIndex >= 0 //Shown column && columnIndex < tableFormat.getShownColumns().size()) { //Shown column EnumTableColumn column = tableFormat.getShownColumns().get(columnIndex); if (column != null) { isNumeric = isNumeric(column); isDate = isDate(column); for (E e : items) { String text = FilterMatcher.formatFilter(tableFormat.getColumnValue(e, column.name())); if (text != null) { simpleFilters.add(new SimpleFilter(column, text)); } } } } return new FilterMenu<>(jFrame, gui, simpleFilters, isNumeric, isDate); } String getName() { return toolName; } public EventList getEventList() { return eventList; } public EventList getExportEventList() { return exportEventList; } public FilterList getFilterList() { return filterList; } Map> getFilters() { return filters; } @Override public Map> getAllFilters() { //Need to be updated each time something has changed.... Map> allFilters = new HashMap<>(); allFilters.putAll(defaultFilters); allFilters.putAll(filters); return allFilters; } Map> getDefaultFilters() { return defaultFilters; } /** * @return Current list of settings update listeners. List may be empty but should never be null. */ public List getSettingsUpdateListenerList() { return settingsUpdateListenerList; } /*** * @return Is the filter panel shown */ public boolean isFilterShown() { return gui.isFilterShown(); } /*** * @param shown Whether to show the filter panel */ public void setFilterShown(boolean shown) { gui.setFilterShown(shown); } /** * Overwrite to do stuff before filtering. */ protected void beforeFilter() { } /** * Overwrite to do stuff after filtering. */ protected void afterFilter() { } /** * Overwrite to do stuff after saved filters have been changed. */ protected void updateFilters() { } protected List> columnsAsList(final EnumTableColumn[] fixme) { List> columns = new ArrayList<>(); columns.addAll(Arrays.asList(fixme)); return columns; } boolean isNumeric(final EnumTableColumn column) { if (column == null) { return false; } else if (column instanceof AllColumn) { return false; } else if (Number.class.isAssignableFrom(column.getType())) { return true; } else if (NumberValue.class.isAssignableFrom(column.getType())) { return true; } else { return false; } } boolean isDate(final EnumTableColumn column) { if (column == null) { return false; } else if (column instanceof AllColumn) { return false; } else if (Date.class.isAssignableFrom(column.getType())) { return true; } else { return false; } } boolean isAll(final EnumTableColumn column) { return (column instanceof AllColumn); } private class ListenerClass implements ListEventListener { @Override public void listChanged(final ListEvent listChanges) { gui.updateShowing(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/FilterExport.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog.Formula; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuJumps.Jump; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager.FormulaColumn; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager.JumpColumn; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.SimpleColumnManager; import net.nikr.eve.jeveasset.io.local.SettingsReader; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class FilterExport { //Constants private final String ENABLED = "enabled"; private final String DISABLED = "disabled"; private final String FORMULA = "FORMULA"; private final String JUMP = "JUMP"; private final String toolName; private SimpleColumnManager columnManager; public FilterExport(String toolName) { this(toolName, null); } /** * For testing * @param toolName * @param columnManager */ protected FilterExport(String toolName, SimpleColumnManager columnManager) { this.toolName = toolName; this.columnManager = columnManager; } protected String exportFilter(String filterName, List filterList) { StringBuilder builder = new StringBuilder(); exportFilter(builder, filterName, filterList); return builder.toString(); } protected void exportFilter(StringBuilder builder, String filterName, List filterList) { //Header addHeader(builder, filterName); //Each filter for (Filter filter : filterList) { addFilter(builder, filter); } builder.append("\r\n"); } private void addHeader(StringBuilder builder, String filterName) { builder.append("["); builder.append(toolName.toUpperCase()); //Never used, but, usefull to identify where the filters fit builder.append("] ["); builder.append(wrap(filterName)); builder.append("]\r\n"); } private void addFilter(StringBuilder builder, Filter filter) { builder.append("["); builder.append(filter.getGroup()); builder.append("] ["); builder.append(filter.getLogic().name()); builder.append("] ["); EnumTableColumn column = filter.getColumn(); builder.append(column.name()); builder.append("] ["); builder.append(filter.getCompareType().name()); builder.append("] ["); builder.append(wrap(filter.getText())); builder.append("] ["); builder.append(wrapEnabled(filter.isEnabled())); builder.append("]"); if (column instanceof FormulaColumn) { FormulaColumn formulaColumn = (FormulaColumn) column; builder.append(" ["); builder.append(FORMULA); builder.append(wrap(formulaColumn.getFormula().getOriginalExpression()).replace(" ", "")); builder.append("]"); } if (column instanceof JumpColumn) { JumpColumn jumpColumn = (JumpColumn) column; builder.append(" ["); builder.append(JUMP); builder.append(jumpColumn.getJump().getSystemID()); builder.append("]"); } builder.append("\r\n"); } protected Map> importFilter(String importText) { List filterList = new ArrayList<>(); Map> filters = new HashMap<>(); boolean headerLoaded = false; if (importText == null) { return filters; } List groups = new ArrayList<>(); for (String line : importText.split("[\r\n]+")) { groups.clear(); //Clear old data //For each [*] Pattern pattern = Pattern.compile("\\[([^\\]]|\\]\\])*\\]"); // \[([^\]]|\]\])*\] A([^B]|BB)*B Matcher m = pattern.matcher(line); while (m.find()) { groups.add(m.group()); } //Header if (groups.size() == 2) { filterList = new ArrayList<>(); //New list (as the list is passed to "filters") String filterName = unwrap(groups.get(1)); filters.put(filterName, filterList); headerLoaded = true; } //Filter if (headerLoaded) { if (groups.size() == 4) { //backward compatibility (5.7.X and bellow) //Logic Filter.LogicType logic = null; try { logic = Filter.LogicType.valueOf(unwrap(groups.get(0))); } catch (IllegalArgumentException ex) { //Already null; } //Column EnumTableColumn column = SettingsReader.getColumn(unwrap(groups.get(1)), toolName, Settings.get()); //Compare Filter.CompareType compare = null; try { compare = Filter.CompareType.valueOf(unwrap(groups.get(2))); } catch (IllegalArgumentException ex) { //Already null; } String text = null; EnumTableColumn compareColumn = null; if (Filter.CompareType.isColumnCompare(compare)) { compareColumn = SettingsReader.getColumn(unwrap(groups.get(3)), toolName, Settings.get()); if (compareColumn != null) { //Valid text = unwrap(groups.get(3)); } } else { text = unwrap(groups.get(3)); } if (logic != null && column != null && compare != null && (text != null || compareColumn != null)) { Filter filter = new Filter(logic, column, compare, text); filterList.add(filter); } } if (groups.size() >= 5 && headerLoaded) { //Group Integer group = null; try { group = Integer.valueOf(unwrap(groups.get(0))); } catch (IllegalArgumentException ex) { //Already null; } //Logic Filter.LogicType logic = null; try { logic = Filter.LogicType.valueOf(unwrap(groups.get(1))); } catch (IllegalArgumentException ex) { //Already null; } //Column String columnName = unwrap(groups.get(2)); EnumTableColumn column = SettingsReader.getColumn(columnName, toolName, Settings.get()); //Compare Filter.CompareType compare = null; try { compare = Filter.CompareType.valueOf(unwrap(groups.get(3))); } catch (IllegalArgumentException ex) { //Already null; } String text = null; EnumTableColumn compareColumn = null; if (Filter.CompareType.isColumnCompare(compare)) { compareColumn = SettingsReader.getColumn(unwrap(groups.get(4)), toolName, Settings.get()); if (compareColumn != null) { //Valid text = unwrap(groups.get(4)); } } else { text = unwrap(groups.get(4)); } //Enabled boolean enabled = true; if (groups.size() >= 6) { enabled = unwrapEnabled(groups.get(5)); } //Special Columns if (groups.size() == 7 && column == null) { //Only if the column doesn't already exist String columnData = unwrap(groups.get(6)); if (columnData.startsWith(FORMULA)) { String expresion = columnData.replaceFirst(FORMULA, ""); Formula formula = new Formula(columnName, expresion, null); if (columnManager == null) { //Lazy load (as it's initialized after this class) columnManager = ColumnManager.getColumnManager(toolName); } if (columnManager != null) { column = columnManager.addColumn(formula); } } else if (columnData.startsWith(JUMP)) { String system = columnData.replaceFirst(JUMP, ""); try { long systemID = Long.valueOf(system); MyLocation from = ApiIdConverter.getLocation(systemID); Jump jump = new Jump(from); if (columnManager == null) { //Lazy load (as it's initialized after this class) columnManager = ColumnManager.getColumnManager(toolName); } if (columnManager != null) { column = columnManager.addColumn(jump); } } catch (NumberFormatException ex) { //No nothing } } } if (group != null && logic != null && column != null && compare != null && (text != null || compareColumn != null)) { Filter filter = new Filter(group, logic, column, compare, text, enabled); filterList.add(filter); } } } //Ignore everything that does not match the syntax } return filters; } protected String createExample(List> columns) { StringBuilder builder = new StringBuilder(); addHeader(builder, "Example Filter"); boolean s = true; boolean d = true; for (EnumTableColumn column : columns) { if (s && column.getType().equals(String.class)) { addFilter(builder, new Filter(Filter.LogicType.AND, column, Filter.CompareType.CONTAINS, "text")); builder.append("\r\n"); s = false; } if (d && column.getType().equals(Double.class)) { addFilter(builder, new Filter(Filter.LogicType.AND, column, Filter.CompareType.GREATER_THAN, "0")); builder.append("\r\n"); d = false; } if (!d && !s) { break; //both found } } return builder.toString(); } private String wrap(String text) { return text.replace("]", "]]"); } /** * * * Convert the enabled disable flag into a readable format for export. * * @param enabled The state of the flag. * @return A string that contains an export element in human readable form, * either "enabled" or "disabled". */ private String wrapEnabled(boolean enabled) { if (enabled) { return wrap(ENABLED); } return wrap(DISABLED); } private String unwrap(String text) { text = text.substring(1, text.length() - 1); text = text.replace("]]", "]"); return text; } /** * * * Unwrap and convert the human readable enable disable flag to a boolean, * case insensitive. * * @param text The text of the element to be unwrapped and converted. * @return "disabled" returns false, all others (including invalid data) * return true. */ private boolean unwrapEnabled(String text) { String unwrapped = unwrap(text); if (DISABLED.equalsIgnoreCase(unwrapped)) { return false; } else if (ENABLED.equalsIgnoreCase(unwrapped)) { return true; } //Assume true if no match. return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/FilterGui.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.GroupLayout; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.SettingsUpdateListener; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.io.shared.DesktopUtil; import net.nikr.eve.jeveasset.io.shared.DesktopUtil.HelpLink; class FilterGui { private enum FilterGuiAction { ADD, CLEAR, SAVE, MANAGER, SHOW_FILTERS, EXPORT, MANUAL_FILTER, MANUAL_TOOL } private final JPanel jPanel; private final GroupLayout layout; private final JFixedToolBar jToolBar; private final JButton jExportButton; private final JDropDownButton jExportMenu; private final JDropDownButton jLoadFilter; private final JButton jFilterHelp; private final JDropDownButton jHelp; private final JMenuItem jToolHelpMenuItem; private final JCheckBox jShowFilters; private final JLabel jShowing; private final JFrame jFrame; private final FilterControl filterControl; private final SimpleTableFormat tableFormat; private final List> filterPanels = new ArrayList<>(); private final FilterSave filterSave; private final JFilterManagerDialog jFilterManagerDialog; private final ExportDialog exportDialog; private boolean multiUpdate = false; private HelpLink helpLink = null; private final ListenerClass listener = new ListenerClass(); protected FilterGui(final JFrame jFrame, final FilterControl filterControl, SimpleTableFormat tableFormat) { this.jFrame = jFrame; this.filterControl = filterControl; this.tableFormat = tableFormat; exportDialog = new ExportDialog<>(jFrame, filterControl.getName(), filterControl, filterControl, tableFormat, filterControl.getExportEventList()); jPanel = new JPanel(); layout = new GroupLayout(jPanel); jPanel.setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(false); jToolBar = new JFixedToolBar(); //Add JButton jAddField = new JButton(GuiShared.get().addField()); jAddField.setToolTipText(GuiShared.get().addFieldToolTip()); jAddField.setIcon(Images.EDIT_ADD.getIcon()); jAddField.setActionCommand(FilterGuiAction.ADD.name()); jAddField.addActionListener(listener); jToolBar.addButton(jAddField); //Reset JButton jClearFields = new JButton(GuiShared.get().clearField()); jClearFields.setToolTipText(GuiShared.get().clearFieldToolTip()); jClearFields.setIcon(Images.FILTER_CLEAR.getIcon()); jClearFields.setActionCommand(FilterGuiAction.CLEAR.name()); jClearFields.addActionListener(listener); jToolBar.addButton(jClearFields); jToolBar.addSeparator(); //Save Filter JButton jSaveFilter = new JButton(GuiShared.get().saveFilter()); jSaveFilter.setToolTipText(GuiShared.get().saveFilterToolTip()); jSaveFilter.setIcon(Images.FILTER_SAVE.getIcon()); jSaveFilter.setActionCommand(FilterGuiAction.SAVE.name()); jSaveFilter.addActionListener(listener); jToolBar.addButton(jSaveFilter); //Load Filter jLoadFilter = new JDropDownButton(GuiShared.get().loadFilter()); jLoadFilter.setToolTipText(GuiShared.get().loadFilterToolTip()); jLoadFilter.setIcon(Images.FILTER_LOAD.getIcon()); jLoadFilter.keepVisible(2); jLoadFilter.setTopFixedCount(2); jLoadFilter.setInterval(125); jToolBar.addButton(jLoadFilter); jToolBar.addSeparator(); //Export jExportButton = new JButton(GuiShared.get().export()); jExportButton.setToolTipText(GuiShared.get().exportToolTip()); jExportButton.setIcon(Images.DIALOG_CSV_EXPORT.getIcon()); jExportButton.setActionCommand(FilterGuiAction.EXPORT.name()); jExportButton.addActionListener(listener); jToolBar.addButton(jExportButton); jExportMenu = new JDropDownButton(GuiShared.get().export(), Images.DIALOG_CSV_EXPORT.getIcon()); jExportMenu.setToolTipText(GuiShared.get().exportToolTip()); jExportMenu.setVisible(false); jToolBar.addButton(jExportMenu); JMenuItem jExportMenuItem = new JMenuItem(GuiShared.get().exportTableData()); jExportMenuItem.setIcon(Images.DIALOG_CSV_EXPORT.getIcon()); jExportMenuItem.setActionCommand(FilterGuiAction.EXPORT.name()); jExportMenuItem.addActionListener(listener); jExportMenu.add(jExportMenuItem); jToolBar.addSeparator(); //Show Filters jShowFilters = new JCheckBox(GuiShared.get().showFilters()); jShowFilters.setToolTipText(GuiShared.get().showFiltersToolTip()); jShowFilters.setActionCommand(FilterGuiAction.SHOW_FILTERS.name()); jShowFilters.addActionListener(listener); jShowFilters.setSelected(true); jToolBar.add(jShowFilters); jToolBar.addGlue(5); //Showing jShowing = new JLabel(); jShowing.setHorizontalAlignment(JLabel.RIGHT); jToolBar.add(jShowing); jToolBar.addSpace(5); jHelp = new JDropDownButton(Images.MISC_HELP.getIcon()); jHelp.setVisible(false); jToolBar.addButtonIcon(jHelp); JMenuItem jFilterHelpMenuItem = new JMenuItem(GuiShared.get().helpFilter(), Images.MISC_HELP.getIcon()); jFilterHelpMenuItem.setActionCommand(FilterGuiAction.MANUAL_FILTER.name()); jFilterHelpMenuItem.addActionListener(listener); jHelp.add(jFilterHelpMenuItem); jToolHelpMenuItem = new JMenuItem(Images.SETTINGS_TOOLS.getIcon()); jToolHelpMenuItem.setActionCommand(FilterGuiAction.MANUAL_TOOL.name()); jToolHelpMenuItem.addActionListener(listener); jHelp.add(jToolHelpMenuItem); jFilterHelp = new JButton(Images.MISC_HELP.getIcon()); jFilterHelp.setActionCommand(FilterGuiAction.MANUAL_FILTER.name()); jFilterHelp.addActionListener(listener); jToolBar.addButtonIcon(jFilterHelp); updateFilters(); add(); filterSave = new FilterSave(jFrame); jFilterManagerDialog = new JFilterManagerDialog<>(jFrame, filterControl.getName(), this, tableFormat.getAllColumns(), filterControl.getFilters(), filterControl.getDefaultFilters()); } protected JPanel getPanel() { return jPanel; } public void updateColumns() { for (FilterPanel filterPanel : filterPanels) { filterPanel.updateColumns(); } } /*** * @return Is the filter panel shown */ public boolean isFilterShown() { return jShowFilters.isSelected(); } /*** * @param shown Whether to show the filter panel */ public void setFilterShown(boolean shown) { jShowFilters.setSelected(shown); update(); } protected final void addExportOption(final JMenuItem jMenuItem) { if (!jExportMenu.isVisible()) { //First jExportMenu.setVisible(true); jExportButton.setVisible(false); } jExportMenu.add(jMenuItem); } protected final void setManualLink(final HelpLink helpLink, Icon icon) { this.helpLink = helpLink; if (helpLink != null) { jToolHelpMenuItem.setText(helpLink.getTitle()); jToolHelpMenuItem.setIcon(icon); jHelp.setVisible(true); jFilterHelp.setVisible(false); } else { jHelp.setVisible(false); jFilterHelp.setVisible(true); } } protected void updateShowing() { jShowing.setText(GuiShared.get().filterShowing(EventListManager.size(filterControl.getFilterList()), EventListManager.size(filterControl.getEventList()), getCurrentFilterName())); } protected String getCurrentFilterName() { if (isFiltersEmpty()) { return GuiShared.get().filterEmpty(); } List filters = getFilters(); if (filterControl.getAllFilters().containsValue(filters)) { for (Map.Entry> entry : filterControl.getAllFilters().entrySet()) { if (entry.getValue().equals(filters)) { return entry.getKey(); } } } return GuiShared.get().filterUntitled(); } protected List getFilters() { List filters = new ArrayList<>(); for (FilterPanel filterPanel : filterPanels) { filters.add(filterPanel.getFilter()); } return filters; } protected boolean isFiltersEmpty() { //One filter that is empty. Otherwise not empty return filterPanels.size() == 1 && filterPanels.get(0).getFilter().isEmpty(); } private List> getMatchers() { List> matchers = new ArrayList<>(); for (FilterPanel filterPanel : filterPanels) { FilterMatcher matcher = filterPanel.getMatcher(); if (!matcher.isEmpty()) { matchers.add(matcher); } } return matchers; } protected void update() { update(true); } private void update(boolean sort) { //Save focus owner Component focusOwner = jFrame.getFocusOwner(); //Update group updateGroupSize(); jPanel.removeAll(); GroupLayout.ParallelGroup horizontalGroup = layout.createParallelGroup(); GroupLayout.SequentialGroup verticalGroup = layout.createSequentialGroup(); //Toolbars horizontalGroup.addComponent(jToolBar, jToolBar.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE); verticalGroup.addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE); //Filters if (jShowFilters.isSelected()) { if (sort) { Collections.sort(filterPanels); } int group = -1; for (FilterPanel filterPanel : filterPanels) { if (!filterPanel.isMoving()) { if (group > -1 && group != filterPanel.getGroup()) { FilterPanelSeparator separator = new FilterPanelSeparator(group); horizontalGroup.addComponent(separator.getPanel()); verticalGroup.addGap(0).addComponent(separator.getPanel(), GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE).addGap(0); } group = filterPanel.getGroup(); } horizontalGroup.addComponent(filterPanel.getPanel()); verticalGroup.addComponent(filterPanel.getPanel(), GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE); } } layout.setHorizontalGroup(horizontalGroup); layout.setVerticalGroup(verticalGroup); //Load focus owner if (focusOwner != null) { focusOwner.requestFocusInWindow(); } } protected void updateGroupSize() { Set groups = new HashSet<>(); for (FilterPanel filterPanel : filterPanels) { if (!filterPanel.isAnd()) { groups.add(filterPanel.getGroup()); } } int groupSize = groups.size() + 1; for (FilterPanel filterPanel : filterPanels) { filterPanel.updateGroupSize(groupSize); } } protected int getFromIndex(FilterPanel filterPanel) { return filterPanels.indexOf(filterPanel); } protected int getToIndex(FilterPanel filterPanel) { List> list = new ArrayList<>(filterPanels); Collections.sort(list); return list.indexOf(filterPanel); } protected void move(FilterPanel filterPanel, int index) { filterPanels.remove(filterPanel); filterPanels.add(index, filterPanel); update(false); } protected boolean fade(FilterPanel filterPanel) { int index = filterPanels.indexOf(filterPanel); List> list = new ArrayList<>(filterPanels); Collections.sort(list); return index != list.indexOf(filterPanel); } protected void clone(final FilterPanel filterPanel) { int index = filterPanels.indexOf(filterPanel); FilterPanel clone = new FilterPanel<>(this, filterControl, tableFormat); clone.setFilter(filterPanel.getFilter()); filterPanels.add(index, clone); if (!multiUpdate) { update(); } } protected void remove(final FilterPanel filterPanel) { filterPanels.remove(filterPanel); if (!multiUpdate) { update(); } } private void add() { add(new FilterPanel<>(this, filterControl, tableFormat)); } private void add(final FilterPanel filterPanel) { filterPanels.add(filterPanel); if (!multiUpdate) { update(); } } protected void addEmpty() { if (filterPanels.isEmpty()) { add(); } } private void clearEmpty() { if (isFiltersEmpty()) { remove(filterPanels.get(0)); } } protected void clear() { multiUpdate = true; while (!filterPanels.isEmpty()) { remove(filterPanels.get(0)); } addEmpty(); multiUpdate = false; update(); refilter(); } private void loadFilter(final String filterName, final boolean add) { if (filterName == null) { return; } if (filterControl.getAllFilters().containsKey(filterName)) { List filters = filterControl.getAllFilters().get(filterName); if (add) { addFilters(filters); } else { setFilters(filters); } } } protected void setFilters(final List filters) { multiUpdate = true; while (!filterPanels.isEmpty()) { remove(filterPanels.get(0)); } multiUpdate = false; addFilters(filters); } protected void addFilter(final Filter filter) { addFilters(Collections.singletonList(filter)); } protected void addFilters(final List filters) { multiUpdate = true; clearEmpty(); //Remove single empty filter... for (Filter filter : filters) { FilterPanel filterPanel = new FilterPanel<>(this, filterControl, tableFormat); filterPanel.setFilter(filter); add(filterPanel); } addEmpty(); //Add single filter (if empty) multiUpdate = false; update(); refilter(); } protected final void updateFilters() { jLoadFilter.removeAll(); JMenuItem jMenuItem; jMenuItem = new JMenuItem(GuiShared.get().manageFilters(), Images.DIALOG_SETTINGS.getIcon()); jMenuItem.setActionCommand(FilterGuiAction.MANAGER.name()); jMenuItem.addActionListener(listener); jMenuItem.setRolloverEnabled(true); jLoadFilter.add(jMenuItem); List filters = new ArrayList<>(filterControl.getFilters().keySet()); Collections.sort(filters, StringComparators.CASE_INSENSITIVE); List defaultFilters = new ArrayList<>(filterControl.getDefaultFilters().keySet()); Collections.sort(defaultFilters, StringComparators.CASE_INSENSITIVE); if (!filters.isEmpty() || !defaultFilters.isEmpty()) { jLoadFilter.addSeparator(); } for (String s : defaultFilters) { jMenuItem = new JMenuItem(s, Images.FILTER_LOAD_DEFAULT.getIcon()); jMenuItem.setRolloverEnabled(true); jMenuItem.setActionCommand(s); jMenuItem.addActionListener(listener); jLoadFilter.add(jMenuItem); } for (String s : filters) { jMenuItem = new JMenuItem(s, Images.FILTER_LOAD.getIcon()); jMenuItem.setRolloverEnabled(true); jMenuItem.setActionCommand(s); jMenuItem.addActionListener(listener); jLoadFilter.add(jMenuItem); } updateShowing(); filterControl.updateFilters(); } protected void saveSettings(String msg) { filterControl.saveSettings(msg); } protected void refilter() { filterControl.beforeFilter(); List> matchers = getMatchers(); boolean empty = true; for (FilterMatcher matcher : matchers) { if (!matcher.isEmpty()) { empty = false; break; } } if (empty) { filterControl.getFilterList().setMatcher(null); } else { filterControl.getFilterList().setMatcher(new FilterLogicalMatcher<>(matchers)); } filterControl.afterFilter(); updateShowing(); fireSettingsUpdate(); } protected void repaint() { for (FilterPanel filterPanel : filterPanels) { filterPanel.repaint(); } } protected String getFilterName() { return filterSave.show(new ArrayList<>(filterControl.getFilters().keySet()), new ArrayList<>(filterControl.getDefaultFilters().keySet())); } /** * Loop though set update listeners and trigger their action. */ private void fireSettingsUpdate() { for (SettingsUpdateListener updateListener : filterControl.getSettingsUpdateListenerList()) { updateListener.settingChanged(); } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (FilterGuiAction.ADD.name().equals(e.getActionCommand())) { add(); updateShowing(); fireSettingsUpdate(); } else if (FilterGuiAction.CLEAR.name().equals(e.getActionCommand())) { clear(); } else if (FilterGuiAction.MANAGER.name().equals(e.getActionCommand())) { jFilterManagerDialog.setVisible(true); } else if (FilterGuiAction.SHOW_FILTERS.name().equals(e.getActionCommand())) { update(); Settings.get().getCurrentTableFiltersShown().put(filterControl.getName(), isFilterShown()); fireSettingsUpdate(); } else if (FilterGuiAction.SAVE.name().equals(e.getActionCommand())) { if (isFiltersEmpty()) { JOptionPane.showMessageDialog(jFrame, GuiShared.get().nothingToSave(), GuiShared.get().saveFilter(), JOptionPane.PLAIN_MESSAGE); } else { String name = filterSave.show(new ArrayList<>(filterControl.getFilters().keySet()), new ArrayList<>(filterControl.getDefaultFilters().keySet())); if (name != null && !name.isEmpty()) { Settings.lock("Filter (New)"); //Lock for Filter (New) filterControl.getFilters().put(name, getFilters()); Settings.unlock("Filter (New)"); //Unlock for Filter (New) saveSettings("Filter (New)"); //Save Filter (New) updateFilters(); } } } else if (FilterGuiAction.EXPORT.name().equals(e.getActionCommand())) { exportDialog.setVisible(true); } else if (FilterGuiAction.MANUAL_FILTER.name().equals(e.getActionCommand())) { DesktopUtil.browse(new HelpLink("https://wiki.jeveassets.org/manual/filters", GuiShared.get().helpFilter()), jFrame); } else if (FilterGuiAction.MANUAL_TOOL.name().equals(e.getActionCommand())) { DesktopUtil.browse(helpLink, jFrame); } else { loadFilter(e.getActionCommand(), (e.getModifiers() & ActionEvent.CTRL_MASK) != 0); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/FilterLogicalMatcher.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import ca.odell.glazedlists.matchers.Matcher; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class FilterLogicalMatcher implements Matcher { private final List> and = new ArrayList<>(); private final Map>> or = new HashMap<>(); public FilterLogicalMatcher(final List> matchers) { for (FilterMatcher matcher : matchers) { addMatcher(matcher); } } public FilterLogicalMatcher(final SimpleTableFormat tableFormat, ColumnCache columnCache, final List filters) { for (Filter filter : filters) { FilterMatcher matcher = new FilterMatcher<>(tableFormat, columnCache, filter); addMatcher(matcher); } } private void addMatcher(FilterMatcher matcher) { if (!matcher.isEmpty()) { if (matcher.isAnd()) { //And and.add(matcher); } else { List> list = or.get(matcher.getGroup()); if (list == null) { list = new ArrayList<>(); or.put(matcher.getGroup(), list); } list.add(matcher); } } } @Override public boolean matches(final E item) { for (FilterMatcher matcher : and) { if (!matcher.matches(item)) { //if just one don't match, none match return false; } } //All ANDs matches for (List> list : or.values()) { boolean found = false; for (FilterMatcher matcher : list) { if (matcher.matches(item)) { //if just one is true all is true found = true; break; } } if (!found) { //if none in group match (just need to match one) return false; } } return true; //Matched } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/FilterMatcher.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import ca.odell.glazedlists.matchers.Matcher; import java.text.NumberFormat; import java.text.ParsePosition; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.TimeZone; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.CompareType; import static net.nikr.eve.jeveasset.gui.shared.filter.Filter.CompareType.NEXT_DAYS; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.LogicType; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.AssetContainer; import net.nikr.eve.jeveasset.gui.shared.table.containers.NumberValue; public class FilterMatcher implements Matcher { public static final Locale LOCALE = Locale.ENGLISH; //Use english AKA US_EN private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(LOCALE); private static final NumberFormat PERCENT_FORMAT = NumberFormat.getPercentInstance(LOCALE); private static final Calendar CALENDAR = Calendar.getInstance(TimeZone.getTimeZone("GMT")); private static final Map CELL_VALUE_CACHE = new HashMap<>(); private static boolean cellValueCache = false; //Cell value cache private final SimpleTableFormat tableFormat; private final ColumnCache columnCache; private final int group; private final boolean and; private final EnumTableColumn enumColumn; private final CompareType compare; private final String text; private final Pattern pattern; private final boolean empty; FilterMatcher(final SimpleTableFormat filterControl, ColumnCache columnCache, final Filter filter) { this(filterControl, columnCache, filter.getGroup(), filter.getLogic(), filter.getColumn(), filter.getCompareType(), filter.getText(), filter.isEnabled()); } FilterMatcher(final SimpleTableFormat tableFormat, ColumnCache columnCache, int group, final LogicType logic, final EnumTableColumn enumColumn, final CompareType compare, final String text, final boolean enabled) { this.tableFormat = tableFormat; this.columnCache = columnCache; this.group = group; this.enumColumn = enumColumn; this.compare = compare; Pattern compiled; if (text == null) { this.pattern = null; } else { try { compiled = Pattern.compile(format(text), Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); } catch (PatternSyntaxException ex) { compiled = Pattern.compile("", Pattern.CASE_INSENSITIVE); } this.pattern = compiled; } if (CompareType.isColumnCompare(compare)) { this.text = text; } else { this.text = formatData(text, true); } empty = !enabled || text == null || text.isEmpty(); and = logic == Filter.LogicType.AND; } public int getGroup() { return group; } protected boolean isAnd() { return and; } public boolean isEmpty() { return empty; } @Override public boolean matches(final E item) { if (enumColumn instanceof Filter.AllColumn) { return matchesAll(item); } Object column = tableFormat.getColumnValue(item, enumColumn.name()); if (column == null) { return false; } if (null == compare) { //Fallback: show all... return true; } else switch (compare) { case CONTAINS: return contains(column, text); case CONTAINS_NOT: return !contains(column, text); case EQUALS: return equals(column, text); case EQUALS_DATE: return equalsDate(column, text); case EQUALS_NOT: return !equals(column, text); case REGEX: return regex(column, pattern); case EQUALS_NOT_DATE: return !equalsDate(column, text); case GREATER_THAN: return great(column, text); case LESS_THAN: return less(column, text); case BEFORE: return before(column, text); case AFTER: return after(column, text); case GREATER_THAN_COLUMN: return great(column, tableFormat.getColumnValue(item, text)); case LESS_THAN_COLUMN: return less(column, tableFormat.getColumnValue(item, text)); case EQUALS_COLUMN: return equals(column, formatData(tableFormat.getColumnValue(item, text), false)); case EQUALS_NOT_COLUMN: return !equals(column, formatData(tableFormat.getColumnValue(item, text), false)); case CONTAINS_COLUMN: return contains(column, formatData(tableFormat.getColumnValue(item, text), false)); case CONTAINS_NOT_COLUMN: return !contains(column, formatData(tableFormat.getColumnValue(item, text), false)); case BEFORE_COLUMN: return before(column, tableFormat.getColumnValue(item, text)); case AFTER_COLUMN: return after(column, tableFormat.getColumnValue(item, text)); case LAST_DAYS: return lastDays(column, text); case NEXT_DAYS: return nextDays(column, text); case LAST_HOURS: return lastHours(column, text); case NEXT_HOURS: return nextHours(column, text); default: //Fallback: show all... return true; } } public static String buildItemCache(SimpleTableFormat filterControl, E e) { StringBuilder builder = new StringBuilder(); for (EnumTableColumn testColumn : filterControl.getAllColumns()) { Object columnValue = filterControl.getColumnValue(e, testColumn.name()); if (columnValue != null) { builder.append("\n"); builder.append(formatData(columnValue, false)); builder.append("\r"); } } return builder.toString(); } private boolean matchesAll(final E item) { String haystack; if (columnCache != null) { haystack = columnCache.getCache().get(item); if (haystack == null) { //Will be build on update if any filter is set haystack = buildItemCache(tableFormat, item); columnCache.addCache(item, haystack); } } else { haystack = buildItemCache(tableFormat, item); } if (compare == null || text == null) { return true; } else switch (compare) { case CONTAINS: return haystack.contains(text); case CONTAINS_NOT: return !haystack.contains(text); case EQUALS: return haystack.contains("\n" + text + "\r"); case EQUALS_NOT: return !haystack.contains("\n" + text + "\r"); case REGEX: return pattern.matcher(haystack).find(); default: return true; } } private boolean equals(final Object object1, final String formattedText) { //Null if (object1 == null || formattedText == null) { return false; } //Equals (case insentive) return formatData(object1, false).equals(formattedText); } private boolean regex(final Object object1, final Pattern pattern) { //Null if (object1 == null || pattern == null) { return false; } //Rexex return pattern.matcher(formatData(object1, false)).find(); } private boolean contains(final Object object1, final String formattedText) { //Null if (object1 == null || formattedText == null) { return false; } //Contains (case insentive) return formatData(object1, false).contains(formattedText); } private boolean less(final Object object1, final Object object2) { return greatThen(object2, object1, false); } private boolean great(final Object object1, final Object object2) { return greatThen(object1, object2, true); } private boolean greatThen(final Object object1, final Object object2, final boolean fallback) { //Null if (object1 == null || object2 == null) { return fallback; } //Double / Float Double double1 = getDouble(object1); Double double2 = getDouble(object2); //Long / Integer Long long1 = getLong(object1); Long long2 = getLong(object2); if (long1 != null && long2 != null) { return long1 > long2; } if (long1 != null && double2 != null) { return long1 > double2; } if (double1 != null && double2 != null) { return double1 > double2; } if (double1 != null && long2 != null) { return double1 > long2; } return fallback; //Fallback } private boolean before(final Object object1, final Object object2) { //Date Date date1 = getDate(object1, false); Date date2 = getDate(object2, true); if (date1 != null && date2 != null) { CALENDAR.setTime(date2); CALENDAR.set(Calendar.HOUR_OF_DAY, 0); CALENDAR.set(Calendar.MINUTE, 0); CALENDAR.set(Calendar.SECOND, 0); CALENDAR.set(Calendar.MILLISECOND, 0); return date1.before(CALENDAR.getTime()); } return false; //Fallback } private boolean after(final Object object1, final Object object2) { Date date1 = getDate(object1, false); Date date2 = getDate(object2, true); if (date1 != null && date2 != null) { CALENDAR.setTime(date2); CALENDAR.set(Calendar.HOUR_OF_DAY, 23); CALENDAR.set(Calendar.MINUTE, 59); CALENDAR.set(Calendar.SECOND, 59); CALENDAR.set(Calendar.MILLISECOND, 999); return date1.after(CALENDAR.getTime()); } return false; } private boolean equalsDate(final Object object1, final Object object2) { Date date1 = getDate(object1, false); Date date2 = getDate(object2, true); if (date1 != null && date2 != null) { CALENDAR.setTime(date2); CALENDAR.set(Calendar.HOUR_OF_DAY, 12); CALENDAR.set(Calendar.MINUTE, 0); CALENDAR.set(Calendar.SECOND, 0); CALENDAR.set(Calendar.MILLISECOND, 0); date2 = CALENDAR.getTime(); CALENDAR.setTime(date1); CALENDAR.set(Calendar.HOUR_OF_DAY, 12); CALENDAR.set(Calendar.MINUTE, 0); CALENDAR.set(Calendar.SECOND, 0); CALENDAR.set(Calendar.MILLISECOND, 0); date1 = CALENDAR.getTime(); return date1.equals(date2); } return false; } private boolean lastDays(final Object object1, final Object object2) { Date date = getDate(object1, false); Number days = createNumber(object2); if (date != null && days != null) { CALENDAR.setTime(new Date()); CALENDAR.set(Calendar.HOUR_OF_DAY, 0); CALENDAR.set(Calendar.MINUTE, 0); CALENDAR.set(Calendar.SECOND, 0); CALENDAR.set(Calendar.MILLISECOND, 0); CALENDAR.add(Calendar.DAY_OF_MONTH, -days.intValue()); return date.before(Settings.getNow()) && date.after(CALENDAR.getTime()); } return false; } private boolean nextDays(final Object object1, final Object object2) { Date date = getDate(object1, false); Number days = createNumber(object2); if (date != null && days != null) { CALENDAR.setTime(new Date()); CALENDAR.set(Calendar.HOUR_OF_DAY, 23); CALENDAR.set(Calendar.MINUTE, 59); CALENDAR.set(Calendar.SECOND, 59); CALENDAR.set(Calendar.MILLISECOND, 999); CALENDAR.add(Calendar.DAY_OF_MONTH, days.intValue()); return date.after(Settings.getNow()) && date.before(CALENDAR.getTime()); } return false; } private boolean lastHours(final Object object1, final Object object2) { Date date = getDate(object1, false); Number hours = createNumber(object2); if (date != null && hours != null) { CALENDAR.setTime(new Date()); CALENDAR.add(Calendar.HOUR_OF_DAY, -hours.intValue()); return date.before(Settings.getNow()) && date.after(CALENDAR.getTime()); } return false; } private boolean nextHours(final Object object1, final Object object2) { Date date = getDate(object1, false); Number hours = createNumber(object2); if (date != null && hours != null) { CALENDAR.setTime(new Date()); CALENDAR.add(Calendar.HOUR_OF_DAY, hours.intValue()); return date.after(Settings.getNow()) && date.before(CALENDAR.getTime()); } return false; } private static Number getNumber(final Object obj, final boolean userInput) { if (obj instanceof Number) { return (Number) obj; } else if (obj instanceof NumberValue) { return ((NumberValue) obj).getNumber(); } else if (userInput) { return createNumber(obj); } else { return null; } } private Double getDouble(final Object obj) { if (obj instanceof Double) { return (Double) obj; } else if (obj instanceof Float) { return Double.valueOf((Float) obj); } else if (obj instanceof NumberValue) { return ((NumberValue) obj).getDouble(); } else { return createDouble(obj); } } private Long getLong(final Object obj) { if (obj instanceof Long) { return (Long) obj; } else if (obj instanceof Integer) { return Long.valueOf((Integer) obj); } else if (obj instanceof NumberValue) { return ((NumberValue) obj).getLong(); } else { return null; } } private static Double createDouble(final Object object) { Number number = parse(object, NUMBER_FORMAT); if (number != null) { return number.doubleValue(); } else { return null; } } private static Number createNumber(final Object object) { Number number = parse(object, NUMBER_FORMAT); if (number != null) { return number; } else { return createPercent(object); } } private static Double createPercent(final Object object) { Number d = parse(object, PERCENT_FORMAT); if (d != null) { return d.doubleValue() * 100; } else { return null; } } private static Number parse(final Object object, final NumberFormat numberFormat) { if (object instanceof String) { String filterValue = (String) object; //Used to check if parsing was successful ParsePosition position = new ParsePosition(0); //Parse number using the Locale Number n = numberFormat.parse(filterValue, position); if (n != null && position.getIndex() == filterValue.length()) { //Numeric return n; } } return null; } private static Date getDate(final Object obj, final boolean userInput) { if (obj instanceof Date) { return (Date) obj; } else if (userInput && (obj instanceof String)) { return Formatter.columnStringToDate((String) obj); } else { return null; } } private static AssetContainer getAssetContainer(final Object obj) { if (obj instanceof AssetContainer) { return (AssetContainer) obj; } else { return null; } } public static String formatFilter(final Object object) { return format(object, false); } private static String formatData(final Object object, final boolean userInput) { if (object == null) { return null; } return format(object, userInput).toLowerCase(); } public static void clearColumnValueCache() { CELL_VALUE_CACHE.clear(); cellValueCache = Settings.get().isColumnValueCache(); } private static String format(final Object object, final boolean userInput) { if (cellValueCache) { String value = CELL_VALUE_CACHE.get(object); if (value != null) { return value; } else { value = createFormat(object, userInput); CELL_VALUE_CACHE.put(object, value); return value; } } else { return createFormat(object, userInput); } } private static String createFormat(final Object object, final boolean userInput) { if (object == null) { return null; } //Number Number number = getNumber(object, userInput); if (number != null) { return Formatter.compareFormat(number); } //Date Date date = getDate(object, userInput); if (date != null) { return Formatter.columnDate(date); } //AssetContainer AssetContainer assetContainer = getAssetContainer(object); if (assetContainer != null) { return assetContainer.getContainer(); } //String return format(object.toString()); } private static String format(String string) { return string .replace("„", "\"") //Index .replace("“", "\"") //Set transmit state .replace("”", "\"") //Cancel character .replace("‘", "'") //Private use one .replace("’", "'") //Private use two .replace("`", "'") //Grave accent .replace("´", "'") //Acute accent .replace("–", "-") //En dash .replace("‐", "-") //Hyphen .replace("‑", "-") //Non-breaking hyphen .replace("‒", "-") //Figure dash .replace("—", "-") //Em dash ; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/FilterMenu.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Date; import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.CompareType; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.LogicType; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.GuiShared; class FilterMenu extends JMenu { private final JFrame jFrame; private final FilterGui gui; private final Set filters; FilterMenu(final JFrame jFrame, final FilterGui gui, Set filters, final boolean isNumeric, final boolean isDate) { super(GuiShared.get().popupMenuAddField()); this.jFrame = jFrame; this.gui = gui; this.setIcon(Images.FILTER_CONTAIN.getIcon()); this.filters = filters; ListenerClass listener = new ListenerClass(); JMenuItem jMenuItem; CompareType[] compareTypes; if (isNumeric) { compareTypes = CompareType.valuesNumeric(); } else if (isDate) { compareTypes = CompareType.valuesDate(); } else { compareTypes = CompareType.valuesString(); } for (CompareType compareType : compareTypes) { jMenuItem = new JMenuItem(compareType.toString()); jMenuItem.setIcon(compareType.getIcon()); jMenuItem.setActionCommand(compareType.name()); jMenuItem.addActionListener(listener); jMenuItem.setEnabled(!filters.isEmpty()); add(jMenuItem); } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (filters.size() > 1) { int returnValue = JOptionPane.showConfirmDialog(jFrame, GuiShared.get().popupMenuAddFieldMsg(filters.size()), GuiShared.get().popupMenuAddField(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if (returnValue == JOptionPane.CANCEL_OPTION) { return; } } for (SimpleFilter filter : filters) { gui.addFilter(filter.getFilter(e.getActionCommand())); } } } public static class SimpleFilter { private final EnumTableColumn column; private final String text; public SimpleFilter(EnumTableColumn column, String text) { this.column = column; this.text = text; } public Filter getFilter(String s) { CompareType compareType = Filter.CompareType.valueOf(s); if (CompareType.isColumnCompare(compareType)) { return new Filter(LogicType.AND, column, compareType, column.name()); } else if (compareType == CompareType.LAST_DAYS || compareType == CompareType.NEXT_DAYS) { return new Filter(LogicType.AND, column, compareType, between(TimeUnit.DAYS)); } else if (compareType == CompareType.LAST_HOURS || compareType == CompareType.NEXT_HOURS) { return new Filter(LogicType.AND, column, compareType, between(TimeUnit.HOURS)); } else { return new Filter(LogicType.AND, column, compareType, text); } } private String between(TimeUnit unit) { Date date = Formatter.columnStringToDate(text); long diff = Math.abs(date.getTime() - Settings.getNow().getTime()); long hours = unit.convert(diff, TimeUnit.MILLISECONDS) + 1; return String.valueOf(hours); } @Override public int hashCode() { int hash = 7; hash = 79 * hash + Objects.hashCode(this.column); hash = 79 * hash + Objects.hashCode(this.text); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final SimpleFilter other = (SimpleFilter) obj; if (!Objects.equals(this.text, other.text)) { return false; } return Objects.equals(this.column, other.column); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/FilterPanel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import com.github.lgooddatepicker.optionalusertools.DateChangeListener; import com.github.lgooddatepicker.zinternaltools.DateChangeEvent; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import javax.swing.BorderFactory; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.SpinnerListModel; import javax.swing.SpinnerNumberModel; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.border.CompoundBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.plaf.synth.SynthFormattedTextFieldUI; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.TextManager; import net.nikr.eve.jeveasset.gui.shared.components.JDateChooser; import net.nikr.eve.jeveasset.gui.shared.components.ListComboBoxModel; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.AllColumn; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.CompareType; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.LogicType; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; class FilterPanel implements Comparable> { private enum FilterPanelAction { FILTER, FILTER_TIMER, GROUP_TIMER, REMOVE, CLONE } private final JPanel jPanel; private final GroupLayout layout; private final JCheckBox jEnabled; private final JComboBox jLogic; private final JSpinner jGroup; private final JComboBox> jColumn; private final JComboBox jCompare; private final JTextField jText; private final JComboBox> jCompareColumn; private final JDateChooser jDate; private final JLabel jSpacing; private final JButton jRemove; private final JButton jClone; private final Timer timer; private final Timer groupTimer; private final FilterGui gui; private final FilterControl filterControl; private final SimpleTableFormat tableFormat; private final List> allColumns; private final List> numericColumns; private final List> dateColumns; private final SpinnerNumberModel groupModel; private final Executor fades = Executors.newSingleThreadExecutor(); private boolean loading = false; private boolean moving = false; FilterPanel(final FilterGui gui, final FilterControl filterControl, SimpleTableFormat tableFormat) { this.gui = gui; this.filterControl = filterControl; this.tableFormat = tableFormat; ListenerClass listener = new ListenerClass(); groupTimer = new Timer(500, listener); groupTimer.setActionCommand(FilterPanelAction.GROUP_TIMER.name()); groupModel = new SpinnerNumberModel(0, 0, 0, 1); groupModel.addChangeListener(listener); jGroup = new JSpinner(groupModel); jGroup.setEnabled(false); allColumns = new ArrayList<>(); allColumns.add(new AllColumn<>()); allColumns.addAll(tableFormat.getAllColumns()); numericColumns = new ArrayList<>(); for (EnumTableColumn object : tableFormat.getAllColumns()) { if (filterControl.isNumeric(object)) { numericColumns.add(object); } } dateColumns = new ArrayList<>(); for (EnumTableColumn object : tableFormat.getAllColumns()) { if (filterControl.isDate(object)) { dateColumns.add(object); } } jEnabled = new JCheckBox(); jEnabled.setSelected(true); jEnabled.addActionListener(listener); jEnabled.setActionCommand(FilterPanelAction.FILTER.name()); jLogic = new JComboBox<>(LogicType.values()); jLogic.setPrototypeDisplayValue(LogicType.AND); jLogic.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { boolean oldValue = loading; loading = true; Dimension preferredSize = ((JSpinner.DefaultEditor) jGroup.getEditor()).getTextField().getPreferredSize(); groupModel.removeChangeListener(listener); if (isAnd()) { groupModel.setMinimum(0); groupModel.setValue(0); jGroup.setEditor(new JSpinner.DefaultEditor(jGroup)); jGroup.setModel(new SpinnerListModel(Collections.singletonList(""))); jGroup.setEditor(new JSpinner.DefaultEditor(jGroup)); jGroup.setEnabled(false); } else { groupModel.addChangeListener(listener); jGroup.setModel(groupModel); jGroup.setEditor(new JSpinner.NumberEditor(jGroup)); groupModel.setMinimum(1); if (groupModel.getNumber().intValue() == 0) { groupModel.setValue(1); } jGroup.setEnabled(true); } ((JSpinner.DefaultEditor) jGroup.getEditor()).getTextField().setHorizontalAlignment(JTextField.CENTER); ((JSpinner.DefaultEditor) jGroup.getEditor()).getTextField().setPreferredSize(preferredSize); ((JSpinner.DefaultEditor) jGroup.getEditor()).getTextField().setMaximumSize(preferredSize); ((JSpinner.DefaultEditor) jGroup.getEditor()).getTextField().setMinimumSize(preferredSize); ((JSpinner.DefaultEditor) jGroup.getEditor()).getTextField().setEditable(false); ((JSpinner.DefaultEditor) jGroup.getEditor()).getTextField().setFocusable(false); loading = oldValue; if (!loading) { groupChanged(); } } }); loading = true; jLogic.setSelectedIndex(0); loading = false; updateGroupColor(); JComboBox jComboBox = new JComboBox<>(); FontMetrics fontMetrics = jComboBox.getFontMetrics(jComboBox.getFont()); EnumTableColumn longestColumn = null; for (EnumTableColumn column : allColumns) { if (longestColumn == null || fontMetrics.stringWidth(longestColumn.getColumnName()) < fontMetrics.stringWidth(column.getColumnName())) { longestColumn = column; } } jColumn = new JComboBox<>(new ListComboBoxModel<>(allColumns)); jColumn.setPrototypeDisplayValue(longestColumn); jColumn.addActionListener(listener); jColumn.setActionCommand(FilterPanelAction.FILTER.name()); jCompare = new JComboBox<>(); jCompare.setPrototypeDisplayValue(CompareType.CONTAINS_NOT_COLUMN); jCompare.addActionListener(listener); jCompare.setActionCommand(FilterPanelAction.FILTER.name()); jText = new JTextField(); jText.getDocument().addDocumentListener(listener); jText.addKeyListener(listener); TextManager.installTextComponent(jText); jCompareColumn = new JComboBox<>(); jCompareColumn.setPrototypeDisplayValue(longestColumn); jCompareColumn.addActionListener(listener); jCompareColumn.setActionCommand(FilterPanelAction.FILTER.name()); jDate = new JDateChooser(false); jDate.addDateChangeListener(listener); jSpacing = new JLabel(); jClone = new JButton(); jClone.setIcon(Images.EDIT_COPY.getIcon()); jClone.addActionListener(listener); jClone.setActionCommand(FilterPanelAction.CLONE.name()); jRemove = new JButton(); jRemove.setIcon(Images.EDIT_DELETE.getIcon()); jRemove.addActionListener(listener); jRemove.setActionCommand(FilterPanelAction.REMOVE.name()); timer = new Timer(500, listener); timer.setActionCommand(FilterPanelAction.FILTER_TIMER.name()); jPanel = new JPanel(); layout = new GroupLayout(jPanel); jPanel.setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(false); layout.setHorizontalGroup( layout.createSequentialGroup() .addComponent(jEnabled, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) .addGap(0) .addComponent(jLogic, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jGroup, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jColumn, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jCompare, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jText, 50, 50, Integer.MAX_VALUE) .addComponent(jCompareColumn, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jDate, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jSpacing, 0, 0, Integer.MAX_VALUE) .addComponent(jClone, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) .addComponent(jRemove, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) ); layout.setVerticalGroup( layout.createParallelGroup() .addComponent(jEnabled, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jLogic, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jGroup, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jColumn, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCompare, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jText, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCompareColumn, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDate, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSpacing, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jClone, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRemove, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); updateNumeric(false); } protected void updateColumns() { EnumTableColumn selectedItem = jColumn.getItemAt(jColumn.getSelectedIndex()); allColumns.clear(); allColumns.add(new AllColumn<>()); allColumns.addAll(tableFormat.getAllColumns()); numericColumns.clear(); for (EnumTableColumn object : tableFormat.getAllColumns()) { if (filterControl.isNumeric(object)) { numericColumns.add(object); } } dateColumns.clear(); for (EnumTableColumn object : tableFormat.getAllColumns()) { if (filterControl.isDate(object)) { dateColumns.add(object); } } jColumn.setActionCommand("comboBoxChanged"); jColumn.setModel(new ListComboBoxModel<>(allColumns)); if (allColumns.contains(selectedItem)) { jColumn.setSelectedItem(selectedItem); jColumn.setActionCommand(FilterPanelAction.FILTER.name()); //After: Do not refilter } else if (!allColumns.isEmpty()) { jColumn.setActionCommand(FilterPanelAction.FILTER.name()); //Before: refilter jColumn.setSelectedIndex(0); } } boolean isAnd() { return ((LogicType) jLogic.getSelectedItem()) == LogicType.AND; } boolean isMoving() { return moving; } Integer getGroup() { return groupModel.getNumber().intValue(); } JPanel getPanel() { return jPanel; } FilterMatcher getMatcher() { int group = getGroup(); boolean enabled = jEnabled.isSelected(); LogicType logic = (LogicType) jLogic.getSelectedItem(); EnumTableColumn column = (EnumTableColumn) jColumn.getSelectedItem(); CompareType compare = (CompareType) jCompare.getSelectedItem(); String text; if (isColumnCompare()) { EnumTableColumn compareColumn = (EnumTableColumn) jCompareColumn.getSelectedItem(); text = compareColumn.name(); } else if (isDateCompare()) { text = getDataString(); } else { text = jText.getText(); } return new FilterMatcher<>(tableFormat, filterControl, group, logic, column, compare, text, enabled); } Filter getFilter() { int group = getGroup(); boolean enabled = jEnabled.isSelected(); LogicType logic = (LogicType) jLogic.getSelectedItem(); EnumTableColumn column = (EnumTableColumn) jColumn.getSelectedItem(); CompareType compare = (CompareType) jCompare.getSelectedItem(); String text; if (isColumnCompare()) { EnumTableColumn compareColumn = (EnumTableColumn) jCompareColumn.getSelectedItem(); text = compareColumn.name(); } else if (isDateCompare()) { text = getDataString(); } else { text = jText.getText(); } return new Filter(group, logic, column, compare, text, enabled); } void setFilter(final Filter filter) { boolean oldValue = loading; loading = true; jEnabled.setSelected(filter.isEnabled()); jLogic.setSelectedItem(filter.getLogic()); groupModel.setValue(filter.getGroup()); updateGroupColor(); jColumn.setSelectedItem(filter.getColumn()); jCompare.setSelectedItem(filter.getCompareType()); if (isColumnCompare()) { try { EnumTableColumn enumColumn = tableFormat.valueOf(filter.getText()); if (enumColumn != null) { jCompareColumn.setSelectedItem(enumColumn); } } catch (IllegalArgumentException ex) { //ignore missing columns... } } else if (isDateCompare()) { setDateString(Formatter.columnStringToDate(filter.getText())); } else { jText.setText(filter.getText()); timer.stop(); } loading = oldValue; } @Override public int compareTo(FilterPanel o) { if (this.isAnd() && o.isAnd()) { return 0; } else if (this.isAnd()) { return 1; } else if (o.isAnd()) { return -1; } else { return this.getGroup().compareTo(o.getGroup()); } } private void setDateString(Date date) { jDate.setDate(date); } private String getDataString() { LocalDate date = jDate.getDate(); Instant instant = date.atStartOfDay().atZone(ZoneId.of("GMT")).toInstant(); //End of day - GMT return Formatter.columnDate(Date.from(instant)); } private void refilter() { if (!loading) { gui.refilter(); } } private boolean isInvalidRegex() { if (!isRegexCompare()) { return false; } String text = jText.getText(); try { Pattern.compile(text, Pattern.CASE_INSENSITIVE); return false; } catch (PatternSyntaxException ex) { return true; } } private boolean isRegexCompare() { CompareType compareType = (CompareType) jCompare.getSelectedItem(); return CompareType.isRegexCompare(compareType); } private boolean isColumnCompare() { CompareType compareType = (CompareType) jCompare.getSelectedItem(); return CompareType.isColumnCompare(compareType); } private boolean isNumericCompare() { CompareType compareType = (CompareType) jCompare.getSelectedItem(); return CompareType.isNumericCompare(compareType); } private boolean isDateCompare() { CompareType compareType = (CompareType) jCompare.getSelectedItem(); return CompareType.isDateCompare(compareType); } private void updateNumeric(final boolean saveIndex) { Object object = jCompare.getSelectedItem(); CompareType[] compareTypes; if (filterControl.isNumeric((EnumTableColumn) jColumn.getSelectedItem())) { compareTypes = CompareType.valuesNumeric(); } else if (filterControl.isDate((EnumTableColumn) jColumn.getSelectedItem())) { compareTypes = CompareType.valuesDate(); } else if (filterControl.isAll((EnumTableColumn) jColumn.getSelectedItem())) { compareTypes = CompareType.valuesAll(); } else { compareTypes = CompareType.valuesString(); } jCompare.setModel(new ListComboBoxModel<>(compareTypes)); for (CompareType compareType : compareTypes) { if (compareType.equals(object) && saveIndex) { jCompare.setSelectedItem(compareType); } } updateCompare(saveIndex); } private void updateCompare(final boolean saveIndex) { if (isColumnCompare()) { //Column jText.setVisible(false); jCompareColumn.setVisible(true); jDate.setVisible(false); jSpacing.setVisible(true); } else if (isDateCompare()) { //Date jText.setVisible(false); jCompareColumn.setVisible(false); jDate.setVisible(true); jSpacing.setVisible(true); } else { //String jText.setVisible(true); jCompareColumn.setVisible(false); jDate.setVisible(false); jSpacing.setVisible(false); } Object object = jCompareColumn.getSelectedItem(); List> compareColumns; if (isNumericCompare()) { compareColumns = new ArrayList<>(numericColumns); } else if (isDateCompare()) { compareColumns = new ArrayList<>(dateColumns); } else { compareColumns = new ArrayList<>(tableFormat.getAllColumns()); } jCompareColumn.setModel(new ListComboBoxModel<>(compareColumns)); for (Object column : compareColumns) { if (column.equals(object) && saveIndex) { jCompareColumn.setSelectedItem(column); } } } private void processFilterAction(final ActionEvent e) { //Get the initial loading state so we can reset it at the end. //We need to do this in the even that we were loading true when we entered we do not want to blindly //set false after one pass. //This should mean that no events triggered hear would cause additional refreshes. boolean oldValue = loading; loading = true; if (jColumn.equals(e.getSource())) { updateNumeric(true); } if (jCompare.equals(e.getSource())) { updateCompare(true); } updateEnabledColor(); timer.stop(); loading = oldValue; refilter(); } void updateGroupSize(int size) { boolean oldValue = loading; loading = true; if (size > 9) { size = 9; } groupModel.setMaximum(size); if (groupModel.getNumber().intValue() > size) { groupModel.setValue(size); } loading = oldValue; } protected void repaint() { updateEnabledColor(); updateGroupColor(); } private void updateEnabledColor() { if (jEnabled.isSelected()) { if (isInvalidRegex()) { ColorSettings.config(jText, ColorEntry.GLOBAL_ENTRY_WARNING); } else { ColorSettings.configReset(jText); } } else { ColorSettings.config(jText, ColorEntry.GLOBAL_ENTRY_INVALID); } } private void updateGroupColor() { Color color = getGroupColor(); Border border = jGroup.getBorder(); JFormattedTextField jTextField = ((JSpinner.DefaultEditor) jGroup.getEditor()).getTextField(); if ("Nimbus".equals(UIManager.getLookAndFeel().getName())) { if (color == Color.GRAY) { jTextField.setUI(null); jTextField.updateUI(); } else { jTextField.setUI(new SynthFormattedTextFieldUI() { @Override protected void paint(javax.swing.plaf.synth.SynthContext context, java.awt.Graphics g) { g.setColor(color); g.fillRect(3, 3, getComponent().getWidth()-3, getComponent().getHeight()-6); super.paint(context, g); }; }); } } else { if (color == Color.GRAY) { jTextField.setOpaque(false); } else { jTextField.setBackground(color); jTextField.setOpaque(true); } if (border instanceof CompoundBorder) { CompoundBorder compoundBorder = (CompoundBorder) border; if (color == Color.GRAY) { jGroup.setBorder(BorderFactory.createCompoundBorder(compoundBorder.getOutsideBorder(), BorderFactory.createLineBorder(jGroup.getBackground(), 2))); } else { jGroup.setBorder(BorderFactory.createCompoundBorder(compoundBorder.getOutsideBorder(), BorderFactory.createLineBorder(color, 2))); } } } } private Color getGroupColor() { switch (getGroup()) { case 0: return Color.GRAY; case 1: return ColorSettings.background(ColorEntry.FILTER_OR_GROUP_1); case 2: return ColorSettings.background(ColorEntry.FILTER_OR_GROUP_2); case 3: return ColorSettings.background(ColorEntry.FILTER_OR_GROUP_3); case 4: return ColorSettings.background(ColorEntry.FILTER_OR_GROUP_4); case 5: return ColorSettings.background(ColorEntry.FILTER_OR_GROUP_5); case 6: return ColorSettings.background(ColorEntry.FILTER_OR_GROUP_6); case 7: return ColorSettings.background(ColorEntry.FILTER_OR_GROUP_7); default: return Color.GRAY; } } private void groupChanged() { refilter(); if (!loading) { if (gui.fade(FilterPanel.this)) { fades.execute(new FadeThread()); } else { updateGroupColor(); gui.updateGroupSize(); gui.update(); } } } private class ListenerClass implements ActionListener, KeyListener, DocumentListener, DateChangeListener, ChangeListener { @Override public void insertUpdate(final DocumentEvent e) { timer.stop(); timer.start(); } @Override public void removeUpdate(final DocumentEvent e) { timer.stop(); timer.start(); } @Override public void changedUpdate(final DocumentEvent e) { timer.stop(); timer.start(); } @Override public void keyTyped(final KeyEvent e) { } @Override public void keyPressed(final KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { refilter(); } } @Override public void keyReleased(final KeyEvent e) { } @Override public void actionPerformed(final ActionEvent e) { if (FilterPanelAction.REMOVE.name().equals(e.getActionCommand())) { gui.remove(FilterPanel.this); gui.addEmpty(); refilter(); } else if (FilterPanelAction.CLONE.name().equals(e.getActionCommand())) { gui.clone(FilterPanel.this); refilter(); jText.requestFocusInWindow(); jCompareColumn.requestFocusInWindow(); jDate.getComponentToggleCalendarButton().requestFocusInWindow(); } else if (FilterPanelAction.FILTER.name().equals(e.getActionCommand())) { processFilterAction(e); } else if (FilterPanelAction.FILTER_TIMER.name().equals(e.getActionCommand())) { if (!Settings.get().isFilterOnEnter()) { processFilterAction(e); } } else if (FilterPanelAction.GROUP_TIMER.name().equals(e.getActionCommand())) { groupTimer.stop(); groupChanged(); } } @Override public void dateChanged(DateChangeEvent e) { refilter(); } @Override public void stateChanged(ChangeEvent e) { if (!loading) { groupTimer.stop(); groupTimer.start(); } } } private class FadeThread implements Runnable, ActionListener { private final List components = new ArrayList<>(); private final Timer moveTimer = new Timer(50, this); private int from; private int to; private int index; public FadeThread() { components.add(new FadeComponent(jEnabled)); components.add(new FadeComponent(jPanel)); } @Override public void run() { if (!gui.fade(FilterPanel.this)) { return; } moving = true; Fade fadeIn = new Fade(components, 100, Color.GRAY); fadeIn.start(true); from = gui.getFromIndex(FilterPanel.this); to = gui.getToIndex(FilterPanel.this); index = from; moveTimer.start(); synchronized (this) { try { wait(); } catch (InterruptedException ex) { //No problem } } Fade fadeOut = new Fade(components, 750); fadeOut.start(true); } @Override public void actionPerformed(ActionEvent e) { if (from < to) { index++; } else if (from > to) { index--; } else { //Should never happen } gui.move(FilterPanel.this, index); if (index == to) { moveTimer.stop(); updateGroupColor(); moving = false; gui.update(); synchronized (this) { notifyAll(); } } } } private static class Fade implements ActionListener { private static final float MS_PER_FRAME = 20; //(100/3); private final int frames; private final Map> map = new HashMap<>(); private final Timer timer; private int frameCount = 0; private Fade(List fadeComponents, int duration) { this(fadeComponents, duration, null); } private Fade(List fadeComponents, int duration, Color to) { this.frames = (int) (duration / MS_PER_FRAME); for (FadeComponent fadeComponent : fadeComponents) { Color from = fadeComponent.getComponent().getBackground(); List colors = new ArrayList<>(); Color toColor = to == null ? fadeComponent.getColor() : to; float redDiff = (from.getRed() - toColor.getRed()) / frames; float blueDiff = (from.getBlue() - toColor.getBlue()) / frames; float greenDiff = (from.getGreen() - toColor.getGreen()) / frames; for (int i = 1; i <= frames; i++) { colors.add(new Color((int) (from.getRed() - (i * redDiff)), (int) (from.getGreen() - (i * greenDiff)), (int) (from.getBlue() - (i * blueDiff)))); } colors.add(toColor); map.put(fadeComponent.getComponent(), colors); } timer = new Timer((int) MS_PER_FRAME, this); } public void start(boolean wait) { timer.start(); if (wait) { synchronized (this) { try { wait(); } catch (InterruptedException ex) { //Done waiting } } } } public void stop() { timer.stop(); for (Map.Entry> entry : map.entrySet()) { entry.getKey().setBackground(entry.getValue().get(entry.getValue().size() - 1)); } synchronized (this) { notifyAll(); } } @Override public void actionPerformed(ActionEvent e) { frameCount++; if (frameCount >= frames) { timer.stop(); for (Map.Entry> entry : map.entrySet()) { entry.getKey().setBackground(entry.getValue().get(entry.getValue().size() - 1)); } synchronized (this) { notifyAll(); } } else { for (Map.Entry> entry : map.entrySet()) { entry.getKey().setBackground(entry.getValue().get(frameCount)); } } } } private static class FadeComponent { private final Component jComponent; private final Color color; public FadeComponent(Component jComponent) { this.jComponent = jComponent; this.color = jComponent.getBackground(); } public Component getComponent() { return jComponent; } public Color getColor() { return color; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/FilterPanelSeparator.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import java.awt.Color; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.LookupOp; import java.awt.image.LookupTable; import java.util.Arrays; import javax.swing.GroupLayout; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.UIManager; import net.nikr.eve.jeveasset.gui.images.Images; public class FilterPanelSeparator { private final JPanel jPanel; private final int group; public FilterPanelSeparator(int group) { this.group = group; jPanel = new JPanel(); GroupLayout layout = new GroupLayout(jPanel); jPanel.setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(false); BufferedImageOp lookup = new LookupOp(new ColorMapper(Color.WHITE, getColor("nimbusBlueGrey", "Separator.foreground")), null); BufferedImage convertedImage = lookup.filter((BufferedImage)Images.MISC_AND.getImage(), null); JLabel jIcon = new JLabel(new ImageIcon(convertedImage)); layout.setHorizontalGroup( layout.createSequentialGroup() .addGap(30) .addComponent(jIcon, 12, 12, 12) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGap(1) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jIcon, 4, 4, 4) ) .addGap(1) ); } public JPanel getPanel() { return jPanel; } @Override public int hashCode() { int hash = 7; hash = 47 * hash + this.group; return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final FilterPanelSeparator other = (FilterPanelSeparator) obj; if (this.group != other.group) { return false; } return true; } private static Color getColor(String ... values) { for (String s : values) { Color color = UIManager.getColor(s); if (color != null) { return color; } } return Color.BLACK; } private static class ColorMapper extends LookupTable { private final int[] from; private final int[] to; public ColorMapper(Color from, Color to) { super(0, 4); this.from = new int[]{ from.getRed(), from.getGreen(), from.getBlue(), from.getAlpha(),}; this.to = new int[]{ to.getRed(), to.getGreen(), to.getBlue(), to.getAlpha(),}; } @Override public int[] lookupPixel(int[] src, int[] dest) { if (dest == null) { dest = new int[src.length]; } int[] newColor = (Arrays.equals(src, from) ? to : src); System.arraycopy(newColor, 0, dest, 0, newColor.length); return dest; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/FilterSave.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.matchers.TextMatcherEditor; import ca.odell.glazedlists.swing.AutoCompleteSupport; import java.awt.AWTException; import java.awt.Robot; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.EventModels.StringFilterator; import net.nikr.eve.jeveasset.i18n.GuiShared; public class FilterSave extends JDialogCentered { private enum FilterSaveAction { SAVE, CANCEL } private final EventList filters; private final List defaultFilters = new ArrayList<>(); private final JComboBox jName; private final JButton jSave; private String returnString; public FilterSave(final Window window) { super(null, GuiShared.get().saveFilter(), window); ListenerClass listener = new ListenerClass(); JLabel jText = new JLabel(GuiShared.get().enterFilterName()); jName = new JComboBox<>(); filters = EventListManager.create(); AutoCompleteSupport nameAutoComplete = AutoCompleteSupport.install(jName, EventModels.createSwingThreadProxyList(filters), new StringFilterator()); nameAutoComplete.setFilterMode(TextMatcherEditor.CONTAINS); jSave = new JButton(GuiShared.get().save()); jSave.setActionCommand(FilterSaveAction.SAVE.name()); jSave.addActionListener(listener); JButton jCancel = new JButton(GuiShared.get().cancel()); jCancel.setActionCommand(FilterSaveAction.CANCEL.name()); jCancel.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jText) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jName, 220, 220, 220) .addGroup(layout.createSequentialGroup() .addComponent(jSave, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jText, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jName, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup() .addComponent(jSave, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } String show(final List filters, final List defaultFilters) { returnString = null; Collections.sort(filters, StringComparators.CASE_INSENSITIVE); try { this.filters.getReadWriteLock().writeLock().lock(); this.filters.clear(); this.filters.addAll(filters); } finally { this.filters.getReadWriteLock().writeLock().unlock(); } this.defaultFilters.clear(); this.defaultFilters.addAll(defaultFilters); this.setVisible(true); return returnString; } private boolean validate() { String name = (String) jName.getSelectedItem(); if (name == null) { JOptionPane.showMessageDialog(this.getDialog(), GuiShared.get().noFilterName(), GuiShared.get().saveFilter(), JOptionPane.PLAIN_MESSAGE); return false; } if (name.isEmpty()) { JOptionPane.showMessageDialog(this.getDialog(), GuiShared.get().noFilterName(), GuiShared.get().saveFilter(), JOptionPane.PLAIN_MESSAGE); return false; } for (String filter : defaultFilters) { if (filter.toLowerCase().equals(name.toLowerCase())) { //Case insetitive contains JOptionPane.showMessageDialog(this.getDialog(), GuiShared.get().overwriteDefaultFilter(), GuiShared.get().saveFilter(), JOptionPane.PLAIN_MESSAGE); return false; } } try { filters.getReadWriteLock().readLock().lock(); if (filters.contains(name)) { int nReturn = JOptionPane.showConfirmDialog(this.getDialog(), GuiShared.get().overwrite(), GuiShared.get().overwriteFilter(), JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE); if (nReturn == JOptionPane.NO_OPTION) { return false; } } } finally { filters.getReadWriteLock().readLock().unlock(); } return true; } @Override protected JComponent getDefaultFocus() { return jName; } @Override protected JButton getDefaultButton() { return jSave; } @Override protected void windowShown() { } @Override protected void save() { if (validate()) { returnString = (String) jName.getSelectedItem(); setVisible(false); } //XXX - Workaround for strange bug: // 1. Tricker validation by pressing enter in the jName JComboBox // 2. Doing validate JOptionPane is shown and lose focus (to another program) // 3. JOptionPane is hidden (by mouse click) // 4. jName is not responding (string is locked) try { Robot robot = new Robot(); robot.keyRelease(KeyEvent.VK_ENTER); } catch (AWTException e) { } } @Override public void setVisible(final boolean b) { if (b) { jName.getModel().setSelectedItem(""); } super.setVisible(b); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (FilterSaveAction.SAVE.name().equals(e.getActionCommand())) { save(); } if (FilterSaveAction.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/JFilterManagerDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.swing.JFrame; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.components.JManagerDialog; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JFilterManagerDialog extends JManagerDialog { private final Map> filters; private final Map> defaultFilters; private final List> columns; private final FilterGui gui; private final JTextDialog jTextDialog; private final FilterExport filterExport; JFilterManagerDialog(final JFrame jFrame, final String toolName, final FilterGui gui, List> columns, final Map> filters, final Map> defaultFilters) { super(null, jFrame, GuiShared.get().filterManager(), true, false, false, true, true); this.gui = gui; this.columns = columns; this.filters = filters; this.defaultFilters = defaultFilters; jTextDialog = new JTextDialog(jFrame); filterExport = new FilterExport(toolName); } @Override protected void load(final String name) { List filter = filters.get(name); gui.setFilters(filter); this.setVisible(false); } @Override protected void edit(String name) { //Edit is not supported } @Override protected void merge(final String name, final List list) { //Get filters to merge Settings.lock("Filter (Merge)"); //Lock for Filter (Merge) List filter = new ArrayList<>(); for (String mergeName : list) { for (Filter currentFilter : filters.get(mergeName)) { if (!filter.contains(currentFilter)) { filter.add(currentFilter); } } } filters.put(name, filter); updateFilters(); Settings.unlock("Filter (Merge)"); //Unlock for Filter (Merge) gui.saveSettings("Filter (Merge)"); //Save Filter (Merge) } @Override protected void copy(String fromName, String toName) { //Copy is not supported } @Override protected void rename(final String name, final String oldName) { List filter = filters.get(oldName); Settings.lock("Filter (Rename)"); //Lock for Filter (Rename) filters.remove(oldName); //Remove renamed filter (with old name) filters.remove(name); //Remove overwritten filter filters.put(name, filter); //Add renamed filter (with new name) updateFilters(); Settings.unlock("Filter (Rename)"); //Unlock for Filter (Rename) gui.saveSettings("Filter (Rename)"); //Save Filter (Rename) } @Override protected void delete(final List list) { Settings.lock("Filter (Delete)"); //Lock for Filter (Delete) for (String filterName : list) { filters.remove(filterName); } updateFilters(); Settings.unlock("Filter (Delete)"); //Unlock for Filter (Delete) gui.saveSettings("Filter (Delete)"); //Save Filter (Delete) } @Override protected void export(List list) { StringBuilder builder = new StringBuilder(); for (String filterName : list) { filterExport.exportFilter(builder, filterName, filters.get(filterName)); } jTextDialog.exportText(builder.toString()); } @Override protected void importData() { importData(""); } private void importData(String oldText) { String importText = jTextDialog.importText(oldText, filterExport.createExample(columns)); if (importText == null) { return; //Cancel } Map> importedFilters = filterExport.importFilter(importText); if (importedFilters.isEmpty()) { int value = JOptionPane.showConfirmDialog(getDialog(), GuiShared.get().managerImportFailMsg(), GuiShared.get().managerImportFailTitle(), JOptionPane.OK_CANCEL_OPTION); if (value == JOptionPane.OK_OPTION) { //Not cancelled importData(importText); } return; } boolean filtersSaved = false; for (Map.Entry> entry : importedFilters.entrySet()) { filtersSaved = saveFilter(entry.getKey(), entry.getValue()) || filtersSaved; } if (filtersSaved) { updateFilters(); gui.saveSettings("Filter (Import)"); //Save Filter (Import); } } private boolean saveFilter(String filterName, List filterList) { if (filterList.isEmpty() || filterName == null || filterName.isEmpty()) { return false; } List filter = filters.get(filterName); if (filter != null) { //Filter already exist filterName = gui.getFilterName(); //get new name } if (filterName != null && !filterName.isEmpty()) { Settings.lock("Filter (Import)"); //Lock for Filter (Merge) filters.put(filterName, filterList); Settings.unlock("Filter (Import)"); //Lock for Filter (Merge) return true; } return false; } @Override protected boolean validateName(final String name, final String oldName, final String title) { for (String filter : defaultFilters.keySet()) { if (filter.equalsIgnoreCase(name)) { JOptionPane.showMessageDialog(this.getDialog(), GuiShared.get().overwriteDefaultFilter(), title, JOptionPane.PLAIN_MESSAGE); return false; } } return super.validateName(name, oldName, title); } @Override protected String textDeleteMultipleMsg(int size) { return GuiShared.get().deleteFilters(size); } @Override protected String textDelete() { return GuiShared.get().deleteFilter(); } @Override protected String textEnterName() { return GuiShared.get().enterFilterName(); } @Override protected String textMerge() { return GuiShared.get().mergeFilters(); } @Override protected String textRename() { return GuiShared.get().renameFilter(); } @Override protected String textOverwrite() { return GuiShared.get().overwriteFilter(); } public final void updateFilters() { update(filters.keySet()); gui.updateFilters(); } @Override public void setVisible(final boolean b) { if (b) { updateFilters(); } super.setVisible(b); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/SimpleFilterControl.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import java.util.HashMap; import java.util.List; import java.util.Map; public interface SimpleFilterControl { public void saveSettings(final String msg); public default Map> getAllFilters() { return new HashMap<>(); } public default boolean isFiltersEmpty() { return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/filter/SimpleTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import java.util.List; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; public interface SimpleTableFormat { public Object getColumnValue(E item, String column); public List> getAllColumns(); public List> getShownColumns(); public EnumTableColumn valueOf(String column) throws IllegalArgumentException; public void addColumn(EnumTableColumn column); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JFormulaDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import com.udojava.evalex.Expression; import com.udojava.evalex.LazyFunction; import com.udojava.evalex.LazyOperator; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.math.BigDecimal; import java.math.MathContext; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JTextField; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.text.BadLocationException; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.NumberValue; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JFormulaDialog & EnumTableColumn, Q> extends JDialogCentered { public static MathContext FORMULA_PRECISION = MathContext.DECIMAL64; //64bit == Double size private enum FormulaDialogAction { OK, CANCEL } private final JTextField jName; private final JTextField jFormula; private final JButton jOK; private final List columnNames = new ArrayList<>(); private final List columnStaticNames = new ArrayList<>(); private final ColumnManager columnManager; private Formula returnValue = null; public JFormulaDialog(Program program, ColumnManager columnManager) { super(program, GuiShared.get().formulaTitle(), Images.MISC_FORMULA.getImage()); this.columnManager = columnManager; ListenerClass listener = new ListenerClass(); JLabel jNameLabel = new JLabel(GuiShared.get().formulaName()); jName = new JTextField(); jName.addCaretListener(listener); JLabel jFormulaLabel = new JLabel(GuiShared.get().formulaString()); jFormula = new JTextField(); jFormula.addCaretListener(listener); JDropDownButton jColumns = new JDropDownButton(GuiShared.get().formulaColumns()); for (T t : columnManager.getEnumConstants()) { if (isAssignableFrom(t.getType())) { String column = getSoftName(t); JMenuItem jMenuItem = new JMenuItem(t.getColumnName()); if (isNumber(t.getType())) { jMenuItem.setIcon(Images.MISC_NUMBER.getIcon()); } else if (isDate(t.getType())) { jMenuItem.setIcon(Images.MISC_DATE.getIcon()); jMenuItem.setToolTipText(GuiShared.get().formulaDateToolTip()); } jMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { jFormula.getDocument().insertString(jFormula.getCaretPosition(), column, null); jFormula.requestFocusInWindow(); } catch (BadLocationException ex) { //No problem } } }); jColumns.add(jMenuItem); } } JDropDownButton jFunctions = new JDropDownButton(GuiShared.get().formulaFunctions()); ExpressionValues expression = new ExpressionValues(); for (LazyFunction function : expression.getFunctions()) { StringBuilder builder = new StringBuilder(); for (int i = 1; i < function.getNumParams(); i++) { builder.append(","); } builder.append(")"); String after = builder.toString(); String before = function.getName().toLowerCase() + "("; JMenuItem jMenuItem = new JMenuItem(before + after); jMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { int start = jFormula.getSelectionStart(); int end = jFormula.getSelectionEnd(); jFormula.getDocument().insertString(end, after, null); jFormula.getDocument().insertString(start, before, null); jFormula.setCaretPosition(start + before.length()); jFormula.requestFocusInWindow(); } catch (BadLocationException ex) { //No problem } } }); jFunctions.add(jMenuItem); } JDropDownButton jOperators = new JDropDownButton(GuiShared.get().formulaOperations()); for (LazyOperator operator : expression.getOperators()) { JMenuItem jMenuItem = new JMenuItem(operator.getOper()); jMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { jFormula.getDocument().insertString(jFormula.getCaretPosition(), operator.getOper(), null); jFormula.requestFocusInWindow(); } catch (BadLocationException ex) { //No problem } } }); jOperators.add(jMenuItem); } //Static columns - does not change for (T t : columnManager.getEnumConstants()) { columnStaticNames.add(toColumnName(t.getColumnName())); } //System names (reserved for jump columns) - does not change for (MyLocation location : StaticData.get().getLocations()) { if (location.isSystem()) { columnStaticNames.add(toColumnName(location.getSystem())); } } jOK = new JButton(GuiShared.get().ok()); jOK.setActionCommand(FormulaDialogAction.OK.name()); jOK.addActionListener(listener); JButton jCancel = new JButton(GuiShared.get().cancel()); jCancel.setActionCommand(FormulaDialogAction.CANCEL.name()); jCancel.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jNameLabel) .addComponent(jFormulaLabel) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jName) .addGroup(layout.createSequentialGroup() .addComponent(jColumns, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jFunctions, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jOperators, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) .addComponent(jFormula) .addGroup(layout.createSequentialGroup() .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jNameLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jName, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jColumns, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFunctions, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOperators, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jFormulaLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFormula, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } @Override protected JComponent getDefaultFocus() { return jName; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { validate(); } @Override protected void save() { returnValue = new Formula(jName.getText(), getExpressionString(), null); setVisible(false); } public Formula edit(Formula formula) { reset(formula.getColumnName(), formula.getOriginalExpression()); setVisible(true); return returnValue; } public Formula add() { reset("", ""); setVisible(true); return returnValue; } private void reset(String name, String expression) { returnValue = null; columnNames.clear(); for (Formula f : columnManager.getFormulas()) { columnNames.add(toColumnName(f.getColumnName())); } columnNames.addAll(columnStaticNames); columnNames.remove(toColumnName(name)); //Remove current name (that is still vaild) jName.setText(name); jFormula.setText(fromExpressionString(expression)); validate(); } public static String getHardName(EnumTableColumn t) { return t.name().replace("_", ""); } private static String getSoftName(EnumTableColumn t) { return "[" + t.getColumnName() + "]"; } private String toColumnName(String text) { return text.toLowerCase(); } private String getExpressionString() { return toExpressionString(jFormula.getText()); } private String toExpressionString(String text) { for (T t : columnManager.getEnumConstants()) { if (isAssignableFrom(t.getType())) { text = text.replace(getSoftName(t), getHardName(t)); } } return text; } private String fromExpressionString(String text) { for (T t : columnManager.getEnumConstants()) { if (isAssignableFrom(t.getType())) { text = replaceAll(t, text); } } return text; } public static String replaceAll(EnumTableColumn enumColumn, String text) { return text.replaceAll("\\b" + getHardName(enumColumn) + "\\b", getSoftName(enumColumn).replace("$", "\\$")); //$ is reserved for } private Expression getExpression() { return new Expression(getExpressionString(), FORMULA_PRECISION); } private boolean isFomulaValid() { Expression expression = getExpression(); Set hardNames = new HashSet<>(); for (T t : columnManager.getEnumConstants()) { if (isAssignableFrom(t.getType())) { String hardName = getHardName(t); expression.setVariable(hardName, new BigDecimal(2.0)); hardNames.add(hardName); } } return safeEval(hardNames, expression); } private boolean isAssignableFrom(Class c) { return Number.class.isAssignableFrom(c) || NumberValue.class.isAssignableFrom(c) || Date.class.isAssignableFrom(c); } private boolean isNumber(Class c) { return Number.class.isAssignableFrom(c) || NumberValue.class.isAssignableFrom(c); } private boolean isDate(Class c) { return Date.class.isAssignableFrom(c); } public static boolean safeEval(Set hardNames, Expression expression) { try { if (!hardNames.containsAll(expression.getUsedVariables())) { return false; //Invalid variable } expression.eval(); return true; } catch (RuntimeException ex) { return false; } } private boolean isNameValid() { String name = jName.getText(); return !name.isEmpty() && !columnNames.contains(toColumnName(name)); } private void validate() { boolean nameValid = isNameValid(); boolean fomulaValid = isFomulaValid(); if (nameValid) { ColorSettings.configReset(jName); } else { ColorSettings.config(jName, ColorEntry.GLOBAL_ENTRY_INVALID); } if (fomulaValid) { ColorSettings.configReset(jFormula); } else { ColorSettings.config(jFormula, ColorEntry.GLOBAL_ENTRY_INVALID); } jOK.setEnabled(nameValid && fomulaValid); } private class ListenerClass implements ActionListener, CaretListener { @Override public void actionPerformed(final ActionEvent e) { if (FormulaDialogAction.OK.name().equals(e.getActionCommand())) { save(); } else if (FormulaDialogAction.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); } } @Override public void caretUpdate(CaretEvent e) { validate(); } } private static class ExpressionValues extends Expression { public ExpressionValues() { super("", FORMULA_PRECISION); } public Collection getOperators() { return operators.values(); } public Collection getFunctions() { return functions.values(); } } public static class Formula implements Comparable { private final String columnName; private final Expression expression; private final Map values = new HashMap<>(); private final Collection usedVariables; private final Collection variableColumns = new ArrayList<>(); private final boolean isBoolean; private Integer index; public Formula(String columnName, String expressionString, Integer index) { this.expression = new Expression(expressionString, FORMULA_PRECISION); this.columnName = columnName; this.index = index; this.usedVariables = expression.getUsedVariables(); this.isBoolean = expression.isBoolean(); } public String getColumnName() { return columnName; } public String getOriginalExpression() { return expression.getOriginalExpression(); } public Expression getExpression() { return expression; } public boolean isBoolean() { return isBoolean; } public Integer getIndex() { return index; } public Map getValues() { return values; } public Collection getUsedVariables() { return usedVariables; } public Collection getVariableColumns() { return variableColumns; } public void setIndex(Integer index) { this.index = index; } @Override public int hashCode() { int hash = 7; hash = 47 * hash + Objects.hashCode(this.columnName); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Formula other = (Formula) obj; if (!Objects.equals(this.columnName, other.columnName)) { return false; } return true; } @Override public int compareTo(Formula other) { return this.columnName.compareTo(other.columnName); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuAssetFilter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import java.util.Set; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.CompareType; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.LogicType; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.JAutoMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetTableFormat; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewGroup; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewLocation; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab.OverviewTableMenu; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.i18n.TabsOverview; public class JMenuAssetFilter extends JAutoMenu { private enum MenuAssetFilterAction { STATION_FILTER, PLANET_FILTER, SYSTEM_FILTER, REGION_FILTER, CONSTELLATION_FILTER, OVERVIEW_GROUP_FILTER, ITEM_TYPE_FILTER } private final JMenuItem jTypeID; private final JMenuItem jPlanet; private final JMenuItem jStation; private final JMenuItem jSystem; private final JMenuItem jConstellation; private final JMenuItem jRegion; private final JMenuItem jLocations; public JMenuAssetFilter(final Program program) { super(GuiShared.get().addFilter(), program); ListenerClass listener = new ListenerClass(); this.setIcon(Images.TOOL_ASSETS.getIcon()); jTypeID = new JMenuItem(GuiShared.get().item()); jTypeID.setIcon(Images.EDIT_ADD.getIcon()); jTypeID.setActionCommand(MenuAssetFilterAction.ITEM_TYPE_FILTER.name()); jTypeID.addActionListener(listener); add(jTypeID); addSeparator(); jStation = new JMenuItem(GuiShared.get().station()); jStation.setIcon(Images.LOC_STATION.getIcon()); jStation.setActionCommand(MenuAssetFilterAction.STATION_FILTER.name()); jStation.addActionListener(listener); add(jStation); jPlanet = new JMenuItem(GuiShared.get().planet()); jPlanet.setIcon(Images.LOC_PLANET.getIcon()); jPlanet.setActionCommand(MenuAssetFilterAction.PLANET_FILTER.name()); jPlanet.addActionListener(listener); add(jPlanet); jSystem = new JMenuItem(GuiShared.get().system()); jSystem.setIcon(Images.LOC_SYSTEM.getIcon()); jSystem.setActionCommand(MenuAssetFilterAction.SYSTEM_FILTER.name()); jSystem.addActionListener(listener); add(jSystem); jConstellation = new JMenuItem(GuiShared.get().constellation()); jConstellation.setIcon(Images.LOC_CONSTELLATION.getIcon()); jConstellation.setActionCommand(MenuAssetFilterAction.CONSTELLATION_FILTER.name()); jConstellation.addActionListener(listener); add(jConstellation); jRegion = new JMenuItem(GuiShared.get().region()); jRegion.setIcon(Images.LOC_REGION.getIcon()); jRegion.setActionCommand(MenuAssetFilterAction.REGION_FILTER.name()); jRegion.addActionListener(listener); add(jRegion); jLocations = new JMenuItem(TabsOverview.get().locations()); jLocations.setIcon(Images.LOC_LOCATIONS.getIcon()); jLocations.setActionCommand(MenuAssetFilterAction.OVERVIEW_GROUP_FILTER.name()); jLocations.addActionListener(listener); } @Override public void updateMenuData() { jTypeID.setEnabled(!menuData.getTypeIDs().isEmpty()); jStation.setEnabled(!menuData.getStationAndCitadelNames().isEmpty()); jPlanet.setEnabled(!menuData.getPlanetNames().isEmpty()); jSystem.setEnabled(!menuData.getSystemNames().isEmpty()); jConstellation.setEnabled(!menuData.getConstellationNames().isEmpty()); jRegion.setEnabled(!menuData.getRegionNames().isEmpty()); } public void setTool(Object object) { if (object instanceof OverviewTableMenu) { OverviewTab overviewTab = ((OverviewTableMenu)object).getOverviewTab(); jLocations.setEnabled(overviewTab.isGroupAndNotEmpty()); add(jLocations); } else { remove(jLocations); } } public static & EnumTableColumn, Q> List getFilters(Set names, T column, CompareType compareType) { List filters = new ArrayList<>(); boolean and = names.size() < 2; for (String name : names) { filters.add(new Filter(and ? LogicType.AND : LogicType.OR, column, compareType, name)); } return filters; } private void addFilters(Set names, AssetTableFormat column, CompareType compareType) { List filters = getFilters(names, column, compareType); program.getAssetsTab().addFilters(filters); program.getMainWindow().addTab(program.getAssetsTab()); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (MenuAssetFilterAction.STATION_FILTER.name().equals(e.getActionCommand())) { addFilters(menuData.getStationAndCitadelNames(), AssetTableFormat.LOCATION, CompareType.EQUALS); } else if (MenuAssetFilterAction.PLANET_FILTER.name().equals(e.getActionCommand())) { addFilters(menuData.getPlanetNames(), AssetTableFormat.LOCATION, CompareType.EQUALS); } else if (MenuAssetFilterAction.SYSTEM_FILTER.name().equals(e.getActionCommand())) { addFilters(menuData.getSystemNames(), AssetTableFormat.SYSTEM, CompareType.EQUALS); } else if (MenuAssetFilterAction.CONSTELLATION_FILTER.name().equals(e.getActionCommand())) { addFilters(menuData.getConstellationNames(), AssetTableFormat.CONSTELLATION, CompareType.EQUALS); } else if (MenuAssetFilterAction.REGION_FILTER.name().equals(e.getActionCommand())) { addFilters(menuData.getRegionNames(), AssetTableFormat.REGION, CompareType.EQUALS); } else if (MenuAssetFilterAction.OVERVIEW_GROUP_FILTER.name().equals(e.getActionCommand())) { OverviewGroup overviewGroup = program.getOverviewTab(true).getSelectGroup(); if (overviewGroup == null) { return; } List filters = new ArrayList<>(); for (OverviewLocation location : overviewGroup.getLocations()) { if (location.isStation()) { filters.add(new Filter(LogicType.OR, AssetTableFormat.LOCATION, CompareType.EQUALS, location.getName())); } if (location.isPlanet()) { filters.add(new Filter(LogicType.OR, AssetTableFormat.LOCATION, CompareType.EQUALS, location.getName())); } if (location.isSystem()) { filters.add(new Filter(LogicType.OR, AssetTableFormat.SYSTEM, CompareType.EQUALS, location.getName())); } if (location.isConstellation()) { filters.add(new Filter(LogicType.OR, AssetTableFormat.CONSTELLATION, CompareType.EQUALS, location.getName())); } if (location.isRegion()) { filters.add(new Filter(LogicType.OR, AssetTableFormat.REGION, CompareType.EQUALS, location.getName())); } } program.getAssetsTab().addFilters(filters); program.getMainWindow().addTab(program.getAssetsTab()); } else if (MenuAssetFilterAction.ITEM_TYPE_FILTER.name().equals(e.getActionCommand())) { addFilters(menuData.getTypeNames(), AssetTableFormat.NAME, CompareType.CONTAINS); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuColumns.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Map; import javax.swing.ButtonGroup; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JRadioButtonMenuItem; import javax.swing.table.AbstractTableModel; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JAutoCompleteDialog; import net.nikr.eve.jeveasset.gui.shared.table.JEditColumnsDialog; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.ResizeMode; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.View; import net.nikr.eve.jeveasset.gui.shared.table.JViewManagerDialog; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JMenuColumns & EnumTableColumn, Q> extends JMenu { private JEditColumnsDialog jEditColumnsDialog; private JAutoCompleteDialog jViewSaveDialog; private JViewManagerDialog jViewManagerDialog; public JMenuColumns(final Program program, EnumTableFormatAdaptor tableFormatAdaptor, final AbstractTableModel tableModel, final JAutoColumnTable jTable, final String name) { this(program, tableFormatAdaptor, tableModel, jTable, name, true); } public JMenuColumns(final Program program, EnumTableFormatAdaptor tableFormatAdaptor, final AbstractTableModel tableModel, final JAutoColumnTable jTable, final String name, final boolean editable) { super(GuiShared.get().tableSettings()); JMenuItem jMenuItem; setIcon(Images.TABLE_COLUMN_SHOW.getIcon()); if (editable) { if (jEditColumnsDialog == null) { //Create dialog (only once) jEditColumnsDialog = new JEditColumnsDialog<>(program, tableFormatAdaptor); } if (jViewSaveDialog == null) { //Create dialog (only once) jViewSaveDialog = new JAutoCompleteDialog<>(program, GuiShared.get().saveView(), Images.FILTER_SAVE.getImage(), GuiShared.get().saveViewMsg(), false, JAutoCompleteDialog.VIEW_OPTIONS); } if (jViewManagerDialog == null) { //Create dialog (only once) jViewManagerDialog = new JViewManagerDialog(program, tableFormatAdaptor, tableModel, jTable); } jMenuItem = new JMenuItem(GuiShared.get().tableColumns(), Images.DIALOG_SETTINGS.getIcon()); jMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { jEditColumnsDialog.setVisible(true); tableModel.fireTableStructureChanged(); jTable.autoResizeColumns(); } }); add(jMenuItem); addSeparator(); jMenuItem = new JMenuItem(GuiShared.get().saveView(), Images.FILTER_SAVE.getIcon()); jMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { //Get views... Map views = Settings.get().getTableViews(name); jViewSaveDialog.updateData(new ArrayList<>(views.values())); //Update views View view = jViewSaveDialog.show(); if (view != null) { //Validate view.setColumns(tableFormatAdaptor.getColumns()); //Set data Settings.lock("View (New)"); //Lock for View (New) views.remove(view.getName()); //Remove old views.put(view.getName(), view); //Add new Settings.unlock("View (New)"); //Unlock for View (New) program.saveSettings("View (New)"); //Save View (New) } } }); add(jMenuItem); JMenu jLoad = new JMenu(GuiShared.get().loadView()); jLoad.setIcon(Images.FILTER_LOAD.getIcon()); add(jLoad); JMenuItem jManage = new JMenuItem(GuiShared.get().editViews(), Images.DIALOG_SETTINGS.getIcon()); jManage.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { Map views = Settings.get().getTableViews(name); jViewManagerDialog.updateData(views); jViewManagerDialog.setVisible(true); } }); if (!Settings.get().getTableViews(name).isEmpty()) { jLoad.setEnabled(true); jLoad.add(jManage); jLoad.addSeparator(); for (final View view : Settings.get().getTableViews(name).values()) { jMenuItem = new JMenuItem(view.getName(), Images.FILTER_LOAD.getIcon()); jMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { jViewManagerDialog.loadView(view); } }); jLoad.add(jMenuItem); } } else { jLoad.setEnabled(false); } addSeparator(); } jMenuItem = new JMenuItem(GuiShared.get().tableColumnsReset(), Images.TABLE_COLUMN_SHOW.getIcon()); jMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { tableFormatAdaptor.reset(); tableModel.fireTableStructureChanged(); jTable.autoResizeColumns(); program.saveSettings("Columns (Reset)"); //Save Resize Mode } }); add(jMenuItem); addSeparator(); ButtonGroup buttonGroup = new ButtonGroup(); JRadioButtonMenuItem jRadioButton; for (final ResizeMode mode : ResizeMode.values()) { jRadioButton = new JRadioButtonMenuItem(mode.toString(), Images.TABLE_COLUMN_RESIZE.getIcon()); jRadioButton.setSelected(tableFormatAdaptor.getResizeMode() == mode); jRadioButton.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { tableFormatAdaptor.setResizeMode(mode); jTable.saveColumnsWidth(); jTable.autoResizeColumns(); program.updateTableMenu(); program.saveSettings("Resize Mode"); //Save Resize Mode } }); buttonGroup.add(jRadioButton); add(jRadioButton); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuCopy.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import javax.swing.JMenuItem; import javax.swing.JTable; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.CopyHandler; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JMenuCopy extends JMenuItem { public JMenuCopy(final JTable jTable) { super(GuiShared.get().copy()); this.setIcon(Images.EDIT_COPY.getIcon()); CopyHandler.installCopyAction(this, jTable); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuCopyPlus.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.DecimalFormat; import java.util.Map; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.JAutoMenu; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JMenuCopyPlus extends JAutoMenu { private final DecimalFormat number = new DecimalFormat("0"); private final JTextDialog jTextDialog; private final JMenuItem jEveMultiBuy; public JMenuCopyPlus(Program program) { super(GuiShared.get().copyPlus(), program); setIcon(Images.EDIT_COPY.getIcon()); jTextDialog = new JTextDialog(program.getMainWindow().getFrame()); jEveMultiBuy = new JMenuItem(GuiShared.get().copyEveMultiBuy()); jEveMultiBuy.setIcon(Images.MISC_EVE.getIcon()); jEveMultiBuy.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { StringBuilder builder = new StringBuilder(); for (Map.Entry entry : menuData.getItemCounts().entrySet()) { builder.append(entry.getKey().getTypeName()); builder.append(" "); builder.append(number.format(entry.getValue())); builder.append("\r\n"); } jTextDialog.exportText(builder.toString()); } }); add(jEveMultiBuy); } @Override protected void updateMenuData() { jEveMultiBuy.setEnabled(!menuData.getItemCounts().isEmpty()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuFormula.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.JMenu; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.MenuScroller; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog.Formula; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.JAutoMenu; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JMenuFormula & EnumTableColumn, Q> extends JAutoMenu { private enum MenuFormulaAction { ADD } private final JMenuItem jAdd; private final JFormulaDialog jFormulaDialog; private final ColumnManager columnManager; public JMenuFormula(Program program, ColumnManager columnManager) { super(GuiShared.get().formulaMenu(), program); this.columnManager = columnManager; setIcon(Images.MISC_FORMULA.getIcon()); MenuScroller menuScroller = new MenuScroller(this); menuScroller.keepVisible(2); menuScroller.setTopFixedCount(2); menuScroller.setInterval(125); jFormulaDialog = new JFormulaDialog<>(program, columnManager); ListenerClass listener = new ListenerClass(); jAdd = new JMenuItem(GuiShared.get().add()); jAdd.setIcon(Images.EDIT_ADD.getIcon()); jAdd.setActionCommand(MenuFormulaAction.ADD.name()); jAdd.addActionListener(listener); } @Override protected void updateMenuData() { removeAll(); add(jAdd); List columns = new ArrayList<>(columnManager.getFormulas()); if (!columns.isEmpty()) { addSeparator(); Collections.sort(columns); } for (Formula formula : columns) { JMenuItem menuItem; JMenu jMenu = new JMenu(formula.getColumnName()); add(jMenu); menuItem = new JMenuItem(GuiShared.get().delete(), Images.EDIT_DELETE.getIcon()); menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { columnManager.removeColumn(formula); } }); jMenu.add(menuItem); menuItem = new JMenuItem(GuiShared.get().edit(), Images.EDIT_EDIT.getIcon()); menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Formula edited = jFormulaDialog.edit(formula); if (edited == null) { return; //Cancel } edited.setIndex(formula.getIndex()); //Stay at the same index... columnManager.editColumn(formula, edited); } }); jMenu.add(menuItem); } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (MenuFormulaAction.ADD.name().equals(e.getActionCommand())) { Formula formula = jFormulaDialog.add(); if (formula == null) { return; //Cancel } columnManager.addColumn(formula); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuInfo.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import ca.odell.glazedlists.SeparatorList; import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.SwingConstants; import javax.swing.Timer; import javax.swing.border.Border; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.CopyHandler; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.InfoItem; import net.nikr.eve.jeveasset.gui.tabs.loadout.Loadout; import net.nikr.eve.jeveasset.gui.tabs.materials.Material; import net.nikr.eve.jeveasset.gui.tabs.materials.Material.MaterialType; import net.nikr.eve.jeveasset.gui.tabs.slots.Slots; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileTotal; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeAsset; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.i18n.TabsLoadout; public class JMenuInfo { private static Border border = null; public static final int COPY_DELAY = 500; private JMenuInfo() { } public static void treeAsset(final JPopupMenu jPopupMenu, final List list) { Set items = new HashSet<>(); for (TreeAsset asset : list) { items.addAll(asset.getItems()); if (asset.isItem()) { items.add(asset); } } infoItem(jPopupMenu, items); } public static void infoItem(final JPopupMenu jPopupMenu, final Collection list) { List values = createDefault(jPopupMenu); double averageValue = 0; double totalValue = 0; long totalCount = 0; double totalVolume = 0; double totalReprocessed = 0; for (InfoItem infoItem : list) { totalValue = totalValue + infoItem.getValue(); totalCount = totalCount + infoItem.getCount(); totalVolume = totalVolume + infoItem.getVolumeTotal(); totalReprocessed = totalReprocessed + infoItem.getValueReprocessed(); } if (totalCount > 0 && totalValue > 0) { averageValue = totalValue / totalCount; } createMenuItem(values, jPopupMenu, totalValue, AutoNumberFormat.ISK, GuiShared.get().selectionValue(), GuiShared.get().selectionShortValue(), Images.TOOL_VALUES.getIcon()); createMenuItem(values, jPopupMenu, totalReprocessed, AutoNumberFormat.ISK, GuiShared.get().selectionValueReprocessed(), GuiShared.get().selectionShortReprocessedValue(), Images.SETTINGS_REPROCESSING.getIcon()); createMenuItem(values, jPopupMenu, averageValue, AutoNumberFormat.ISK, GuiShared.get().selectionAverage(), GuiShared.get().selectionShortAverage(), Images.ASSETS_AVERAGE.getIcon()); createMenuItem(values, jPopupMenu, totalVolume, AutoNumberFormat.DOUBLE, GuiShared.get().selectionVolume(), GuiShared.get().selectionShortVolume(), Images.ASSETS_VOLUME.getIcon()); createMenuItem(values, jPopupMenu, totalCount, AutoNumberFormat.ITEMS, GuiShared.get().selectionCount(), GuiShared.get().selectionShortCount(), Images.EDIT_ADD.getIcon()); } public static void contracts(final Program program, final JPopupMenu jPopupMenu, final List list) { List values = createDefault(jPopupMenu); double sellingPrice = 0; double sellingAssets = 0; double buying = 0; double sold = 0; double bought = 0; double collateralIssuer = 0; double collateralAcceptor = 0; Set contracts = new HashSet<>(); for (Object object : list) { if (object instanceof SeparatorList.Separator) { continue; } if (object == null) { continue; } MyContractItem contractItem = (MyContractItem) object; contracts.add(contractItem.getContract()); MyContract contract = contractItem.getContract(); if (contract.isIgnoreContract()) { continue; } boolean isIssuer = contract.isForCorp() ? program.getOwners().keySet().contains(contract.getIssuerCorpID()) : program.getOwners().keySet().contains(contract.getIssuerID()); if (isIssuer && //Issuer contract.isOpen() //Not completed && contractItem.isIncluded()) { //Selling sellingAssets = sellingAssets + contractItem.getDynamicPrice() * contractItem.getQuantity(); } } for (MyContract contract : contracts) { boolean isIssuer = contract.isForCorp() ? program.getOwners().keySet().contains(contract.getIssuerCorpID()) : program.getOwners().keySet().contains(contract.getIssuerID()); boolean isAcceptor = contract.getAcceptorID() > 0 && program.getOwners().keySet().contains(contract.getAcceptorID()); if (contract.isCourierContract()) { if (isIssuer && (contract.isInProgress() || contract.isOpen())) { //Collateral Issuer collateralIssuer = collateralIssuer + contract.getCollateral(); } if (isAcceptor && contract.isInProgress()) { //Collateral Acceptor collateralAcceptor = collateralAcceptor + contract.getCollateral(); } } if (contract.isIgnoreContract()) { continue; } if (isIssuer //Issuer && contract.isOpen() //Not completed ) { //Selling/Buying sellingPrice = sellingPrice + contract.getPrice(); //Positive buying = buying - contract.getReward(); //Negative } else if (contract.isCompletedSuccessful()) { //Completed if (isIssuer) { //Sold/Bought sold = sold + contract.getPrice(); //Positive bought = bought - contract.getReward(); //Negative } if (isAcceptor) { //Reverse of the above sold = sold + contract.getReward(); //Positive bought = bought - contract.getPrice(); //Negative } } } List sell = createMenuItemGroup(jPopupMenu, GuiShared.get().selectionTitleSell(), Images.ORDERS_SELL.getIcon()); createMenuItem(sell, jPopupMenu, sellingPrice, AutoNumberFormat.ISK, GuiShared.get().selectionContractsSellingPriceToolTip(), GuiShared.get().selectionContractsSellingPrice(), Images.ORDERS_SELL.getIcon()); createMenuItem(sell, jPopupMenu, sellingAssets, AutoNumberFormat.ISK, GuiShared.get().selectionContractsSellingAssetsToolTip(), GuiShared.get().selectionContractsSellingAssets(), Images.TOOL_VALUES.getIcon()); createMenuItem(sell, jPopupMenu, sold, AutoNumberFormat.ISK, GuiShared.get().selectionContractsSoldToolTip(), GuiShared.get().selectionContractsSold(), Images.ORDERS_SOLD.getIcon()); values.addAll(sell); List buy = createMenuItemGroup(jPopupMenu, GuiShared.get().selectionTitleBuy(), Images.ORDERS_BUY.getIcon()); createMenuItem(buy, jPopupMenu, buying, AutoNumberFormat.ISK, GuiShared.get().selectionContractsBuyingToolTip(), GuiShared.get().selectionContractsBuying(), Images.ORDERS_BUY.getIcon()); createMenuItem(buy, jPopupMenu, bought, AutoNumberFormat.ISK, GuiShared.get().selectionContractsBoughtToolTip(), GuiShared.get().selectionContractsBought(), Images.ORDERS_BOUGHT.getIcon()); values.addAll(buy); List collateral = createMenuItemGroup(jPopupMenu, GuiShared.get().selectionTitleCollateral(), Images.ORDERS_ESCROW.getIcon()); createMenuItem(collateral, jPopupMenu, collateralIssuer, AutoNumberFormat.ISK, GuiShared.get().selectionContractsCollateralIssuerToolTip(), GuiShared.get().selectionContractsCollateralIssuer(), Images.ORDERS_ESCROW.getIcon()); createMenuItem(collateral, jPopupMenu, collateralAcceptor, AutoNumberFormat.ISK, GuiShared.get().selectionContractsCollateralAcceptorToolTip(), GuiShared.get().selectionContractsCollateralAcceptor(), Images.UPDATE_WORKING.getIcon()); values.addAll(collateral); } public static void marketOrder(final JPopupMenu jPopupMenu, final List list) { List values = createDefault(jPopupMenu); double sellOrdersTotal = 0; double sellBrokersFeeTotal = 0; double buyOrdersTotal = 0; double buyBrokersFeeTotal = 0; double toCoverTotal = 0; double escrowTotal = 0; long volumeRemain = 0; long volumeTotal = 0; for (MyMarketOrder marketOrder : list) { if (marketOrder.isBuyOrder()) { //Buy buyOrdersTotal += marketOrder.getPrice() * marketOrder.getVolumeTotal(); escrowTotal += marketOrder.getEscrow(); toCoverTotal += (marketOrder.getPrice() * marketOrder.getVolumeTotal()) - marketOrder.getEscrow(); buyBrokersFeeTotal += marketOrder.getBrokersFeeNotNull(); } else { //Sell sellOrdersTotal += marketOrder.getPrice() * marketOrder.getVolumeTotal(); sellBrokersFeeTotal += marketOrder.getBrokersFeeNotNull(); } volumeRemain += marketOrder.getVolumeRemain(); volumeTotal += marketOrder.getVolumeTotal(); } createMenuItem(values, jPopupMenu, GuiShared.get().selectionOrdersCountValue(Formatter.longFormat(volumeRemain), Formatter.itemsFormat(volumeTotal)), GuiShared.get().selectionOrdersCount(), GuiShared.get().selectionShortCount(), Images.EDIT_ADD.getIcon()); createMenuItem(values, jPopupMenu, sellOrdersTotal + sellBrokersFeeTotal, AutoNumberFormat.ISK, GuiShared.get().selectionOrdersSellTotal(), GuiShared.get().selectionShortSell(), Images.ORDERS_SELL.getIcon()); createMenuItem(values, jPopupMenu, buyOrdersTotal + buyBrokersFeeTotal, AutoNumberFormat.ISK, GuiShared.get().selectionOrdersBuyTotal(), GuiShared.get().selectionShortBuy(), Images.ORDERS_BUY.getIcon()); createMenuItem(values, jPopupMenu, escrowTotal, AutoNumberFormat.ISK, GuiShared.get().selectionOrdersBuyEscrow(), GuiShared.get().selectionShortEscrow(), Images.ORDERS_ESCROW.getIcon()); createMenuItem(values, jPopupMenu, toCoverTotal, AutoNumberFormat.ISK, GuiShared.get().selectionOrdersBuyToCover(), GuiShared.get().selectionShortIskToCover(), Images.ORDERS_TO_COVER.getIcon()); createMenuItem(values, jPopupMenu, sellBrokersFeeTotal + buyBrokersFeeTotal, AutoNumberFormat.ISK, GuiShared.get().selectionOrdersBrokersFee(), GuiShared.get().selectionShortBrokerFees(), Images.MISC_COLLAPSED.getIcon()); } public static void transctions(final JPopupMenu jPopupMenu, final List transactions) { List values = createDefault(jPopupMenu); double sellTotal = 0; double sellTaxTotal = 0; double buyTotal = 0; long sellCount = 0; long buyCount = 0; for (MyTransaction transaction : transactions) { if (transaction.isSell()) { //Sell sellTotal += transaction.getPrice() * transaction.getQuantity(); sellCount += transaction.getQuantity(); sellTaxTotal += transaction.getTaxNotNull(); } else { //Buy buyTotal += transaction.getPrice() * transaction.getQuantity(); buyCount += transaction.getQuantity(); } } double sellAvg = 0; if (sellTotal > 0 && sellCount > 0) { sellAvg = (sellTotal + sellTaxTotal) / sellCount; } double buyAvg = 0; if (buyTotal > 0 && buyCount > 0) { buyAvg = buyTotal / buyCount; } double bothTotal = sellTotal + buyTotal; double bothCount = sellCount + buyCount; double bothAvg = 0; if (bothTotal > 0 && bothCount > 0) { bothAvg = (bothTotal + sellTaxTotal) / bothCount; } //Sell List sell = createMenuItemGroup(jPopupMenu, GuiShared.get().selectionTitleSell(), Images.ORDERS_SELL.getIcon()); createMenuItem(sell, jPopupMenu, sellCount, AutoNumberFormat.ITEMS, GuiShared.get().selectionTransactionsSellCount(), GuiShared.get().selectionShortCount(), Images.EDIT_ADD.getIcon()); createMenuItem(sell, jPopupMenu, sellTotal + sellTaxTotal, AutoNumberFormat.ISK, GuiShared.get().selectionTransactionsSellTotal(), GuiShared.get().selectionShortValue(), Images.TOOL_VALUES.getIcon()); createMenuItem(sell, jPopupMenu, sellAvg, AutoNumberFormat.ISK, GuiShared.get().selectionTransactionsSellAvg(), GuiShared.get().selectionShortAverage(), Images.ASSETS_AVERAGE.getIcon()); createMenuItem(sell, jPopupMenu, sellTaxTotal, AutoNumberFormat.ISK, GuiShared.get().selectionTransactionsSellTax(), GuiShared.get().selectionShortTax(), Images.MISC_COLLAPSED.getIcon()); values.addAll(sell); //Both List both = createMenuItemGroup(jPopupMenu, GuiShared.get().selectionTitleBoth(), Images.TOOL_TRANSACTION.getIcon()); createMenuItem(both, jPopupMenu, sellCount + buyCount, AutoNumberFormat.ITEMS, GuiShared.get().selectionTransactionsBothCount(), GuiShared.get().selectionShortCount(), Images.EDIT_ADD.getIcon()); createMenuItem(both, jPopupMenu, bothTotal + sellTaxTotal, AutoNumberFormat.ISK, GuiShared.get().selectionTransactionsBothTotal(), GuiShared.get().selectionShortValue(), Images.TOOL_VALUES.getIcon()); createMenuItem(both, jPopupMenu, bothAvg, AutoNumberFormat.ISK, GuiShared.get().selectionTransactionsBothAvg(), GuiShared.get().selectionShortAverage(), Images.ASSETS_AVERAGE.getIcon()); values.addAll(both); //Buy List buy = createMenuItemGroup(jPopupMenu, GuiShared.get().selectionTitleBuy(), Images.ORDERS_BUY.getIcon()); createMenuItem(buy, jPopupMenu, buyCount, AutoNumberFormat.ITEMS, GuiShared.get().selectionTransactionsBuyCount(), GuiShared.get().selectionShortCount(), Images.EDIT_ADD.getIcon()); createMenuItem(buy, jPopupMenu, buyTotal, AutoNumberFormat.ISK, GuiShared.get().selectionTransactionsBuyTotal(), GuiShared.get().selectionShortValue(), Images.TOOL_VALUES.getIcon()); createMenuItem(buy, jPopupMenu, buyAvg, AutoNumberFormat.ISK, GuiShared.get().selectionTransactionsBuyAvg(), GuiShared.get().selectionShortAverage(), Images.ASSETS_AVERAGE.getIcon()); values.addAll(buy); } public static void slots(final JPopupMenu jPopupMenu, final List list) { List values = createDefault(jPopupMenu); Slots total = new Slots(""); for (Slots slots : list) { if (slots.isGrandTotal()) { continue; } total.count(slots); } List manufacturing = createMenuItemGroup(jPopupMenu, GuiShared.get().selectionSlotsManufacturing(), Images.MISC_MANUFACTURING.getIcon()); createMenuItem(manufacturing, jPopupMenu, total.getManufacturingDone(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsManufacturingDoneToolTip(), GuiShared.get().selectionSlotsManufacturingDone(), Images.EDIT_SET.getIcon()); createMenuItem(manufacturing, jPopupMenu, total.getManufacturingFree(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsManufacturingFreeToolTip(), GuiShared.get().selectionSlotsManufacturingFree(), Images.EDIT_ADD.getIcon()); createMenuItem(manufacturing, jPopupMenu, total.getManufacturingActive(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsManufacturingActiveToolTip(), GuiShared.get().selectionSlotsManufacturingActive(), Images.UPDATE_WORKING.getIcon()); createMenuItem(manufacturing, jPopupMenu, total.getManufacturingMax(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsManufacturingMaxToolTip(), GuiShared.get().selectionSlotsManufacturingMax(), Images.UPDATE_DONE_OK.getIcon()); values.addAll(manufacturing); List research = createMenuItemGroup(jPopupMenu, GuiShared.get().selectionSlotsResearch(), Images.MISC_INVENTION.getIcon()); createMenuItem(research, jPopupMenu, total.getResearchDone(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsResearchDoneToolTip(), GuiShared.get().selectionSlotsResearchDone(), Images.EDIT_SET.getIcon()); createMenuItem(research, jPopupMenu, total.getResearchFree(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsResearchFreeToolTip(), GuiShared.get().selectionSlotsResearchFree(), Images.EDIT_ADD.getIcon()); createMenuItem(research, jPopupMenu, total.getResearchActive(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsResearchActiveToolTip(), GuiShared.get().selectionSlotsResearchActive(), Images.UPDATE_WORKING.getIcon()); createMenuItem(research, jPopupMenu, total.getResearchMax(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsResearchMaxToolTip(), GuiShared.get().selectionSlotsResearchMax(), Images.UPDATE_DONE_OK.getIcon()); values.addAll(research); List reactions = createMenuItemGroup(jPopupMenu, GuiShared.get().selectionSlotsReactions(), Images.MISC_REACTION.getIcon()); createMenuItem(reactions, jPopupMenu, total.getReactionsDone(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsReactionsDoneToolTip(), GuiShared.get().selectionSlotsReactionsDone(), Images.EDIT_SET.getIcon()); createMenuItem(reactions, jPopupMenu, total.getReactionsFree(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsReactionsFreeToolTip(), GuiShared.get().selectionSlotsReactionsFree(), Images.EDIT_ADD.getIcon()); createMenuItem(reactions, jPopupMenu, total.getReactionsActive(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsReactionsActiveToolTip(), GuiShared.get().selectionSlotsReactionsActive(), Images.UPDATE_WORKING.getIcon()); createMenuItem(reactions, jPopupMenu, total.getReactionsMax(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsReactionsMaxToolTip(), GuiShared.get().selectionSlotsReactionsMax(), Images.UPDATE_DONE_OK.getIcon()); values.addAll(reactions); List marketOrders = createMenuItemGroup(jPopupMenu, GuiShared.get().selectionSlotsMarketOrders(), Images.MISC_MARKET_ORDERS.getIcon()); createMenuItem(marketOrders, jPopupMenu, total.getMarketOrdersFree(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsMarketOrdersFreeToolTip(), GuiShared.get().selectionSlotsMarketOrdersFree(), Images.EDIT_ADD.getIcon()); createMenuItem(marketOrders, jPopupMenu, total.getMarketOrdersActive(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsMarketOrdersActiveToolTip(), GuiShared.get().selectionSlotsMarketOrdersActive(), Images.UPDATE_WORKING.getIcon()); createMenuItem(marketOrders, jPopupMenu, total.getMarketOrdersMax(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsMarketOrdersMaxToolTip(), GuiShared.get().selectionSlotsMarketOrdersMax(), Images.UPDATE_DONE_OK.getIcon()); values.addAll(marketOrders); List contractCharacter = createMenuItemGroup(jPopupMenu, GuiShared.get().selectionSlotsContractCharacter(), Images.MISC_CONTRACTS.getIcon()); createMenuItem(contractCharacter, jPopupMenu, total.getContractCharacterFree(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsContractCharacterFreeToolTip(), GuiShared.get().selectionSlotsContractCharacterFree(), Images.EDIT_ADD.getIcon()); createMenuItem(contractCharacter, jPopupMenu, total.getContractCharacterActive(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsContractCharacterActiveToolTip(), GuiShared.get().selectionSlotsContractCharacterActive(), Images.UPDATE_WORKING.getIcon()); createMenuItem(contractCharacter, jPopupMenu, total.getContractCharacterMax(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsContractCharacterMaxToolTip(), GuiShared.get().selectionSlotsContractCharacterMax(), Images.UPDATE_DONE_OK.getIcon()); values.addAll(contractCharacter); List contractCorporation = createMenuItemGroup(jPopupMenu, GuiShared.get().selectionSlotsContractCorporation(), Images.MISC_CONTRACTS_CORP.getIcon()); createMenuItem(contractCorporation, jPopupMenu, total.getContractCorporationFree(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsContractCorporationFreeToolTip(), GuiShared.get().selectionSlotsContractCorporationFree(), Images.EDIT_ADD.getIcon()); createMenuItem(contractCorporation, jPopupMenu, total.getContractCorporationActive(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsContractCorporationActiveToolTip(), GuiShared.get().selectionSlotsContractCorporationActive(), Images.UPDATE_WORKING.getIcon()); createMenuItem(contractCorporation, jPopupMenu, total.getContractCorporationMax(), AutoNumberFormat.LONG, GuiShared.get().selectionSlotsContractCorporationMaxToolTip(), GuiShared.get().selectionSlotsContractCorporationMax(), Images.UPDATE_DONE_OK.getIcon()); values.addAll(contractCorporation); } public static void industryJob(final JPopupMenu jPopupMenu, final List list) { List values = createDefault(jPopupMenu); int inventionCount = 0; long count = 0; double success = 0; double outputValue = 0; for (MyIndustryJob industryJob : list) { count++; if (industryJob.isInvention() && industryJob.isDone()) { inventionCount++; if (industryJob.isCompletedSuccessful()) { success++; } } if (industryJob.isNotDeliveredToAssets()) { //Only include active jobs outputValue += industryJob.getOutputValue(); } } if (inventionCount <= 0) { createMenuItem(values, jPopupMenu, 0.0, AutoNumberFormat.PERCENT, GuiShared.get().selectionInventionSuccess(), GuiShared.get().selectionShortInventionSuccess(), Images.JOBS_INVENTION_SUCCESS.getIcon()); } else { createMenuItem(values, jPopupMenu, success / count, AutoNumberFormat.PERCENT, GuiShared.get().selectionInventionSuccess(), GuiShared.get().selectionShortInventionSuccess(), Images.JOBS_INVENTION_SUCCESS.getIcon()); } createMenuItem(values, jPopupMenu, outputValue, AutoNumberFormat.ISK, GuiShared.get().selectionManufactureJobsValue(), GuiShared.get().selectionShortOutputValue(), Images.TOOL_VALUES.getIcon()); createMenuItem(values, jPopupMenu, count, AutoNumberFormat.ITEMS, GuiShared.get().selectionCount(), GuiShared.get().selectionShortCount(), Images.EDIT_ADD.getIcon()); } public static void stockpileItem(final JPopupMenu jPopupMenu, final List list) { List values = createDefault(jPopupMenu); double volumnNow = 0; double volumnNeeded = 0; double valueNow = 0; double valueNeeded = 0; for (int i = 0; i < list.size(); i++) { Object object = list.get(i); if (object instanceof SeparatorList.Separator) { continue; } if (object instanceof StockpileTotal) { continue; } if (object == null) { continue; } StockpileItem item = (StockpileItem) object; volumnNow = volumnNow + item.getVolumeNow(); if (item.getVolumeNeeded() < 0) { //Only add if negative volumnNeeded = volumnNeeded + item.getVolumeNeeded(); } valueNow = valueNow + item.getValueNow(); if (item.getValueNeeded() < 0) { //Only add if negative valueNeeded = valueNeeded + item.getValueNeeded(); } } List now = createMenuItemGroup(jPopupMenu, GuiShared.get().selectionTitleNow()); createMenuItem(now, jPopupMenu, valueNow, AutoNumberFormat.ISK, GuiShared.get().selectionValueNow(), GuiShared.get().selectionShortValue(), Images.TOOL_VALUES.getIcon()); createMenuItem(now, jPopupMenu, volumnNow, AutoNumberFormat.DOUBLE, GuiShared.get().selectionVolumeNow(), GuiShared.get().selectionShortVolume(), Images.ASSETS_VOLUME.getIcon()); values.addAll(now); List needed = createMenuItemGroup(jPopupMenu, GuiShared.get().selectionTitleNeeded()); createMenuItem(needed, jPopupMenu, valueNeeded, AutoNumberFormat.ISK, GuiShared.get().selectionValueNeeded(), GuiShared.get().selectionShortValue(), Images.TOOL_VALUES.getIcon()); createMenuItem(needed, jPopupMenu, volumnNeeded, AutoNumberFormat.DOUBLE, GuiShared.get().selectionVolumeNeeded(), GuiShared.get().selectionShortVolume(), Images.ASSETS_VOLUME.getIcon()); values.addAll(needed); } public static void material(final JPopupMenu jPopupMenu, final List selected, final List all) { List values = createDefault(jPopupMenu); MaterialTotal materialTotal = calcMaterialTotal(new ArrayList<>(selected), all); createMenuItem(values, jPopupMenu, materialTotal.getTotalValue(), AutoNumberFormat.ISK, GuiShared.get().selectionValue(), GuiShared.get().selectionShortValue(), Images.TOOL_VALUES.getIcon()); createMenuItem(values, jPopupMenu, materialTotal.getAverageValue(), AutoNumberFormat.ISK, GuiShared.get().selectionAverage(), GuiShared.get().selectionShortAverage(), Images.ASSETS_AVERAGE.getIcon()); createMenuItem(values, jPopupMenu, materialTotal.getTotalCount(), AutoNumberFormat.ITEMS, GuiShared.get().selectionCount(), GuiShared.get().selectionShortCount(), Images.EDIT_ADD.getIcon()); } static MaterialTotal calcMaterialTotal(final List selectedList, final List all) { //Remove none-Material classes List selected = new ArrayList<>(selectedList); for (int i = 0; i < selected.size(); i++) { Object object = selected.get(i); if (!(object instanceof Material)) { selected.remove(i); i--; } } long totalCount = 0; double totalValue = 0; double averageValue = 0; boolean add; for (Material material : all) { if (material.getType() == MaterialType.LOCATIONS) { add = false; for (Material selectedMaterial : selected) { //Equals anything/all if (selectedMaterial.getType() == MaterialType.SUMMARY_ALL) { add = true; break; } //Equals group if (selectedMaterial.getType() == MaterialType.SUMMARY_TOTAL && material.getGroup().equals(selectedMaterial.getName())) { add = true; break; } //Equals name if (selectedMaterial.getType() == MaterialType.SUMMARY && material.getName().equals(selectedMaterial.getName())) { add = true; break; } //Equals location if (selectedMaterial.getType() == MaterialType.LOCATIONS_ALL && material.getHeader().equals(selectedMaterial.getHeader())) { add = true; break; } //Equals location and group if (selectedMaterial.getType() == MaterialType.LOCATIONS_TOTAL && material.getHeader().equals(selectedMaterial.getHeader()) && material.getGroup().equals(selectedMaterial.getName())) { add = true; break; } //Equals location and name if (selectedMaterial.getType() == MaterialType.LOCATIONS && material.getHeader().equals(selectedMaterial.getHeader()) && material.getName().equals(selectedMaterial.getName())) { add = true; break; } } if (add) { totalCount = totalCount + material.getCount(); totalValue = totalValue + material.getValue(); } } } if (totalCount > 0 && totalValue > 0) { averageValue = totalValue / totalCount; } return new MaterialTotal(totalCount, totalValue, averageValue); } public static void module(final JPopupMenu jPopupMenu, final List selected) { List values = createDefault(jPopupMenu); long totalCount = 0; double totalValue = 0; double averageValue = 0; Loadout totalShip = null; Loadout totalModule = null; Loadout totalAll = null; for (int i = 0; i < selected.size(); i++) { Object object = selected.get(i); if (object instanceof Loadout) { Loadout module = (Loadout) object; if (module.getName().equals(TabsLoadout.get().totalShip())) { totalShip = module; } else if (module.getName().equals(TabsLoadout.get().totalModules())) { totalModule = module; } else if (module.getName().equals(TabsLoadout.get().totalAll())) { totalAll = module; break; } else { totalCount = totalCount + module.getCount(); totalValue = totalValue + module.getValue(); } } } if (totalAll != null) { //All totalValue = totalAll.getValue(); totalCount = totalAll.getCount(); } else { if (totalModule != null) { //Module IS total totalValue = totalModule.getValue(); totalCount = totalModule.getCount(); } if (totalShip != null) { //Ship is added to total totalValue = totalValue + totalShip.getValue(); totalCount = totalCount + totalShip.getCount(); } } if (totalCount > 0 && totalValue > 0) { averageValue = totalValue / totalCount; } createMenuItem(values, jPopupMenu, totalValue, AutoNumberFormat.ISK, GuiShared.get().selectionValue(), GuiShared.get().selectionShortValue(), Images.TOOL_VALUES.getIcon()); createMenuItem(values, jPopupMenu, averageValue, AutoNumberFormat.ISK, GuiShared.get().selectionAverage(), GuiShared.get().selectionShortAverage(), Images.ASSETS_AVERAGE.getIcon()); createMenuItem(values, jPopupMenu, totalCount, AutoNumberFormat.ISK, GuiShared.get().selectionCount(), GuiShared.get().selectionShortCount(), Images.EDIT_ADD.getIcon()); } public static JMenuItem createMenuItem(List values, final JPopupMenu jPopupMenu, final Number number, AutoNumberFormat numberFormat, final String toolTip, String copyText, final Icon icon) { return createMenuItem(values, jPopupMenu, null, number, numberFormat, toolTip, copyText, icon); } public static JMenuItem createMenuItem(List values, final JPopupMenu jPopupMenu, final String text, final String toolTip, String copyText, final Icon icon) { return createMenuItem(values, jPopupMenu, text, null, null, toolTip, copyText, icon); } private static JMenuItem createMenuItem(List values, final JPopupMenu jPopupMenu, final String text, final Number number, AutoNumberFormat numberFormat, final String toolTip, String copyText, final Icon icon) { if (values != null) { values.add(new MenuItemValue(copyText, text, number)); } JMenuItem jMenuItem; if (text == null) { //Numeric Value jMenuItem = new JMenuItem(format(number, numberFormat)); } else { //Text value jMenuItem = new JMenuItem(text); } jMenuItem.setToolTipText(GuiShared.get().clickToCopyWrap(toolTip)); jMenuItem.setEnabled(false); jMenuItem.setDisabledIcon(icon); jMenuItem.setForeground(Color.BLACK); jMenuItem.setHorizontalAlignment(SwingConstants.RIGHT); if (jPopupMenu != null) { jPopupMenu.add(jMenuItem); } jMenuItem.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1) { if (number != null) { CopyHandler.toClipboard(Formatter.copyFormat(number)); } else { CopyHandler.toClipboard(text); } jMenuItem.setText(GuiShared.get().selectionCopiedToClipboard()); jMenuItem.setDisabledIcon(Images.EDIT_COPY.getIcon()); final Timer timer = new Timer(COPY_DELAY, null); timer.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (text == null) { jMenuItem.setText(format(number, numberFormat)); } else { jMenuItem.setText(text); } jMenuItem.setDisabledIcon(icon); timer.stop(); } }); timer.start(); } } }); return jMenuItem; } private static List createMenuItemGroup(final JPopupMenu jPopupMenu, final String text) { return createMenuItemGroup(jPopupMenu, text, null); } private static List createMenuItemGroup(final JPopupMenu jPopupMenu, final String text, final Icon icon) { List values = new ArrayList<>(); JMenuItem jMenuItem = new JMenuItem(text); jMenuItem.setToolTipText(GuiShared.get().clickToCopyGroup()); if (icon != null) { jMenuItem.setDisabledIcon(icon); } values.add(new MenuItemValue(null, GuiShared.get().selectionShortGroup(text), null)); jMenuItem.setEnabled(false); if (border == null) { border = BorderFactory.createCompoundBorder( BorderFactory.createCompoundBorder( BorderFactory.createMatteBorder(1, 0, 0, 0, jMenuItem.getBackground().darker()), BorderFactory.createMatteBorder(1, 0, 0, 0, jMenuItem.getBackground().brighter())), BorderFactory.createCompoundBorder( BorderFactory.createMatteBorder(0, 0, 1, 0, jMenuItem.getBackground().brighter()), BorderFactory.createMatteBorder(0, 0, 1, 0, jMenuItem.getBackground().darker()))); } jMenuItem.setForeground(Color.BLACK); jMenuItem.setBorder(border); jMenuItem.setBorderPainted(true); jMenuItem.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1) { CopyHandler.toClipboard(format(values)); jMenuItem.setText(GuiShared.get().selectionCopiedToClipboard()); jMenuItem.setDisabledIcon(Images.EDIT_COPY.getIcon()); final Timer timer = new Timer(COPY_DELAY, null); timer.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jMenuItem.setText(text); jMenuItem.setDisabledIcon(icon); timer.stop(); } }); timer.start(); } } }); jPopupMenu.add(jMenuItem); return values; } public static List createDefault(final JPopupMenu jPopupMenu) { return createDefault(jPopupMenu, new JMenuItem(), GuiShared.get().selectionTitle(), GuiShared.get().clickToCopySelectionInfo(), Images.DIALOG_ABOUT.getIcon()); } public static List createDefault(final JPopupMenu jPopupMenu, final JMenuItem jMenuItem, String title, String toolTip, Icon icon) { final List values = new ArrayList<>(); values.add(new MenuItemValue(null, title, null)); if (jPopupMenu != null) { jPopupMenu.addSeparator(); } jMenuItem.setText(title); jMenuItem.setToolTipText(toolTip); jMenuItem.setDisabledIcon(icon); jMenuItem.setEnabled(false); jMenuItem.setForeground(Color.BLACK); jMenuItem.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1) { CopyHandler.toClipboard(format(values)); jMenuItem.setText(GuiShared.get().selectionCopiedToClipboard()); jMenuItem.setDisabledIcon(Images.EDIT_COPY.getIcon()); final Timer timer = new Timer(COPY_DELAY, null); timer.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jMenuItem.setText(GuiShared.get().selectionTitle()); jMenuItem.setDisabledIcon(Images.DIALOG_ABOUT.getIcon()); timer.stop(); } }); timer.start(); } } }); if (jPopupMenu != null) { jPopupMenu.add(jMenuItem); JPanel jSpacePanel = new JPanel(); jSpacePanel.setOpaque(false); jSpacePanel.setMinimumSize(new Dimension(50, 5)); jSpacePanel.setPreferredSize(new Dimension(50, 5)); jSpacePanel.setMaximumSize(new Dimension(50, 5)); jPopupMenu.add(jSpacePanel); } return values; } public static String format(final Number number, AutoNumberFormat numberFormat) { switch(numberFormat) { case ISK: return Formatter.iskFormat(number); case DOUBLE: return Formatter.doubleFormat(number); case ITEMS: return Formatter.itemsFormat(number); case PERCENT: return Formatter.percentFormat(number); case LONG: return Formatter.longFormat(number); default: return String.valueOf(number); } } private static String format(final List values) { StringBuilder builder = new StringBuilder(); for (MenuItemValue item : values) { if (item.type != null) { builder.append(item.type); builder.append(": "); } if (item.number != null) { builder.append(Formatter.copyFormat(item.number)); builder.append("\r\n"); } else if (item.text != null) { builder.append(item.text); builder.append("\r\n"); } else { builder.append("\r\n"); } } return builder.toString(); } public static class MaterialTotal { private final long totalCount; private final double totalValue; private final double averageValue; public MaterialTotal(final long totalCount, final double totalValue, final double averageValue) { this.totalCount = totalCount; this.totalValue = totalValue; this.averageValue = averageValue; } public double getAverageValue() { return averageValue; } public long getTotalCount() { return totalCount; } public double getTotalValue() { return totalValue; } } public static class MenuItemValue { private final String type; private final String text; private final Number number; public MenuItemValue(String type, String text, Number number) { this.type = type; this.text = text; this.number = number; } } public enum AutoNumberFormat { ISK, DOUBLE, ITEMS, PERCENT, LONG } public interface InfoItem { double getValue(); long getCount(); double getVolumeTotal(); double getValueReprocessed(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuJumps.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.HashMap; import java.util.Map; import java.util.Set; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.RouteFinder; import net.nikr.eve.jeveasset.data.sde.RouteFinder.RouteFinderFilter; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.MenuScroller; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuJumps.Jump; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.JAutoMenu; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.tabs.routing.SolarSystem; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JMenuJumps & EnumTableColumn, Q> extends JAutoMenu { private enum MenuJumpsAction { ADD_SELECTED, ADD_OTHER, CLEAR, SETTINGS } private final JMenuItem jAddOther; private final JMenuItem jAddSelected; private final JMenuItem jSettings; private final JMenuItem jClear; private final ColumnManager columnManager; public JMenuJumps(Program program, ColumnManager columnManager) { super(GuiShared.get().jumps(), program); this.columnManager = columnManager; ListenerClass listener = new ListenerClass(); this.setIcon(Images.TOOL_ROUTING.getIcon()); MenuScroller menuScroller = new MenuScroller(this); menuScroller.keepVisible(4); menuScroller.setTopFixedCount(4); menuScroller.setInterval(125); jAddOther = new JMenuItem(GuiShared.get().jumpsAddCustom()); jAddOther.setIcon(Images.EDIT_SET.getIcon()); jAddOther.setActionCommand(MenuJumpsAction.ADD_OTHER.name()); jAddOther.addActionListener(listener); jAddSelected = new JMenuItem(GuiShared.get().jumpsAddSelected()); jAddSelected.setIcon(Images.EDIT_ADD.getIcon()); jAddSelected.setActionCommand(MenuJumpsAction.ADD_SELECTED.name()); jAddSelected.addActionListener(listener); jSettings = new JMenuItem(GuiShared.get().jumpsSettings()); jSettings.setIcon(Images.DIALOG_SETTINGS.getIcon()); jSettings.setActionCommand(MenuJumpsAction.SETTINGS.name()); jSettings.addActionListener(listener); jClear = new JMenuItem(GuiShared.get().jumpsClear()); jClear.setIcon(Images.EDIT_DELETE.getIcon()); jClear.setActionCommand(MenuJumpsAction.CLEAR.name()); jClear.addActionListener(listener); } @Override public void updateMenuData() { removeAll(); add(jAddSelected); jAddSelected.setEnabled(!menuData.getSystemLocations().isEmpty()); add(jAddOther); addSeparator(); add(jSettings); addSeparator(); add(jClear); Set locations = columnManager.getJumps(); jClear.setEnabled(!locations.isEmpty()); if (!locations.isEmpty()) { addSeparator(); } for (final Jump jump : locations) { //Add to menu final JMenuItem jMenuItem = new JMenuItem(jump.getName()); //FIXME !Jumps i18n - Clear System jMenuItem.setIcon(Images.EDIT_DELETE.getIcon()); jMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //Remove from settings columnManager.removeColumn(jump); } }); add(jMenuItem); } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (MenuJumpsAction.ADD_SELECTED.name().equals(e.getActionCommand())) { columnManager.addColumns(menuData.getSystemLocations()); } else if (MenuJumpsAction.CLEAR.name().equals(e.getActionCommand())) { columnManager.clearJumpColumns(); } else if (MenuJumpsAction.ADD_OTHER.name().equals(e.getActionCommand())) { //Clear tab SolarSystem solarSystem = program.getRoutingTab(true).getSolarSystem(); if (solarSystem != null) { MyLocation location = StaticData.get().getLocation(solarSystem.getSystemID()); if (location != null) { columnManager.addColumn(new Jump(location)); } } } else if (MenuJumpsAction.SETTINGS.name().equals(e.getActionCommand())) { program.showJumpsSettingsPanel(); } } } public static class Jump { private final MyLocation from; private final Map jumps = new HashMap<>(); private Integer index; public Jump(MyLocation from) { this(from, null); } public Jump(MyLocation from, Integer index) { this.from = from; this.index = index; } public String getName() { return from.getSystem(); } public long getSystemID() { return from.getSystemID(); } public Integer addJump(LocationType locationType) { MyLocation location = locationType.getLocation(); if (location == null) { return null; } long systemID = location.getSystemID(); if (systemID <= 0) { return null; } Integer distanceBetween = RouteFinder.get().distanceBetween(RouteFinderFilter.JUMPS, getSystemID(), systemID); jumps.put(locationType, distanceBetween); return distanceBetween; } public Integer getJumps(Object object) { Integer count = jumps.get(object); if (count != null) { return count; } if (object instanceof LocationType) { return addJump((LocationType) object); } else { return null; } } public Integer getIndex() { return index; } public void setIndex(Integer index) { this.index = index; } @Override public int hashCode() { int hash = 7; hash = 89 * hash + (int) (this.from.getSystemID() ^ (this.from.getSystemID() >>> 32)); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Jump other = (Jump) obj; if (this.from.getSystemID() != other.from.getSystemID()) { return false; } return true; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuLoadout.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JSelectionDialog; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.JAutoMenu; import net.nikr.eve.jeveasset.gui.tabs.loadout.LoadoutsTab; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeAsset; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JMenuLoadout extends JAutoMenu { private enum MenuLoadoutAction { OPEN } private List ships; private final JMenuItem jOpen; private final JSelectionDialog jShipDialog; public JMenuLoadout(final Program program) { super(GuiShared.get().loadout(), program); setIcon(Images.TOOL_SHIP_LOADOUTS.getIcon()); ListenerClass listener = new ListenerClass(); jShipDialog = new JSelectionDialog<>(program); jOpen = new JMenuItem(GuiShared.get().loadoutOpen()); //jOpen.setIcon(Images.LOC_SHIP.getIcon()); jOpen.setIcon(Images.EDIT_SET.getIcon()); jOpen.setActionCommand(MenuLoadoutAction.OPEN.name()); jOpen.addActionListener(listener); add(jOpen); } @Override public void updateMenuData() { ships = new ArrayList<>(); for (MyAsset asset : menuData.getAssets()) { if (asset == null) { continue; } //Add Tree sub assets if (asset instanceof TreeAsset) { for (TreeAsset treeAsset : ((TreeAsset) asset).getItems()) { if (!treeAsset.getItem().isShip() || !treeAsset.isSingleton() || !treeAsset.isItem()) { continue; } ships.add(treeAsset); } } //Add if (!asset.getItem().isShip() || !asset.isSingleton()) { continue; } ships.add(asset); } jOpen.setEnabled(!ships.isEmpty()); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (MenuLoadoutAction.OPEN.name().equals(e.getActionCommand())) { MyAsset ship = null; if (ships.size() > 1) { ship = jShipDialog.show(GuiShared.get().loadoutSelectShip(), ships); } else if (!ships.isEmpty()) { ship = ships.get(0); } if (ship == null) { return; } LoadoutsTab loadoutsTab = program.getLoadoutsTab(true); program.getMainWindow().addTab(loadoutsTab, true); loadoutsTab.selectShip(ship); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuLocation.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collections; import java.util.HashSet; import java.util.Set; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.Citadel; import net.nikr.eve.jeveasset.gui.dialogs.update.StructureUpdateDialog; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JSelectionDialog; import net.nikr.eve.jeveasset.i18n.GuiFrame; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.io.online.CitadelGetter; public class JMenuLocation extends MenuManager.JAutoMenu { private enum MenuLocationAction { EDIT, CLEAR, UPDATE } private final JMenuItem jUpdate; private final JMenuItem jEdit; private final JMenuItem jReset; private final JSelectionDialog jLocationDialog; public JMenuLocation(final Program program) { super((GuiShared.get().location()), program); setIcon(Images.LOC_LOCATIONS.getIcon()); ListenerClass listener = new ListenerClass(); jLocationDialog = new JSelectionDialog(program); jEdit = new JMenuItem(GuiShared.get().itemEdit()); jEdit.setIcon(Images.EDIT_EDIT.getIcon()); jEdit.setActionCommand(MenuLocationAction.EDIT.name()); jEdit.addActionListener(listener); add(jEdit); addSeparator(); jUpdate = new JMenuItem(GuiShared.get().updateStructures()); jUpdate.setIcon(Images.DIALOG_UPDATE.getIcon()); jUpdate.setActionCommand(MenuLocationAction.UPDATE.name()); jUpdate.addActionListener(listener); add(jUpdate); addSeparator(); jReset = new JMenuItem(GuiShared.get().itemDelete()); jReset.setIcon(Images.EDIT_DELETE.getIcon()); jReset.setActionCommand(MenuLocationAction.CLEAR.name()); jReset.addActionListener(listener); add(jReset); } @Override public void updateMenuData() { jEdit.setEnabled(!menuData.getEditableCitadelLocations().isEmpty()); jUpdate.setEnabled(!menuData.getEditableCitadelLocations().isEmpty()); if (StructureUpdateDialog.structuresUpdatable(program)) { jUpdate.setIcon(Images.DIALOG_UPDATE.getIcon()); jUpdate.setToolTipText(GuiFrame.get().updatable()); } else { jUpdate.setIcon(Images.DIALOG_UPDATE_DISABLED.getIcon()); jUpdate.setToolTipText(GuiFrame.get().not()); } jReset.setEnabled(!menuData.getUserLocations().isEmpty()); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (MenuLocationAction.CLEAR.name().equals(e.getActionCommand())) { if (menuData.getUserLocations().size() == 1) { //Single MyLocation location = menuData.getUserLocations().iterator().next(); Long locationID = program.getUserLocationSettingsPanel().deleteLocation(location); if (locationID != null) { CitadelGetter.remove(locationID); program.updateLocations(Collections.singleton(location.getLocationID())); } } else { int value = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), GuiShared.get().locationClearConfirmAll(menuData.getUserLocations().size()), GuiShared.get().locationClear(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if (value == JOptionPane.OK_OPTION) { //All Set locationIDs = new HashSet<>(); for (MyLocation location : menuData.getUserLocations()) { locationIDs.add(location.getLocationID()); } CitadelGetter.remove(locationIDs); program.updateLocations(locationIDs); } else { //Single MyLocation location = jLocationDialog.show(GuiShared.get().locationID(), menuData.getUserLocations()); Long locationID = program.getUserLocationSettingsPanel().deleteLocation(location); if (locationID != null) { CitadelGetter.remove(locationID); program.updateLocations(Collections.singleton(location.getLocationID())); } } } } else if (MenuLocationAction.EDIT.name().equals(e.getActionCommand())) { MyLocation renameLocation = jLocationDialog.show(GuiShared.get().locationID(), menuData.getEditableCitadelLocations()); Citadel citadel = program.getUserLocationSettingsPanel().editLocation(renameLocation); if (citadel != null) { CitadelGetter.set(citadel); program.updateLocations(Collections.singleton(renameLocation.getLocationID())); } } else if (MenuLocationAction.UPDATE.name().equals(e.getActionCommand())) { program.updateStructures(menuData.getEditableCitadelLocations(), true); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuLookup.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.swing.Icon; import javax.swing.JMenu; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.JAutoMenu; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewGroup; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewLocation; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab.OverviewTableMenu; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.i18n.TabsOverview; import net.nikr.eve.jeveasset.io.shared.DesktopUtil; public class JMenuLookup extends JAutoMenu { public static enum LookupLinks { //Locations ZKILLBOARD_SYSTEM(GuiShared.get().system(), Images.LOC_SYSTEM.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (MyLocation location : menuData.getSystemLocations()) { urls.add("https://zkillboard.com/system/" +location.getLocationID() + "/"); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getSystemLocations().isEmpty(); } }, ZKILLBOARD_CONSTELLATION(GuiShared.get().constellation(), Images.LOC_CONSTELLATION.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (MyLocation location : menuData.getConstellationLocations()) { urls.add("https://zkillboard.com/constellation/" +location.getLocationID() + "/"); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getConstellationLocations().isEmpty(); } }, ZKILLBOARD_REGION(GuiShared.get().region(), Images.LOC_REGION.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (MyLocation location : menuData.getRegionLocations()) { urls.add("https://zkillboard.com/region/" +location.getLocationID() + "/"); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getRegionLocations().isEmpty(); } }, ZKILLBOARD_OVERVIEW_GROUP(TabsOverview.get().locations(), Images.LOC_REGION.getIcon()) { @Override public Set getLinks(MenuData menuData) { return Collections.emptySet(); } @Override public Boolean isEnabled(MenuData menuData) { return null; } @Override public void open(Program program, MenuData menuData) { OverviewGroup overviewGroup = program.getOverviewTab(true).getSelectGroup(); if (overviewGroup == null) { return; } MenuData data = new MenuData<>(); for (OverviewLocation location : overviewGroup.getLocations()) { if (location.isStation()) { continue; } if (location.isPlanet()) { continue; } for (MyLocation myLocation : StaticData.get().getLocations()) { if (!myLocation.getLocation().equals(location.getName())) { continue; //Not the location you're looking for } if (location.isSystem()) { data.getSystemLocations().add(myLocation); } if (location.isConstellation()) { data.getConstellationLocations().add(myLocation); } if (location.isRegion()) { data.getRegionLocations().add(myLocation); } break; //Location found } } Set urls = new HashSet<>(); urls.addAll(LookupLinks.ZKILLBOARD_SYSTEM.getLinks(data)); urls.addAll(LookupLinks.ZKILLBOARD_CONSTELLATION.getLinks(data)); urls.addAll(LookupLinks.ZKILLBOARD_REGION.getLinks(data)); DesktopUtil.browse(urls, program); } }, EVEMAPS_DOTLAN_STATION(GuiShared.get().station(), Images.LOC_STATION.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (String station : menuData.getStationNames()) { urls.add("https://evemaps.dotlan.net/station/" + station.replace(" ", "_")); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getStationNames().isEmpty(); } }, EVEMAPS_DOTLAN_PLANET(GuiShared.get().planet(), Images.LOC_PLANET.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (String planet : menuData.getPlanetNames()) { urls.add("https://evemaps.dotlan.net/system/" + replaceLast(planet, " ", "/").replace(" ", "_")); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getPlanetNames().isEmpty(); } }, EVEMAPS_DOTLAN_SYSTEM(GuiShared.get().system(), Images.LOC_SYSTEM.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (String system : menuData.getSystemNames()) { urls.add("https://evemaps.dotlan.net/system/" + system.replace(" ", "_")); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getSystemNames().isEmpty(); } }, EVEMAPS_DOTLAN_SYSTEM_REGION(GuiShared.get().systemRegion(), Images.LOC_SYSTEM.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (MyLocation system : menuData.getSystemLocations()) { urls.add("https://evemaps.dotlan.net/map/" + system.getRegion().replace(" ", "_")+ "/" + system.getSystem().replace(" ", "_")); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getSystemLocations().isEmpty(); } }, EVEMAPS_DOTLAN_CONSTELLATION(GuiShared.get().constellation(), Images.LOC_CONSTELLATION.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (MyLocation constellation : menuData.getConstellationLocations()) { urls.add("https://evemaps.dotlan.net/map/" + constellation.getRegion().replace(" ", "_") + "/" + constellation.getConstellation().replace(" ", "_")); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getConstellationLocations().isEmpty(); } }, EVEMAPS_DOTLAN_REGION(GuiShared.get().region(), Images.LOC_REGION.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (String region : menuData.getRegionNames()) { urls.add("https://evemaps.dotlan.net/map/" + region.replace(" ", "_")); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getRegionNames().isEmpty(); } }, EVEMAPS_DOTLAN_OVERVIEW_GROUP(TabsOverview.get().locations(), Images.LOC_LOCATIONS.getIcon()) { @Override public Set getLinks(MenuData menuData) { return Collections.emptySet(); } @Override public Boolean isEnabled(MenuData menuData) { return null; } @Override public void open(Program program, MenuData menuData) { OverviewGroup overviewGroup = program.getOverviewTab(true).getSelectGroup(); if (overviewGroup == null) { return; } MenuData data = new MenuData<>(); for (OverviewLocation location : overviewGroup.getLocations()) { if (location.isStation()) { data.getStationNames().add(location.getName()); } if (location.isPlanet()) { data.getPlanetNames().add(location.getName()); } if (location.isSystem()) { data.getSystemNames().add(location.getName()); } if (location.isRegion()) { data.getRegionNames().add(location.getName()); } for (MyLocation myLocation : StaticData.get().getLocations()) { if (!myLocation.getLocation().equals(location.getName())) { continue; //Not the location you're looking for } if (location.isConstellation()) { data.getConstellationLocations().add(myLocation); } break; //Location found } } Set urls = new HashSet<>(); urls.addAll(LookupLinks.EVEMAPS_DOTLAN_STATION.getLinks(data)); urls.addAll(LookupLinks.EVEMAPS_DOTLAN_PLANET.getLinks(data)); urls.addAll(LookupLinks.EVEMAPS_DOTLAN_SYSTEM.getLinks(data)); urls.addAll(LookupLinks.EVEMAPS_DOTLAN_CONSTELLATION.getLinks(data)); urls.addAll(LookupLinks.EVEMAPS_DOTLAN_REGION.getLinks(data)); DesktopUtil.browse(urls, program); } }, EVEMISSIONEER_SYSTEM(GuiShared.get().system(), Images.LOC_SYSTEM.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (MyLocation location : menuData.getSystemLocations()) { urls.add("https://evemissioneer.com/s/" + location.getLocationID()); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getSystemLocations().isEmpty(); } }, EVEMISSIONEER_CONSTELLATION(GuiShared.get().constellation(), Images.LOC_CONSTELLATION.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (MyLocation location : menuData.getConstellationLocations()) { urls.add("https://evemissioneer.com/c/" + location.getLocationID()); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getConstellationLocations().isEmpty(); } }, EVEMISSIONEER_REGION(GuiShared.get().region(), Images.LOC_REGION.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (MyLocation location : menuData.getRegionLocations()) { urls.add("https://evemissioneer.com/r/" + location.getLocationID()); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getRegionLocations().isEmpty(); } }, //Market FUZZWORK_MARKET(GuiShared.get().fuzzworkMarket(), Images.LINK_FUZZWORK.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int marketTypeID : menuData.getMarketTypeIDs()) { urls.add("https://market.fuzzwork.co.uk/hub/type/" + marketTypeID + "/"); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getMarketTypeIDs().isEmpty(); } }, EVE_TYCOON(GuiShared.get().eveTycoon(), Images.LINK_EVE_TYCOON.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int marketTypeID : menuData.getMarketTypeIDs()) { urls.add("https://evetycoon.com/market/" + marketTypeID); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getMarketTypeIDs().isEmpty(); } }, ADAM4EVE(GuiShared.get().adam4eve(), Images.LINK_ADAM4EVE.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int marketTypeID : menuData.getMarketTypeIDs()) { urls.add("https://www.adam4eve.eu/commodity.php?typeID=" + marketTypeID); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getMarketTypeIDs().isEmpty(); } }, EVE_MARKET_BROWSER(GuiShared.get().eveMarketBrowser(), Images.LINK_EVE_MARKET_BROWSER.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int marketTypeID : menuData.getMarketTypeIDs()) { urls.add("https://evemarketbrowser.com/region/0/type/" + marketTypeID); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getMarketTypeIDs().isEmpty(); } }, JITA_SPACE_MARKET (GuiShared.get().jitaSpace(), Images.LINK_JITA_SPACE.getIcon()){ @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int marketTypeID : menuData.getMarketTypeIDs()) { urls.add("https://www.jita.space/market/" + marketTypeID); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getMarketTypeIDs().isEmpty(); } }, EVECONOMY(GuiShared.get().eveconomy(), Images.LINK_EVECONOMY.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int marketTypeID : menuData.getMarketTypeIDs()) { urls.add("https://eveconomy.online/item/" + marketTypeID); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getMarketTypeIDs().isEmpty(); } }, //Info GAMES_CHRUKER(GuiShared.get().chruker(), Images.LINK_CHRUKER.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int typeID : menuData.getTypeIDs()) { urls.add("http://games.chruker.dk/eve_online/item.php?type_id=" + typeID); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getTypeIDs().isEmpty(); } }, EVE_INFO(GuiShared.get().eveInfo(), Images.LINK_EVEINFO.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int typeID : menuData.getTypeIDs()) { urls.add("https://eveinfo.com/item/" + typeID); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getTypeIDs().isEmpty(); } }, FUZZWORK_ITEMS(GuiShared.get().fuzzworkItems(), Images.LINK_FUZZWORK.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int typeID : menuData.getTypeIDs()) { urls.add("https://www.fuzzwork.co.uk/info/?typeid=" + typeID); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getTypeIDs().isEmpty(); } }, ZKILLBOARD_ITEM(GuiShared.get().zKillboard(), Images.LINK_ZKILLBOARD.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int typeID : menuData.getTypeIDs()) { urls.add("https://zkillboard.com/item/" + typeID + "/"); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getTypeIDs().isEmpty(); } }, EVE_REF(GuiShared.get().eveRef(), Images.LINK_EVE_REF.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int typeID : menuData.getTypeIDs()) { urls.add("https://everef.net/types/" + typeID + "?utm_source=jeveassets"); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getTypeIDs().isEmpty(); } }, JITA_SPACE_ITEM(GuiShared.get().jitaSpace(), Images.LINK_JITA_SPACE.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int typeID : menuData.getTypeIDs()) { urls.add("https://www.jita.space/type/" + typeID); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getTypeIDs().isEmpty(); } }, //Industry FUZZWORK_BLUEPRINTS(GuiShared.get().fuzzworkBlueprints(), Images.LINK_FUZZWORK.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int typeID : menuData.getBlueprintTypeIDs()) { urls.add("https://www.fuzzwork.co.uk/blueprint/?typeid=" + typeID); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getBlueprintTypeIDs().isEmpty(); } }, EVE_COOKBOOK(GuiShared.get().eveCookbook(), Images.LINK_EVE_COOKBOOK.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int typeID : menuData.getBlueprintTypeIDs()) { urls.add("https://evecookbook.com/?blueprintTypeId=" + typeID); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getBlueprintTypeIDs().isEmpty(); } }, //Corporation EVEMAPS_DOTLAN_CORPORATION(GuiShared.get().dotlan(), Images.LINK_DOTLAN_EVEMAPS.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (String corporationName : menuData.getCorporationNames()) { urls.add("https://evemaps.dotlan.net/npc/" + corporationName.replace(" ", "_")); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getCorporationNames().isEmpty(); } }, EVEMISSIONEER_CORPORATION(GuiShared.get().eveMissioneer(), Images.LINK_EVEMISSIONEER.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int corporationID : menuData.getCorporationIDs()) { urls.add("https://evemissioneer.com/co/" + corporationID); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getCorporationIDs().isEmpty(); } }, JITA_SPACE_CORPORATION(GuiShared.get().jitaSpace(), Images.LINK_JITA_SPACE.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int corporationID : menuData.getCorporationIDs()) { urls.add("https://www.jita.space/corporation/" + corporationID); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getCorporationNames().isEmpty(); } }, ZKILLBOARD_CORPORATION(GuiShared.get().zKillboard(), Images.LINK_ZKILLBOARD.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int corporationID : menuData.getCorporationIDs()) { urls.add("https://zkillboard.com/corporation/" + corporationID + "/"); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getCorporationNames().isEmpty(); } }, //Loyalty Points Store FUZZWORK_LP_SELL(GuiShared.get().fuzzworkLPSell(), Images.ORDERS_SELL.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int corporationID : menuData.getCorporationIDs()) { urls.add("https://www.fuzzwork.co.uk/lpstore/sell/10000002/" + corporationID + "/withblueprints"); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getCorporationIDs().isEmpty(); } }, FUZZWORK_LP_BUY(GuiShared.get().fuzzworkLPBuy(), Images.ORDERS_BUY.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int corporationID : menuData.getCorporationIDs()) { urls.add("https://www.fuzzwork.co.uk/lpstore/buy/10000002/" + corporationID + "/withblueprints"); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getCorporationIDs().isEmpty(); } }, JITA_SPACE_LP(GuiShared.get().jitaSpace(), Images.LINK_JITA_SPACE.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (String corporationName : menuData.getCorporationNames()) { urls.add("https://www.jita.space/lp-store/" + corporationName.replace(" ", "_")); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getCorporationNames().isEmpty(); } }, QUANTUM_ANOMALY_LP(GuiShared.get().quantumAnomaly(), Images.LINK_QUANTUM_ANOMALY.getIcon()) { @Override public Set getLinks(MenuData menuData) { Set urls = new HashSet<>(); for (int corporationID : menuData.getCorporationIDs()) { urls.add("https://www.qsna.eu/eve/loyalty-stores/" + corporationID + "/"); } return urls; } @Override public Boolean isEnabled(MenuData menuData) { return !menuData.getCorporationIDs().isEmpty(); } }; private final String title; private final Icon icon; private LookupLinks(String title, Icon icon) { this.title = title; this.icon = icon; } public abstract Set getLinks(MenuData menuData); public abstract Boolean isEnabled(MenuData menuData); public JMenuItem createMenuItem(ActionListener listener) { JMenuItem jMenuItem = new JMenuItem(title); jMenuItem.setIcon(icon); jMenuItem.setActionCommand(name()); jMenuItem.addActionListener(listener); return jMenuItem; } public void open(Program program, MenuData menuData) { DesktopUtil.browse(getLinks(menuData), program); } } private final JMenu jLocations; private final JMenu jzKillboard; private final JMenuItem jzKillboardLocations; private final JMenu jDotlan; private final JMenuItem jDotlanLocations; private final JMenu jEveMissioneer; private final JMenu jMarket; private final JMenu jItemDatabase; private final JMenu jIndustry; private final JMenu jCorporation; private final Map jMenuItems = new EnumMap<>(LookupLinks.class); public JMenuLookup(final Program program) { super(GuiShared.get().lookup(), program); ListenerClass listener = new ListenerClass(); this.setIcon(Images.LINK_LOOKUP.getIcon()); //Locations jLocations = new JMenu(GuiShared.get().location()); jLocations.setIcon(Images.LOC_LOCATIONS.getIcon()); add(jLocations); //zKillboard jzKillboard = new JMenu(GuiShared.get().zKillboard()); jzKillboard.setIcon(Images.LINK_ZKILLBOARD.getIcon()); jLocations.add(jzKillboard); add(jzKillboard, LookupLinks.ZKILLBOARD_SYSTEM, listener); add(jzKillboard, LookupLinks.ZKILLBOARD_CONSTELLATION, listener); add(jzKillboard, LookupLinks.ZKILLBOARD_REGION, listener); jzKillboardLocations = add(jzKillboard, LookupLinks.ZKILLBOARD_OVERVIEW_GROUP, listener); //Dotlan jDotlan = new JMenu(GuiShared.get().dotlan()); jDotlan.setIcon(Images.LINK_DOTLAN_EVEMAPS.getIcon()); jLocations.add(jDotlan); add(jDotlan, LookupLinks.EVEMAPS_DOTLAN_PLANET, listener); add(jDotlan, LookupLinks.EVEMAPS_DOTLAN_SYSTEM, listener); add(jDotlan, LookupLinks.EVEMAPS_DOTLAN_SYSTEM_REGION, listener); add(jDotlan, LookupLinks.EVEMAPS_DOTLAN_CONSTELLATION, listener); add(jDotlan, LookupLinks.EVEMAPS_DOTLAN_REGION, listener); jDotlanLocations = add(jDotlan, LookupLinks.EVEMAPS_DOTLAN_OVERVIEW_GROUP, listener); //EveMissioneer jEveMissioneer = new JMenu(GuiShared.get().eveMissioneer()); jEveMissioneer.setIcon(Images.LINK_EVEMISSIONEER.getIcon()); jLocations.add(jEveMissioneer); add(jEveMissioneer, LookupLinks.EVEMISSIONEER_SYSTEM, listener); add(jEveMissioneer, LookupLinks.EVEMISSIONEER_CONSTELLATION, listener); add(jEveMissioneer, LookupLinks.EVEMISSIONEER_REGION, listener); //Market jMarket = new JMenu(GuiShared.get().market()); jMarket.setIcon(Images.ORDERS_SELL.getIcon()); add(jMarket); add(jMarket, LookupLinks.FUZZWORK_MARKET, listener); add(jMarket, LookupLinks.EVE_TYCOON, listener); add(jMarket, LookupLinks.ADAM4EVE, listener); add(jMarket, LookupLinks.EVE_MARKET_BROWSER, listener); add(jMarket, LookupLinks.JITA_SPACE_MARKET, listener); add(jMarket, LookupLinks.EVECONOMY, listener); //Items jItemDatabase = new JMenu(GuiShared.get().itemDatabase()); jItemDatabase.setIcon(Images.TOOL_ASSETS.getIcon()); add(jItemDatabase); add(jItemDatabase, LookupLinks.GAMES_CHRUKER, listener); add(jItemDatabase, LookupLinks.EVE_INFO, listener); add(jItemDatabase, LookupLinks.FUZZWORK_ITEMS, listener); add(jItemDatabase, LookupLinks.ZKILLBOARD_ITEM, listener); add(jItemDatabase, LookupLinks.EVE_REF, listener); add(jItemDatabase, LookupLinks.JITA_SPACE_ITEM, listener); //Industry jIndustry = new JMenu(GuiShared.get().industry()); jIndustry.setIcon(Images.TOOL_INDUSTRY_JOBS.getIcon()); add(jIndustry); add(jIndustry, LookupLinks.FUZZWORK_BLUEPRINTS, listener); //Other add(jIndustry, LookupLinks.EVE_COOKBOOK, listener); //Corporation jCorporation = new JMenu(GuiShared.get().corporation()); jCorporation.setIcon(Images.LINK_LOOKUP.getIcon()); add(jCorporation); add(jCorporation, LookupLinks.EVEMAPS_DOTLAN_CORPORATION, listener); add(jCorporation, LookupLinks.EVEMISSIONEER_CORPORATION, listener); add(jCorporation, LookupLinks.JITA_SPACE_CORPORATION, listener); add(jCorporation, LookupLinks.ZKILLBOARD_CORPORATION, listener); JMenu jLoyaltyPointsStore = new JMenu(GuiShared.get().loyaltyPointsStore()); jLoyaltyPointsStore.setIcon(Images.TOOL_LOYALTY_POINTS.getIcon()); jCorporation.add(jLoyaltyPointsStore); JMenu jFuzzwork = new JMenu(GuiShared.get().fuzzworkLP()); jFuzzwork.setIcon(Images.LINK_FUZZWORK.getIcon()); jLoyaltyPointsStore.add(jFuzzwork); add(jFuzzwork, LookupLinks.FUZZWORK_LP_SELL, listener); add(jFuzzwork, LookupLinks.FUZZWORK_LP_BUY, listener); add(jLoyaltyPointsStore, LookupLinks.JITA_SPACE_LP, listener); add(jLoyaltyPointsStore, LookupLinks.QUANTUM_ANOMALY_LP, listener); } @Override public void updateMenuData() { for (Map.Entry entry : jMenuItems.entrySet()) { Boolean enabled = entry.getKey().isEnabled(menuData); if (enabled != null) { entry.getValue().setEnabled(enabled); } } //Location jLocations.setEnabled(!menuData.getStationNames().isEmpty() || !menuData.getSystemNames().isEmpty() || !menuData.getRegionNames().isEmpty()); //Market jMarket.setEnabled(!menuData.getMarketTypeIDs().isEmpty()); //Info jItemDatabase.setEnabled(!menuData.getTypeIDs().isEmpty()); //Industry jIndustry.setEnabled(!menuData.getBlueprintTypeIDs().isEmpty()); //Corporation jCorporation.setEnabled(!menuData.getCorporationNames().isEmpty() || !menuData.getCorporationIDs().isEmpty()); } public void setTool(Object object) { if (object instanceof OverviewTableMenu) { OverviewTab overviewTab = ((OverviewTableMenu)object).getOverviewTab(); boolean enabled = overviewTab.isGroupAndNotEmpty(); jDotlanLocations.setEnabled(enabled); jDotlan.add(jDotlanLocations); jzKillboardLocations.setEnabled(enabled); jzKillboard.add(jzKillboardLocations); jLocations.setEnabled(enabled || !overviewTab.isGroup()); } else { jDotlan.remove(jDotlanLocations); jzKillboard.remove(jzKillboardLocations); } } private JMenuItem add(JMenu jMenu, LookupLinks lookupLinks, ListenerClass listener) { JMenuItem jMenuItem = lookupLinks.createMenuItem(listener); jMenuItems.put(lookupLinks, jMenuItem); jMenu.add(jMenuItem); return jMenuItem; } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { //Locations try { LookupLinks links = LookupLinks.valueOf(e.getActionCommand()); links.open(program, menuData); } catch (IllegalArgumentException ex) { //Ignore this } } } public static String replaceLast(String string, String toReplace, String replacement) { int pos = string.lastIndexOf(toReplace); if (pos > -1) { return string.substring(0, pos) + replacement + string.substring(pos + toReplace.length(), string.length()); } else { return string; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuName.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.gui.dialogs.settings.UserNameSettingsPanel.UserName; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JSelectionDialog; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.JAutoMenu; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JMenuName extends JAutoMenu { private enum MenuNameAction { EDIT_NAME, DELETE_NAME, EDIT_CONTAINER, DELETE_CONTAINERS } private List> itemNames; private List> containerNames; private MyAsset selected; private final JMenuItem jEditItem; private final JMenuItem jResetItem; private final JMenuItem jEditContainer; private final JMenuItem jResetContainer; private final JSelectionDialog jContainerDialog; public JMenuName(final Program program) { super(GuiShared.get().itemNameTitle(), program); this.setIcon(Images.SETTINGS_USER_NAME.getIcon()); ListenerClass listener = new ListenerClass(); jContainerDialog = new JSelectionDialog<>(program); jEditItem = new JMenuItem(GuiShared.get().itemEdit()); jEditItem.setIcon(Images.EDIT_EDIT.getIcon()); jEditItem.setActionCommand(MenuNameAction.EDIT_NAME.name()); jEditItem.addActionListener(listener); add(jEditItem); jResetItem = new JMenuItem(GuiShared.get().itemDelete()); jResetItem.setIcon(Images.EDIT_DELETE.getIcon()); jResetItem.setActionCommand(MenuNameAction.DELETE_NAME.name()); jResetItem.addActionListener(listener); add(jResetItem); addSeparator(); jEditContainer = new JMenuItem(GuiShared.get().containerEdit()); jEditContainer.setIcon(Images.EDIT_EDIT.getIcon()); jEditContainer.setActionCommand(MenuNameAction.EDIT_CONTAINER.name()); jEditContainer.addActionListener(listener); add(jEditContainer); jResetContainer = new JMenuItem(GuiShared.get().containerDelete()); jResetContainer.setIcon(Images.EDIT_DELETE.getIcon()); jResetContainer.setActionCommand(MenuNameAction.DELETE_CONTAINERS.name()); jResetContainer.addActionListener(listener); add(jResetContainer); } @Override public void updateMenuData() { itemNames = new ArrayList<>(); containerNames = new ArrayList<>(); for (MyAsset asset : menuData.getAssets()) { if (asset.getOwner() == null) { continue; //Ignore TreeAsset for Location/Group/Category } itemNames.add(new UserName(asset)); for (MyAsset parent : asset.getParents()) { containerNames.add(new UserName(parent)); } } jEditItem.setEnabled(itemNames.size() == 1); jResetItem.setEnabled(program.getUserNameSettingsPanel() != null && program.getUserNameSettingsPanel().contains(itemNames)); jEditContainer.setEnabled(menuData.getAssets().size() == 1 && !menuData.getAssets().get(0).getParents().isEmpty()); jResetContainer.setEnabled(program.getUserNameSettingsPanel() != null && program.getUserNameSettingsPanel().contains(containerNames)); if (menuData.getAssets().size() == 1) { selected = menuData.getAssets().get(0); } else { selected = null; } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (MenuNameAction.EDIT_NAME.name().equals(e.getActionCommand())) { program.getUserNameSettingsPanel().edit(itemNames.get(0)); } if (MenuNameAction.DELETE_NAME.name().equals(e.getActionCommand())) { program.getUserNameSettingsPanel().delete(itemNames); } if (MenuNameAction.EDIT_CONTAINER.name().equals(e.getActionCommand())) { if (selected != null) { MyAsset value = jContainerDialog.show(GuiShared.get().containerText(), selected.getParents()); if (value != null) { program.getUserNameSettingsPanel().edit(new UserName(value)); } } } if (MenuNameAction.DELETE_CONTAINERS.name().equals(e.getActionCommand())) { program.getUserNameSettingsPanel().delete(containerNames); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuPrice.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.gui.dialogs.settings.UserPriceSettingsPanel.UserPrice; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.JAutoMenu; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class JMenuPrice extends JAutoMenu { private static final Logger LOG = LoggerFactory.getLogger(JMenuPrice.class); private enum MenuPriceAction { EDIT, DELETE } private final JMenuItem jEdit; private final JMenuItem jReset; public JMenuPrice(final Program program) { super(GuiShared.get().itemPriceTitle(), program); // this.setIcon(Images.SETTINGS_USER_PRICE.getIcon()); ListenerClass listener =new ListenerClass(); jEdit = new JMenuItem(GuiShared.get().itemEdit()); jEdit.setIcon(Images.EDIT_EDIT.getIcon()); jEdit.setActionCommand(MenuPriceAction.EDIT.name()); jEdit.addActionListener(listener); add(jEdit); jReset = new JMenuItem(GuiShared.get().itemDelete()); jReset.setIcon(Images.EDIT_DELETE.getIcon()); jReset.setActionCommand(MenuPriceAction.DELETE.name()); jReset.addActionListener(listener); add(jReset); } @Override public void updateMenuData() { jEdit.setEnabled(!menuData.getPrices().isEmpty()); jReset.setEnabled(!menuData.getPrices().isEmpty() && program.getUserPriceSettingsPanel().containsKey(menuData.getPrices().keySet())); } private List> createList() { List> itemPrices = new ArrayList<>(); for (Map.Entry entry : menuData.getPrices().entrySet()) { Item item = ApiIdConverter.getItem(Math.abs(entry.getKey())); String name = ""; if (!item.isEmpty()) { if (item.isBlueprint()) { //Blueprint if (entry.getKey() < 0) { //Copy name = item.getTypeName() + " (BPC)"; } else { //Original name = item.getTypeName() + " (BPO)"; } } else { //Not blueprint name = item.getTypeName(); } } itemPrices.add(new UserPrice(entry.getValue(), entry.getKey(), name)); } return itemPrices; } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (MenuPriceAction.EDIT.name().equals(e.getActionCommand())) { if (!menuData.getBpcTypeIDs().isEmpty() && !menuData.getPrices().isEmpty() && !menuData.getTypeNames().isEmpty()) { program.getUserPriceSettingsPanel().edit(createList()); } } else if (MenuPriceAction.DELETE.name().equals(e.getActionCommand())) { if (!menuData.getBpcTypeIDs().isEmpty() && !menuData.getPrices().isEmpty() && !menuData.getTypeNames().isEmpty()) { program.getUserPriceSettingsPanel().delete(createList()); } } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuPriceHistory.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.JAutoMenu; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceHistoryTab; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JMenuPriceHistory extends JAutoMenu { private enum MenuPriceHistoryAction { ADD, SET } private final JMenuItem jAdd; private final JMenuItem jSet; public JMenuPriceHistory(Program program) { super(GuiShared.get().priceHistory(), program); this.setIcon(Images.TOOL_PRICE_HISTORY.getIcon()); ListenerClass listener =new ListenerClass(); jAdd = new JMenuItem(GuiShared.get().add()); jAdd.setIcon(Images.EDIT_ADD.getIcon()); jAdd.setActionCommand(MenuPriceHistoryAction.ADD.name()); jAdd.addActionListener(listener); add(jAdd); jSet = new JMenuItem(GuiShared.get().set()); jSet.setIcon(Images.EDIT_SET.getIcon()); jSet.setActionCommand(MenuPriceHistoryAction.SET.name()); jSet.addActionListener(listener); add(jSet); } @Override protected void updateMenuData() { jAdd.setEnabled(!menuData.getTypeIDs().isEmpty()); jSet.setEnabled(!menuData.getTypeIDs().isEmpty()); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (MenuPriceHistoryAction.ADD.name().equals(e.getActionCommand())) { PriceHistoryTab priceHistoryTab = program.getPriceHistoryTab(true); program.getMainWindow().addTab(priceHistoryTab); priceHistoryTab.addItems(menuData.getTypeIDs()); } else if (MenuPriceHistoryAction.SET.name().equals(e.getActionCommand())) { PriceHistoryTab priceHistoryTab = program.getPriceHistoryTab(true); program.getMainWindow().addTab(priceHistoryTab); priceHistoryTab.setItems(menuData.getTypeIDs()); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuReprocessed.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.HashMap; import java.util.Map; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.JAutoMenu; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedTab; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JMenuReprocessed extends JAutoMenu { private enum MenuReprocessedAction { ADD, SET } private final JMenuItem jAdd; private final JMenuItem jSet; private final Map items = new HashMap<>(); public JMenuReprocessed(final Program program) { super(GuiShared.get().reprocessed(), program); setIcon(Images.TOOL_REPROCESSED.getIcon()); ListenerClass listener = new ListenerClass(); jAdd = new JMenuItem(GuiShared.get().add()); jAdd.setIcon(Images.EDIT_ADD.getIcon()); jAdd.setActionCommand(MenuReprocessedAction.ADD.name()); jAdd.addActionListener(listener); add(jAdd); jSet = new JMenuItem(GuiShared.get().set()); jSet.setIcon(Images.EDIT_SET.getIcon()); jSet.setActionCommand(MenuReprocessedAction.SET.name()); jSet.addActionListener(listener); add(jSet); } @Override public void updateMenuData() { items.clear(); for (Map.Entry entry : menuData.getItemCounts().entrySet()) { if (!entry.getKey().getReprocessedMaterial().isEmpty()) { items.put(entry.getKey(), entry.getValue()); } } jAdd.setEnabled(!items.isEmpty()); jSet.setEnabled(!items.isEmpty()); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(ActionEvent e) { if (MenuReprocessedAction.ADD.name().equals(e.getActionCommand())) { ReprocessedTab reprocessedTab = program.getReprocessedTab(true); reprocessedTab.add(items); reprocessedTab.show(); } if (MenuReprocessedAction.SET.name().equals(e.getActionCommand())) { ReprocessedTab reprocessedTab = program.getReprocessedTab(true); reprocessedTab.set(items); reprocessedTab.show(); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuRouting.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collections; import java.util.Set; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.tabs.routing.RoutingTab; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JMenuRouting extends MenuManager.JAutoMenu { private enum MenuRoutingAction { SYSTEM, STATION } private final JMenuItem jSystem; private final JMenuItem jStation; public JMenuRouting(Program program) { super(GuiShared.get().routing(), program); this.setIcon(Images.TOOL_ROUTING.getIcon()); ListenerClass listener = new ListenerClass(); jStation = new JMenuItem(GuiShared.get().uiStation()); jStation.setIcon(Images.LOC_STATION.getIcon()); jStation.setActionCommand(MenuRoutingAction.STATION.name()); jStation.addActionListener(listener); add(jStation); jSystem = new JMenuItem(GuiShared.get().uiSystem()); jSystem.setIcon(Images.LOC_SYSTEM.getIcon()); jSystem.setActionCommand(MenuRoutingAction.SYSTEM.name()); jSystem.addActionListener(listener); add(jSystem); } @Override public void updateMenuData() { jStation.setEnabled(!menuData.getAutopilotStationLocations().isEmpty() && menuData.getContracts().size() <= 1); jSystem.setEnabled(!menuData.getSystemLocations().isEmpty() && menuData.getContracts().size() <= 1); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (MenuRoutingAction.STATION.name().equals(e.getActionCommand())) { Set locations; if (menuData.getContracts().size() == 1) { MyLocation station = JMenuUI.selectLocation(program, menuData.getAutopilotStationLocations()); if (station == null) { return; } locations = Collections.singleton(station); } else { locations = menuData.getAutopilotStationLocations(); } RoutingTab routingTab = program.getRoutingTab(true); program.getMainWindow().addTab(routingTab); for (MyLocation location : locations) { routingTab.addLocation(location); } } else if (MenuRoutingAction.SYSTEM.name().equals(e.getActionCommand())) { Set locations; if (menuData.getContracts().size() == 1) { MyLocation system = JMenuUI.selectLocation(program, menuData.getSystemLocations()); if (system == null) { return; } locations = Collections.singleton(system); } else { locations = menuData.getSystemLocations(); } RoutingTab routingTab = program.getRoutingTab(true); program.getMainWindow().addTab(routingTab); for (MyLocation location : locations) { routingTab.addLocation(location); } } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuStockpile.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.IndustryMaterial; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.MenuScroller; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.JAutoMenu; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileBpDialog; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileBpDialog.BpData; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileTab; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.i18n.TabsStockpile; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class JMenuStockpile extends JAutoMenu { private enum MenuStockpileAction { ADD_TO } private static StockpileBpDialog stockpileBpDialog = null; private final JMenuItem jAddToNew; ListenerClass listener = new ListenerClass(); public JMenuStockpile(final Program program) { super(GuiShared.get().stockpile(), program); this.setIcon(Images.TOOL_STOCKPILE.getIcon()); MenuScroller menuScroller = new MenuScroller(this); menuScroller.keepVisible(2); menuScroller.setTopFixedCount(2); menuScroller.setInterval(125); jAddToNew = new JStockpileMenu(GuiShared.get().newStockpile()); jAddToNew.setIcon(Images.EDIT_ADD.getIcon()); jAddToNew.setActionCommand(MenuStockpileAction.ADD_TO.name()); jAddToNew.addActionListener(listener); } @Override public void updateMenuData() { List stockpiles = StockpileTab.getShownStockpiles(program); boolean enabled = !menuData.getTypeIDs().isEmpty(); removeAll(); jAddToNew.setEnabled(enabled); add(jAddToNew); //Add "To new Stockpile" if (!stockpiles.isEmpty()) { //Add Separator (if we have stockpiles) addSeparator(); } for (Stockpile stockpile : stockpiles) { //Create menu items JMenuItem jMenuItem = new JStockpileMenu(stockpile); jMenuItem.setIcon(Images.TOOL_STOCKPILE.getIcon()); jMenuItem.setActionCommand(MenuStockpileAction.ADD_TO.name()); jMenuItem.addActionListener(listener); jMenuItem.setEnabled(enabled); add(jMenuItem); } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (MenuStockpileAction.ADD_TO.name().equals(e.getActionCommand())) { Object source = e.getSource(); if (source instanceof JStockpileMenu) { JStockpileMenu jStockpileMenu = (JStockpileMenu) source; Stockpile stockpile = jStockpileMenu.getStockpile(); List items = toStockpileItems(program, stockpile, menuData.getTypeIDs(), menuData.getCounts(), menuData.getRuns(), true); if (items == null) { return; //Cancel } StockpileTab stockpileTab = program.getStockpileTab(true); stockpile = stockpileTab.addToStockpile(stockpile, items, true, true); if (stockpile != null) { program.getMainWindow().addTab(stockpileTab, Settings.get().isStockpileFocusTab()); if (Settings.get().isStockpileFocusTab()) { stockpileTab.scrollToSctockpile(stockpile); //Updated when other tools gain focus } else { program.updateTableMenu(); //Needs update (to include new stockpile) } } } } } } public static BpOptions selectBpImportOptions(Program program, Collection typeIDs, boolean source) { BpData blueprintSelect = null; BpData formulaSelect = null; for (int typeID : typeIDs) { Item item = ApiIdConverter.getItem(Math.abs(typeID)); if (item.isBlueprint() && blueprintSelect == null) { blueprintSelect = getBlueprintSelect(program, source); if (blueprintSelect == null) { return null; //Cancel } } if (item.getItem().isFormula() && formulaSelect == null) { formulaSelect = getFormulaSelect(program); if (formulaSelect == null) { return null; //Cancel } } } return new BpOptions(blueprintSelect, formulaSelect); } public static List toStockpileItems(Program program, BpOptions bpOptions, Stockpile stockpile, Collection typeIDs, Map counts, Map runs) { return toStockpileItems(program, bpOptions.getBlueprintSelect(), bpOptions.getFormulaSelect(), stockpile, typeIDs, counts, runs, false); } public static List toStockpileItems(Program program, Stockpile stockpile, Collection typeIDs, Map counts, Map runs, boolean source) { return toStockpileItems(program, null, null, stockpile, typeIDs, counts, runs, source); } private static List toStockpileItems(Program program, BpData blueprintSelect, BpData formulaSelect, Stockpile stockpile, Collection typeIDs, Map counts, Map runs, boolean source) { List items = new ArrayList<>(); for (int typeID : typeIDs) { Item item = ApiIdConverter.getItem(Math.abs(typeID)); if (item.isBlueprint() && blueprintSelect == null) { blueprintSelect = getBlueprintSelect(program, source); if (blueprintSelect == null) { return null; //Cancel } } if (item.isFormula() && formulaSelect == null) { formulaSelect = getFormulaSelect(program); if (formulaSelect == null) { return null; //Cancel } } if (match(item, blueprintSelect, formulaSelect, TabsStockpile.get().original())) { //PBO items.add(new StockpileItem(stockpile, item, Math.abs(typeID), total(counts, typeID), false)); } else if (match(item, blueprintSelect, null, TabsStockpile.get().copy())) { //BPC items.add(new StockpileItem(stockpile, item, -Math.abs(typeID), total(counts, typeID), false)); } else if (match(item, blueprintSelect, null, TabsStockpile.get().runs())) { //BPC Runs items.add(new StockpileItem(stockpile, item, -Math.abs(typeID), runs(counts, runs, typeID), true)); } else if (match(item, blueprintSelect, null, TabsStockpile.get().materialsManufacturing())) { //BP Materials for (IndustryMaterial material : item.getManufacturingMaterials()) { double count = blueprintSelect.doMath(material.getQuantity(), total(counts, typeID)); Item materialItem = ApiIdConverter.getItem(material.getTypeID()); items.add(new StockpileItem(stockpile, materialItem, material.getTypeID(), count, false)); } } else if (match(item, null, formulaSelect, TabsStockpile.get().materialsReaction())) { //Reaction Materials for (IndustryMaterial material : item.getReactionMaterials()) { Item materialItem = ApiIdConverter.getItem(material.getTypeID()); double count = formulaSelect.doMath(material.getQuantity(), total(counts, typeID)); items.add(new StockpileItem(stockpile, materialItem, material.getTypeID(), count, false)); } } else { //source or not bluepint/formula //PBO or not BP Double count = counts.get(Math.abs(typeID)); if (count != null) { items.add(new StockpileItem(stockpile, item, Math.abs(typeID), count, false)); } //BPC Double bpc = counts.get(-Math.abs(typeID)); if (bpc != null) { items.add(new StockpileItem(stockpile, item, -Math.abs(typeID), bpc, false)); } } } return items; } public static BpData getBlueprintSelect(Program program, boolean source) { String[] sources = {TabsStockpile.get().source(), TabsStockpile.get().original(), TabsStockpile.get().copy(), TabsStockpile.get().runs(), TabsStockpile.get().materialsManufacturing()}; String[] options = {TabsStockpile.get().original(), TabsStockpile.get().copy(), TabsStockpile.get().runs(), TabsStockpile.get().materialsManufacturing()}; if (stockpileBpDialog == null) { stockpileBpDialog = new StockpileBpDialog(program); } return stockpileBpDialog.show(TabsStockpile.get().addBlueprintTitle(), TabsStockpile.get().addBlueprintMsg(), source ? sources : options); } public static BpData getFormulaSelect(Program program) { String[] options = {TabsStockpile.get().original(), TabsStockpile.get().materialsReaction()}; if (stockpileBpDialog == null) { stockpileBpDialog = new StockpileBpDialog(program); } return stockpileBpDialog.show(TabsStockpile.get().addFormulaTitle(), TabsStockpile.get().addFormulaMsg(), options); } public static boolean match(Item item, BpData blueprintSelect, BpData formulaSelect, String match) { return (item.isBlueprint() && blueprintSelect != null && blueprintSelect.matches(match)) || (item.isFormula() && formulaSelect != null && formulaSelect.matches(match)); } private static double runs(Map counts, Map runs, int typeID) { Double bpc = runs.get(-Math.abs(typeID)); //PBC Runs if (bpc == null) { //If no runs data, use count instead bpc = runs.getOrDefault(-Math.abs(typeID), 0.0); //BPC count } //Else use count return bpc + counts.getOrDefault(Math.abs(typeID), 0.0); //BPO } private static double total(Map counts, int typeID) { return counts.getOrDefault(Math.abs(typeID), 0.0) //PBOs + counts.getOrDefault(-Math.abs(typeID), 0.0); //BPCs } public static class JStockpileMenu extends JMenuItem { private final Stockpile stockpile; public JStockpileMenu(final String text) { super(text); this.stockpile = null; } public JStockpileMenu(final Stockpile stockpile) { super(stockpile.getName()); this.stockpile = stockpile; } public Stockpile getStockpile() { return stockpile; } } public static class BpOptions { private final BpData blueprintSelect; private final BpData formulaSelect; public BpOptions(BpData blueprintSelect, BpData formulaSelect) { this.blueprintSelect = blueprintSelect; this.formulaSelect = formulaSelect; } public BpData getBlueprintSelect() { return blueprintSelect; } public BpData getFormulaSelect() { return formulaSelect; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuSum.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.JTable; import javax.swing.SwingConstants; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.AutoNumberFormat; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.MenuItemValue; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.JAutoMenuComponent; import net.nikr.eve.jeveasset.gui.shared.table.containers.NumberValue; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JMenuSum extends JAutoMenuComponent { private final JTable jTable; private final Collection menuItems = new ArrayList<>(); public JMenuSum(final Program program, final JTable jTable) { super(program); this.jTable = jTable; } @Override public Collection getMenuItems() { return menuItems; } public void updateMenuDataColumn(int column) { Sum sum = new Sum(); for (int row = 0; row < jTable.getRowCount(); row++) { sum.add(jTable.getValueAt(row, column)); } show(sum, true); } @Override public void updateMenuData() { Sum sum = new Sum(); for (int row : jTable.getSelectedRows()) { for (int column : jTable.getSelectedColumns()) { sum.add(jTable.getValueAt(row, column)); } } show(sum, false); } private void show(Sum sum, boolean column) { menuItems.clear(); JMenuItem jTitle = new JMenuItem(); final String title; final String toolTip; if (column) { title = GuiShared.get().cellInformationColumn(); toolTip = GuiShared.get().cellInformationColumnToolTip(); } else { title = GuiShared.get().cellInformation(); toolTip = GuiShared.get().cellInformationToolTip(); } List values = JMenuInfo.createDefault(null, jTitle, title, toolTip, Images.MISC_INFO.getIcon()); menuItems.add(jTitle); menuItems.add(createMenuItem(values, sum.getSum(), GuiShared.get().cellSum(), GuiShared.get().cellSumToolTip(), Images.MISC_SUM.getIcon())); menuItems.add(createMenuItem(values, sum.getCount(), GuiShared.get().cellCount(), GuiShared.get().cellCountToolTip(), Images.MISC_COUNT.getIcon())); menuItems.add(createMenuItem(values, sum.getAvg(), GuiShared.get().cellAverage(), GuiShared.get().cellAverageToolTip(), Images.MISC_AVG.getIcon())); menuItems.add(createMenuItem(values, sum.getMax(), GuiShared.get().cellMaximum(), GuiShared.get().cellMaximumToolTip(), Images.MISC_MAX.getIcon())); menuItems.add(createMenuItem(values, sum.getMin(), GuiShared.get().cellMinimum(), GuiShared.get().cellMinimumToolTip(), Images.MISC_MIN.getIcon())); } private JMenuItem createMenuItem(List values, BigDecimal bigDecimal, String copyText, String toolTip, Icon icon) { if (bigDecimal != null) { double doubleValue = bigDecimal.doubleValue(); AutoNumberFormat format; if (doubleValue % 1 == 0) { format = AutoNumberFormat.LONG; } else { format = AutoNumberFormat.DOUBLE; } return JMenuInfo.createMenuItem(values, null, bigDecimal.doubleValue(), format, toolTip, copyText, icon); } else { return createEmptyMenuItem(toolTip, icon); } } private JMenuItem createEmptyMenuItem(String toolTip, Icon icon) { JMenuItem jMenuItem = new JMenuItem(GuiShared.get().none()); jMenuItem.setToolTipText(toolTip); jMenuItem.setEnabled(false); jMenuItem.setDisabledIcon(icon); jMenuItem.setHorizontalAlignment(SwingConstants.RIGHT); return jMenuItem; } private static class Sum { private BigDecimal sum = null; private BigDecimal count = null; private BigDecimal max = null; private BigDecimal min = null; public void add(Object value) { if (value instanceof Double) { add(new BigDecimal((Double)value)); } else if (value instanceof Float) { add(new BigDecimal((Float)value)); } else if (value instanceof Long) { add(new BigDecimal((Long)value)); } else if (value instanceof Integer) { add(new BigDecimal((Integer)value)); } else if (value instanceof NumberValue) { NumberValue numberValue = (NumberValue) value; if (numberValue.getDouble() != null) { add(new BigDecimal(numberValue.getDouble())); } else if (numberValue.getLong() != null) { add(new BigDecimal(numberValue.getLong())); } } } private void add(BigDecimal value) { if (sum == null) { sum = value; } else { sum = sum.add(value); } if (count == null) { count = new BigDecimal(0); } count = count.add(BigDecimal.ONE); if (max == null) { max = value; } else { max = max.max(value); } if (min == null) { min = value; } else { min = min.min(value); } } public boolean isEmpty(BigDecimal bigDecimal) { return bigDecimal == null || bigDecimal.compareTo(BigDecimal.ZERO) == 0; } public BigDecimal getSum() { return sum; } public BigDecimal getCount() { return count; } public BigDecimal getAvg() { if (isEmpty(sum) || isEmpty(count)) { return null; } else { return sum.divide(count, 2, RoundingMode.HALF_UP); } } public BigDecimal getMax() { return max; } public BigDecimal getMin() { return min; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuTags.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import ca.odell.glazedlists.GlazedLists; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.tag.Tag; import net.nikr.eve.jeveasset.data.settings.types.TagsType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.MenuScroller; import net.nikr.eve.jeveasset.gui.shared.menu.JTagsDialog.TagIcon; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.JAutoMenu; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JMenuTags extends JAutoMenu { private enum TagsAction { ACTION_NEW_TAG, } private final JMenuItem jNew; private final ListenerClass listener = new ListenerClass(); private final JTagsDialog jTagsDialog; private List tagsTypes = new ArrayList<>(); public JMenuTags(Program program) { super(GuiShared.get().tags(), program); setIcon(Images.TAG_GRAY.getIcon()); MenuScroller menuScroller = new MenuScroller(this); menuScroller.keepVisible(2); menuScroller.setTopFixedCount(2); menuScroller.setInterval(125); jTagsDialog = new JTagsDialog(program); jNew = new JMenuItem(GuiShared.get().tagsNew(), Images.EDIT_ADD.getIcon()); jNew.setActionCommand(TagsAction.ACTION_NEW_TAG.name()); jNew.addActionListener(listener); } @Override public void updateMenuData() { tagsTypes = menuData.getTags(); boolean valid = !tagsTypes.isEmpty(); removeAll(); //Add New add(jNew); jNew.setEnabled(valid); //All Tags Set allTags = new TreeSet<>(GlazedLists.comparableComparator()); allTags.addAll(Settings.get().getTags().values()); //Separator if (!allTags.isEmpty()) { addSeparator(); } //Add To JCheckBoxMenuItem jCheckMenuItem; for (Tag tag : allTags) { Integer count = menuData.getTagCount().get(tag); if (count == null) { count = 0; } boolean selected = count == tagsTypes.size() && valid; if (selected) { count = 0; } jCheckMenuItem = new JTagCheckMenuItem(tag, count); if (selected) { jCheckMenuItem.setIcon(new TagIcon(tag.getColor(), true)); } else { jCheckMenuItem.setIcon(new TagIcon(tag.getColor())); } jCheckMenuItem.addActionListener(listener); jCheckMenuItem.setSelected(selected); jCheckMenuItem.setEnabled(valid); add(jCheckMenuItem); } } private void addTag(Tag tag) { if (tag != null && !tag.getName().isEmpty()) { Settings.lock("Tags (New)"); //Lock for Tags (New) Tag settingsTag = Settings.get().getTags().get(tag.getName()); if (settingsTag != null) { //Update //Load tag tag = settingsTag; } else { //Add new Settings.get().getTags().put(tag.getName(), tag); } for (TagsType tagsType : tagsTypes) { //Add tag to item tagsType.getTags().add(tag); //Add ID to tag tag.getIDs().add(tagsType.getTagID()); //Update settings Settings.get().getTags(tagsType.getTagID()).add(tag); } Settings.unlock("Tags (New)"); //Unlock for Tags (New) program.updateTags(); program.saveSettings("Tags (New)"); //Save Tags (New) } } private void removeTag(Tag tag) { if (tag != null) { Settings.lock("Tags (Delete)"); //Lock for Tags (Delete) for (TagsType tagsType : tagsTypes) { //Remove tag form item tagsType.getTags().remove(tag); //Remove ID from tag tag.getIDs().remove(tagsType.getTagID()); //Update settings Settings.get().getTags(tagsType.getTagID()).remove(tag); } Settings.unlock("Tags (Delete)"); //Unlock for Tags (Delete) program.updateTags(); program.saveSettings("Tags (Delete)"); //Save Tags (Delete) } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(ActionEvent e) { Object object = e.getSource(); if (object instanceof JTagCheckMenuItem) { JTagCheckMenuItem jCheckBoxMenuItem = (JTagCheckMenuItem) object; Tag tag = jCheckBoxMenuItem.getTag(); if (!jCheckBoxMenuItem.isSelected()) { //State change before this is called removeTag(tag); } else { addTag(tag); } } else if (TagsAction.ACTION_NEW_TAG.name().equals(e.getActionCommand())) { Tag tag = jTagsDialog.show(); addTag(tag); } } } private static class JTagCheckMenuItem extends JCheckBoxMenuItem { private final Tag tag; public JTagCheckMenuItem(Tag tag, Integer count) { super(GuiShared.get().tagsName(tag.getName(), count)); this.tag = tag; } public Tag getTag() { return tag; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuTransactionFilter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import java.util.Set; import javax.swing.JMenuItem; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.CompareType; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.LogicType; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.JAutoMenu; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewGroup; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewLocation; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab.OverviewTableMenu; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTab; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTableFormat; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.i18n.TabsOverview; public class JMenuTransactionFilter extends JAutoMenu { private enum MenuTransactionFilterAction { STATION_FILTER, PLANET_FILTER, SYSTEM_FILTER, CONSTELLATION_FILTER, REGION_FILTER, OVERVIEW_GROUP_FILTER, ITEM_TYPE_FILTER } private final JMenuItem jTypeID; private final JMenuItem jPlanet; private final JMenuItem jStation; private final JMenuItem jSystem; private final JMenuItem jConstellation; private final JMenuItem jRegion; private final JMenuItem jLocations; public JMenuTransactionFilter(final Program program) { super(GuiShared.get().addTransactionFilter(), program); ListenerClass listener = new ListenerClass(); this.setIcon(Images.TOOL_TRANSACTION.getIcon()); jTypeID = new JMenuItem(GuiShared.get().item()); jTypeID.setIcon(Images.EDIT_ADD.getIcon()); jTypeID.setActionCommand(MenuTransactionFilterAction.ITEM_TYPE_FILTER.name()); jTypeID.addActionListener(listener); add(jTypeID); addSeparator(); jStation = new JMenuItem(GuiShared.get().station()); jStation.setIcon(Images.LOC_STATION.getIcon()); jStation.setActionCommand(MenuTransactionFilterAction.STATION_FILTER.name()); jStation.addActionListener(listener); add(jStation); jPlanet = new JMenuItem(GuiShared.get().planet()); jPlanet.setIcon(Images.LOC_PLANET.getIcon()); jPlanet.setActionCommand(MenuTransactionFilterAction.PLANET_FILTER.name()); jPlanet.addActionListener(listener); add(jPlanet); jSystem = new JMenuItem(GuiShared.get().system()); jSystem.setIcon(Images.LOC_SYSTEM.getIcon()); jSystem.setActionCommand(MenuTransactionFilterAction.SYSTEM_FILTER.name()); jSystem.addActionListener(listener); add(jSystem); jConstellation = new JMenuItem(GuiShared.get().constellation()); jConstellation.setIcon(Images.LOC_CONSTELLATION.getIcon()); jConstellation.setActionCommand(MenuTransactionFilterAction.CONSTELLATION_FILTER.name()); jConstellation.addActionListener(listener); add(jConstellation); jRegion = new JMenuItem(GuiShared.get().region()); jRegion.setIcon(Images.LOC_REGION.getIcon()); jRegion.setActionCommand(MenuTransactionFilterAction.REGION_FILTER.name()); jRegion.addActionListener(listener); add(jRegion); jLocations = new JMenuItem(TabsOverview.get().locations()); jLocations.setIcon(Images.LOC_LOCATIONS.getIcon()); jLocations.setActionCommand(MenuTransactionFilterAction.OVERVIEW_GROUP_FILTER.name()); jLocations.addActionListener(listener); } @Override public void updateMenuData() { jTypeID.setEnabled(!menuData.getTypeIDs().isEmpty()); jStation.setEnabled(!menuData.getStationAndCitadelNames().isEmpty()); jPlanet.setEnabled(!menuData.getPlanetNames().isEmpty()); jSystem.setEnabled(!menuData.getSystemNames().isEmpty()); jConstellation.setEnabled(!menuData.getConstellationNames().isEmpty()); jRegion.setEnabled(!menuData.getRegionNames().isEmpty()); } public void setTool(Object object) { if (object instanceof OverviewTableMenu) { OverviewTab overviewTab = ((OverviewTableMenu)object).getOverviewTab(); jLocations.setEnabled(overviewTab.isGroupAndNotEmpty()); add(jLocations); } else { remove(jLocations); } } private void addFilters(Set names, TransactionTableFormat column, CompareType compareType) { List filters = JMenuAssetFilter.getFilters(names, column, compareType); TransactionTab transactionsTab = program.getTransactionsTab(true); transactionsTab.addFilters(filters); program.getMainWindow().addTab(transactionsTab); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (MenuTransactionFilterAction.STATION_FILTER.name().equals(e.getActionCommand())) { addFilters(menuData.getStationAndCitadelNames(), TransactionTableFormat.LOCATION, CompareType.EQUALS); } else if (MenuTransactionFilterAction.PLANET_FILTER.name().equals(e.getActionCommand())) { addFilters(menuData.getPlanetNames(), TransactionTableFormat.LOCATION, CompareType.EQUALS); } else if (MenuTransactionFilterAction.SYSTEM_FILTER.name().equals(e.getActionCommand())) { addFilters(menuData.getSystemNames(), TransactionTableFormat.SYSTEM, CompareType.EQUALS); } else if (MenuTransactionFilterAction.CONSTELLATION_FILTER.name().equals(e.getActionCommand())) { addFilters(menuData.getConstellationNames(), TransactionTableFormat.CONSTELLATION, CompareType.EQUALS); } else if (MenuTransactionFilterAction.REGION_FILTER.name().equals(e.getActionCommand())) { addFilters(menuData.getRegionNames(), TransactionTableFormat.REGION, CompareType.EQUALS); } else if (MenuTransactionFilterAction.OVERVIEW_GROUP_FILTER.name().equals(e.getActionCommand())) { OverviewGroup overviewGroup = program.getOverviewTab(true).getSelectGroup(); if (overviewGroup == null) { return; } List filters = new ArrayList<>(); for (OverviewLocation location : overviewGroup.getLocations()) { if (location.isStation()) { filters.add(new Filter(LogicType.OR, TransactionTableFormat.LOCATION, CompareType.EQUALS, location.getName())); } if (location.isPlanet()) { filters.add(new Filter(LogicType.OR, TransactionTableFormat.LOCATION, CompareType.EQUALS, location.getName())); } if (location.isSystem()) { filters.add(new Filter(LogicType.OR, TransactionTableFormat.SYSTEM, CompareType.EQUALS, location.getName())); } if (location.isConstellation()) { filters.add(new Filter(LogicType.OR, TransactionTableFormat.CONSTELLATION, CompareType.EQUALS, location.getName())); } if (location.isRegion()) { filters.add(new Filter(LogicType.OR, TransactionTableFormat.REGION, CompareType.EQUALS, location.getName())); } } TransactionTab transactionsTab = program.getTransactionsTab(true); transactionsTab.addFilters(filters); program.getMainWindow().addTab(transactionsTab); } else if (MenuTransactionFilterAction.ITEM_TYPE_FILTER.name().equals(e.getActionCommand())) { addFilters(menuData.getTypeNames(), TransactionTableFormat.NAME, CompareType.CONTAINS); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuUI.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyShip; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.JOptionInput; import net.nikr.eve.jeveasset.gui.shared.NativeUtil; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow.LockWorkerAdaptor; import net.nikr.eve.jeveasset.gui.tabs.routing.SolarSystem; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.io.esi.AbstractEsiGetter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.DesktopUtil; import net.troja.eve.esi.api.UserInterfaceApi; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class JMenuUI extends MenuManager.JAutoMenu { private static final Logger LOG = LoggerFactory.getLogger(JMenuUI.class); private enum MenuUIAction { AUTOPILOT_SYSTEM, AUTOPILOT_STATION, MARKET, OWNER, CONTRACTS } public static enum EsiOwnerRequirement { AUTOPILOT, OPEN_WINDOW, } private final JMenu jWaypoints; private final JMenuItem jSystem; private final JMenuItem jStation; private final JMenuItem jMarket; private final JMenuItem jOwner; private final JMenuItem jContracts; private static JLockWindow jLockWindow = null; public JMenuUI(Program program) { super(GuiShared.get().ui(), program); setIcon(Images.MISC_EVE.getIcon()); ListenerClass listener = new ListenerClass(); jWaypoints = new JMenu(GuiShared.get().uiWaypoint()); jWaypoints.setIcon(Images.TOOL_ROUTING.getIcon()); add(jWaypoints); jStation = new JMenuItem(GuiShared.get().uiStation()); jStation.setIcon(Images.LOC_STATION.getIcon()); jStation.setActionCommand(MenuUIAction.AUTOPILOT_STATION.name()); jStation.addActionListener(listener); jWaypoints.add(jStation); jSystem = new JMenuItem(GuiShared.get().uiSystem()); jSystem.setIcon(Images.LOC_SYSTEM.getIcon()); jSystem.setActionCommand(MenuUIAction.AUTOPILOT_SYSTEM.name()); jSystem.addActionListener(listener); jWaypoints.add(jSystem); jMarket = new JMenuItem(GuiShared.get().uiMarket()); jMarket.setIcon(Images.TOOL_MARKET_ORDERS.getIcon()); jMarket.setActionCommand(MenuUIAction.MARKET.name()); jMarket.addActionListener(listener); add(jMarket); jOwner = new JMenuItem(GuiShared.get().uiOwner()); jOwner.setIcon(Images.DIALOG_PROFILES.getIcon()); jOwner.setActionCommand(MenuUIAction.OWNER.name()); jOwner.addActionListener(listener); add(jOwner); jContracts = new JMenuItem(GuiShared.get().uiContract()); jContracts.setIcon(Images.TOOL_CONTRACTS.getIcon()); jContracts.setActionCommand(MenuUIAction.CONTRACTS.name()); jContracts.addActionListener(listener); add(jContracts); } @Override public void updateMenuData() { jWaypoints.setEnabled(menuData.getSystemLocations().size() == 1 || menuData.getAutopilotStationLocations().size() == 1 || menuData.getContracts().size() == 1); jStation.setEnabled(menuData.getAutopilotStationLocations().size() == 1 || menuData.getContracts().size() == 1); jSystem.setEnabled(menuData.getSystemLocations().size() == 1 || menuData.getContracts().size() == 1); jMarket.setEnabled(menuData.getMarketTypeIDs().size() == 1); jOwner.setEnabled(!menuData.getOwnerIDs().isEmpty()); jContracts.setEnabled(menuData.getContracts().size() == 1); } private JLockWindow getLockWindow() { return getLockWindow(program); } public static JLockWindow getLockWindow(Program program) { if (jLockWindow == null) { jLockWindow = new JLockWindow(program.getMainWindow().getFrame()); } return jLockWindow; } private EsiOwner selectOwner(EsiOwnerRequirement requirement) { return selectOwner(program, requirement); } public static EsiOwner selectOwner(Program program, EsiOwnerRequirement requirement) { List owners = new ArrayList<>(); for (EsiOwner owner : program.getProfileManager().getEsiOwners()) { if (requirement == EsiOwnerRequirement.OPEN_WINDOW && owner.isOpenWindows()) { owners.add(owner); } if (requirement == EsiOwnerRequirement.AUTOPILOT && owner.isAutopilot()) { owners.add(owner); } } if (owners.isEmpty()) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), GuiShared.get().uiCharacterInvalidMsg(), GuiShared.get().uiCharacterTitle(), JOptionPane.PLAIN_MESSAGE); return null; } Object object = JOptionInput.showInputDialog(program.getMainWindow().getFrame(), GuiShared.get().uiCharacterMsg(), GuiShared.get().uiCharacterTitle(), JOptionPane.PLAIN_MESSAGE, null, owners.toArray(new EsiOwner[owners.size()]), owners.get(0)); if (object == null) { return null; //Cancel } else if (object instanceof EsiOwner) { return (EsiOwner) object; } else { return null; } } private MyLocation selectLocation(Set locations) { return selectLocation(program, locations); } public static MyLocation selectLocation(Program program, Set locations) { if (locations.isEmpty()) { return null; } else if (locations.size() == 1) { return locations.iterator().next(); } else { Object object = JOptionInput.showInputDialog(program.getMainWindow().getFrame(), null, GuiShared.get().uiLocationTitle(), JOptionPane.PLAIN_MESSAGE, null, locations.toArray(new MyLocation[locations.size()]), locations.iterator().next()); if (object == null) { return null; //Cancel } else if (object instanceof MyLocation) { return (MyLocation) object; } else { return null; } } } private void setAutopilot(Long locationID, EsiOwner owner) { boolean addToBeginning; boolean clearOtherWaypoints; int clearValue = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), GuiShared.get().uiWaypointClear(), GuiShared.get().uiWaypointTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE); clearOtherWaypoints = clearValue == JOptionPane.YES_OPTION; if (clearOtherWaypoints) { addToBeginning = false; } else { int beginningValue = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), GuiShared.get().uiWaypointBeginning(), GuiShared.get().uiWaypointTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE); addToBeginning = beginningValue == JOptionPane.YES_OPTION; } getLockWindow().show(GuiShared.get().updating(), new EsiUpdate(owner) { @Override protected void updateESI() throws Throwable { getApi().postUiAutopilotWaypoint(addToBeginning, clearOtherWaypoints, locationID, AbstractEsiGetter.COMPATIBILITY_DATE, null, null, null); } @Override protected void ok() { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), GuiShared.get().uiWaypointOk(), GuiShared.get().uiWaypointTitle(), JOptionPane.PLAIN_MESSAGE); EveGatecampCheck.open(program, owner, locationID); } @Override protected void fail() { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), GuiShared.get().uiWaypointFail(), GuiShared.get().uiWaypointTitle(), JOptionPane.PLAIN_MESSAGE); } }); } public static class ContractMenuData extends MenuData { public ContractMenuData(List items) { super(items); Set contracts = new HashSet<>(); for (Object item : items) { if (item instanceof MyContractItem) { contracts.add(((MyContractItem)item).getContract()); } } setContracts(contracts); } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (MenuUIAction.AUTOPILOT_STATION.name().equals(e.getActionCommand())) { EsiOwner owner = selectOwner(EsiOwnerRequirement.AUTOPILOT); if (owner == null) { return; } MyLocation station = selectLocation(menuData.getAutopilotStationLocations()); if (station == null) { return; } setAutopilot(station.getStationID() != 0 ? station.getStationID() : station.getLocationID(), owner); } else if (MenuUIAction.AUTOPILOT_SYSTEM.name().equals(e.getActionCommand())) { EsiOwner owner = selectOwner(EsiOwnerRequirement.AUTOPILOT); if (owner == null) { return; } MyLocation system = selectLocation(menuData.getSystemLocations()); if (system == null) { return; } setAutopilot(system.getSystemID(), owner); } else if (MenuUIAction.MARKET.name().equals(e.getActionCommand())) { EsiOwner owner = selectOwner(EsiOwnerRequirement.OPEN_WINDOW); Integer typeID = menuData.getMarketTypeIDs().iterator().next(); openMarketDetails(program, owner, typeID, true); } else if (MenuUIAction.OWNER.name().equals(e.getActionCommand())) { EsiOwner esiOwner = selectOwner(EsiOwnerRequirement.OPEN_WINDOW); if (esiOwner == null) { return; } List owners = new ArrayList<>(); for (Long ownerID : menuData.getOwnerIDs()) { if (ownerID != null && ownerID > 0) { String name = Settings.get().getOwners().get(ownerID); if (name == null) { name = GuiShared.get().unknownOwner(); } owners.add(new Owner(ownerID, name)); } } Owner owner; if (owners.size() > 1) { Collections.sort(owners); Object object = JOptionInput.showInputDialog(program.getMainWindow().getFrame(), GuiShared.get().uiOwnerMsg(), GuiShared.get().uiOwnerTitle(), JOptionPane.PLAIN_MESSAGE, null, owners.toArray(new Owner[owners.size()]), owners.get(0)); if (object == null) { return; //Cancel } if (object instanceof Owner) { owner = (Owner) object; } else { return; } } else if (!owners.isEmpty()) { owner = owners.get(0); } else { return; } getLockWindow().show(GuiShared.get().updating(), new EsiUpdate(esiOwner) { @Override protected void updateESI() throws Throwable { getApi().postUiOpenwindowInformation(owner.getID(), AbstractEsiGetter.COMPATIBILITY_DATE, null, null, null); } @Override protected void ok() { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), GuiShared.get().uiOwnerOk(), GuiShared.get().uiOwnerTitle(), JOptionPane.PLAIN_MESSAGE); } @Override protected void fail() { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), GuiShared.get().uiOwnerFail(), GuiShared.get().uiOwnerTitle(), JOptionPane.PLAIN_MESSAGE); } }); } else if (MenuUIAction.CONTRACTS.name().equals(e.getActionCommand())) { EsiOwner owner = selectOwner(EsiOwnerRequirement.OPEN_WINDOW); if (owner == null) { return; } MyContract contract = menuData.getContracts().iterator().next(); getLockWindow().show(GuiShared.get().updating(), new EsiUpdate(owner) { @Override protected void updateESI() throws Throwable { getApi().postUiOpenwindowContract(SafeConverter.toLong(contract.getContractID()), AbstractEsiGetter.COMPATIBILITY_DATE, null, null, null); } @Override protected void ok() { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), GuiShared.get().uiContractOk(), GuiShared.get().uiContractTitle(), JOptionPane.PLAIN_MESSAGE); } @Override protected void fail() { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), GuiShared.get().uiContractFail(), GuiShared.get().uiContractTitle(), JOptionPane.PLAIN_MESSAGE); } }); } } } public static void openMarketDetails(Program program, EsiOwner owner, Integer typeID, boolean showOkMsg) { if (owner == null) { return; } getLockWindow(program).show(GuiShared.get().updating(), new EsiUpdate(owner) { @Override protected void updateESI() throws Throwable { getApi().postUiOpenwindowMarketdetails(SafeConverter.toLong(typeID), AbstractEsiGetter.COMPATIBILITY_DATE, null, null, null); } @Override protected void ok() { if (showOkMsg) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), GuiShared.get().uiMarketOk(), GuiShared.get().uiMarketTitle(), JOptionPane.PLAIN_MESSAGE); } } @Override protected void fail() { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), GuiShared.get().uiMarketFail(), GuiShared.get().uiMarketTitle(), JOptionPane.PLAIN_MESSAGE); } }); } private static class Owner implements Comparable { private final long id; private final String name; public Owner(long id, String name) { this.id = id; this.name = name; } public long getID() { return id; } @Override public String toString() { return name; } @Override public int compareTo(Owner o) { return this.name.compareTo(o.name); } } public static abstract class EsiUpdate extends LockWorkerAdaptor { private boolean ok; protected abstract void updateESI() throws Throwable; protected abstract void ok(); protected abstract void fail(); private final EsiOwner owner; public EsiUpdate(EsiOwner owner) { this.owner = owner; } protected UserInterfaceApi getApi() { if (owner != null) { //Auth return owner.getUserInterfaceApiAuth(); } else { return AbstractEsiGetter.USER_INTERFACE_API; } } @Override public void task() { try { updateESI(); ok = true; } catch (Throwable t) { ok = false; LOG.error(t.getMessage(), t); } } @Override public void gui() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (ok) { ok(); if (Settings.get().isFocusEveOnlineOnEsiUiCalls()) { NativeUtil.focusEveOnline(owner.getOwnerName()); } } else { fail(); } } }); } } public static class EveGatecampCheck { public static final String[] EVE_GATECAMP_CHECK_ROUTE_OPTIONS = { GuiShared.get().uiWaypointEveGatecampCheckSecure(), GuiShared.get().uiWaypointEveGatecampCheckUnsecure(), GuiShared.get().uiWaypointEveGatecampCheckShortest() }; public static final String[] EVE_GATECAMP_CHECK_OPEN_OPTIONS = { GuiShared.get().uiWaypointEveGatecampCheckAsk(), GuiShared.get().uiWaypointEveGatecampCheckAlwaysOpen(), GuiShared.get().uiWaypointEveGatecampCheckNeverOpen() }; public static void setOpenOption(Object object) { if (object == null) { return; //Cancel } if (GuiShared.get().uiWaypointEveGatecampCheckAlwaysOpen().equals(object)) { //Secure Settings.get().setEveGatecampCheckAlwaysOpen(true); Settings.get().setEveGatecampCheckNeverOpen(false); } else if (GuiShared.get().uiWaypointEveGatecampCheckNeverOpen().equals(object)) { //Unsecure Settings.get().setEveGatecampCheckSecure(false); Settings.get().setEveGatecampCheckUnsecure(true); } else if (GuiShared.get().uiWaypointEveGatecampCheckAsk().equals(object)) { //Shortest Settings.get().setEveGatecampCheckSecure(false); Settings.get().setEveGatecampCheckUnsecure(false); } else { //Default Settings.get().setEveGatecampCheckSecure(false); Settings.get().setEveGatecampCheckUnsecure(false); } } public static String getOpenOption() { if (Settings.get().isEveGatecampCheckAlwaysOpen()) { return GuiShared.get().uiWaypointEveGatecampCheckAlwaysOpen(); } else if (Settings.get().isEveGatecampCheckNeverOpen()) { return GuiShared.get().uiWaypointEveGatecampCheckNeverOpen(); } else { return GuiShared.get().uiWaypointEveGatecampCheckAsk(); } } public static String setRouteOption(Object object) { if (object == null) { return ""; //Cancel } if (GuiShared.get().uiWaypointEveGatecampCheckSecure().equals(object)) { //Secure Settings.get().setEveGatecampCheckSecure(true); Settings.get().setEveGatecampCheckUnsecure(false); return ":secure"; } else if (GuiShared.get().uiWaypointEveGatecampCheckUnsecure().equals(object)) { //Unsecure Settings.get().setEveGatecampCheckSecure(false); Settings.get().setEveGatecampCheckUnsecure(true); return ":insecure"; } else if (GuiShared.get().uiWaypointEveGatecampCheckShortest().equals(object)) { //Shortest Settings.get().setEveGatecampCheckSecure(false); Settings.get().setEveGatecampCheckUnsecure(false); return ":shortest"; } return ""; } public static String getRouteOption() { if (Settings.get().isEveGatecampCheckSecure()) { //Secure return GuiShared.get().uiWaypointEveGatecampCheckSecure(); } else if (Settings.get().isEveGatecampCheckUnsecure()) { //Unsecure return GuiShared.get().uiWaypointEveGatecampCheckUnsecure(); } else { //Shortest return GuiShared.get().uiWaypointEveGatecampCheckShortest(); } } public static void open(Program program, EsiOwner owner, long locationID) { open(program, owner, Collections.singleton(locationID)); } public static void open(Program program, EsiOwner owner, Set locationIDs) { if (owner == null) { return; } MyShip activeShip = owner.getActiveShip(); if (activeShip == null || activeShip.getLocation().isEmpty()) { return; } String from = activeShip.getLocation().getSystem(); StringBuilder routeBuilder = new StringBuilder(); Set route = new HashSet<>(); for (Long locationID : locationIDs) { MyLocation toLocation = ApiIdConverter.getLocation(locationID); if (toLocation.isEmpty()) { return; } String to = toLocation.getSystem(); if (routeBuilder.length() > 0) { routeBuilder.append(","); } else { if (from.equals(to)) { continue; } } route.add(to); routeBuilder.append(to.replace(" ", "%20")); } if (routeBuilder.length() == 0) { return; } StringBuilder avoidBuilder = new StringBuilder(); boolean avoidInRoute = false; for (SolarSystem system : Settings.get().getJumpsAvoidSettings().getAvoid().values()) { if (avoidBuilder.length() > 0) { avoidBuilder.append(","); } String systemName = system.getName(); if (!avoidInRoute && route.contains(systemName)) { avoidInRoute = true; } avoidBuilder.append(systemName.replace(" ", "%20")); } if (!Settings.get().isEveGatecampCheckSet()) { //Default Options int returnValue = JOptionPane.showOptionDialog(program.getMainWindow().getFrame(), GuiShared.get().uiWaypointEveGatecampCheckOptions(), GuiShared.get().uiWaypointTitle(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, EVE_GATECAMP_CHECK_OPEN_OPTIONS, EVE_GATECAMP_CHECK_OPEN_OPTIONS[0]); if (returnValue == JOptionPane.CLOSED_OPTION) { return; //Cancel } String openOption = EVE_GATECAMP_CHECK_OPEN_OPTIONS[returnValue]; if (GuiShared.get().uiWaypointEveGatecampCheckAlwaysOpen().equals(openOption)) { //Always Open //Default Route Options Object routeOption = JOptionInput.showInputDialog(program.getMainWindow().getFrame(), GuiShared.get().uiWaypointEveGatecampCheckDefault(), GuiShared.get().uiWaypointTitle(), JOptionPane.PLAIN_MESSAGE, null, EVE_GATECAMP_CHECK_ROUTE_OPTIONS, EVE_GATECAMP_CHECK_ROUTE_OPTIONS[0]); if (routeOption == null) { return; //cancel } setRouteOption(routeOption); } setOpenOption(openOption); Settings.get().setEveGatecampCheckSet(true); } if (Settings.get().isEveGatecampCheckNeverOpen()) { return; } String routeOption; if (Settings.get().isEveGatecampCheckAlwaysOpen()) { if (Settings.get().isEveGatecampCheckSecure()) { //Secure routeOption = ":secure"; } else if (Settings.get().isEveGatecampCheckUnsecure()) { //Unsecure routeOption = ":insecure"; } else { //Shortest routeOption = ":shortest"; } } else { String defaultOption = getRouteOption(); Object object = JOptionInput.showInputDialog(program.getMainWindow().getFrame(), GuiShared.get().uiWaypointEveGatecampCheck(), GuiShared.get().uiWaypointTitle(), JOptionPane.PLAIN_MESSAGE, null, EVE_GATECAMP_CHECK_ROUTE_OPTIONS, defaultOption); if (object == null) { return; } routeOption = setRouteOption(object); } /* if (avoidInRoute) { JOptionPane.showMessageDialog(program.getMainWindow().get, EAST); } */ DesktopUtil.browse("https://eve-gatecheck.space/eve/#" + from + ":" + routeBuilder.toString() + routeOption + ":" + avoidBuilder.toString(), program); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/JTagsDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.Image; import java.awt.Point; import java.awt.RenderingHints; import java.awt.Toolkit; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.image.FilteredImageSource; import java.awt.image.RGBImageFilter; import java.util.HashSet; import java.util.Set; import javax.swing.GroupLayout; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JColorChooser; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JTextField; import javax.swing.JWindow; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.tag.Tag; import net.nikr.eve.jeveasset.data.settings.tag.TagColor; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JTagsDialog extends JDialogCentered { private enum TagsDialogAction { OK, CANCEL, SHOW_COLOR } //GUI private ColorPicker colorPicker; private JTextField jTextField; private JButton jColor; private JButton jOK; //Data private Tag tag; private Tag editTag; private Set unique; public JTagsDialog(Program program) { super(program, "", Images.TAG_GRAY.getImage()); ListenerClass listener = new ListenerClass(); JLabel jLabel = new JLabel(GuiShared.get().tagsNewMsg()); jTextField = new JTextField(); jTextField.addFocusListener(listener); jTextField.addCaretListener(listener); jColor = new JButton(); colorPicker = new ColorPicker(getDialog(), jColor); jColor.addFocusListener(listener); jColor.setActionCommand(TagsDialogAction.SHOW_COLOR.name()); jColor.addActionListener(listener); jOK = new JButton(GuiShared.get().ok()); jOK.setActionCommand(TagsDialogAction.OK.name()); jOK.addActionListener(listener); jOK.addFocusListener(listener); JButton jCancel = new JButton(GuiShared.get().cancel()); jCancel.setActionCommand(TagsDialogAction.CANCEL.name()); jCancel.addActionListener(listener); jCancel.addFocusListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jLabel, 250, 250, Integer.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addComponent(jTextField, 200, 200, 200) .addComponent(jColor, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) ) .addGroup(layout.createSequentialGroup() .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup() .addComponent(jTextField, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jColor, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } public Tag show(Tag editTag) { return show(editTag, new HashSet<>(Settings.get().getTags().keySet())); } public Tag show(Tag editTag, Set unique) { getDialog().setTitle(GuiShared.get().tagsEditTitle()); this.editTag = editTag; this.unique = unique; tag = null; jColor.setIcon(new TagIcon(editTag.getColor())); jTextField.setText(editTag.getName()); setVisible(true); return tag; } public Tag show() { return show(new HashSet<>(Settings.get().getTags().keySet())); } public Tag show(Set unique) { getDialog().setTitle(GuiShared.get().tagsNewTitle()); this.unique = unique; editTag = null; tag = null; jColor.setIcon(new TagIcon(TagColor.getValues()[0])); jTextField.setText(""); setVisible(true); return tag; } @Override protected JComponent getDefaultFocus() { return jTextField; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { } @Override protected void save() { String name = jTextField.getText(); TagIcon icon = (TagIcon) jColor.getIcon(); TagColor color = icon.getTagColor(); tag = new Tag(name, color); setVisible(false); } private class ListenerClass implements ActionListener, FocusListener, CaretListener { @Override public void actionPerformed(ActionEvent e) { if (TagsDialogAction.OK.name().equals(e.getActionCommand())) { save(); } else if (TagsDialogAction.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); } else if (TagsDialogAction.SHOW_COLOR.name().equals(e.getActionCommand())) { colorPicker.show(); } } @Override public void focusGained(FocusEvent e) { colorPicker.hide(); } @Override public void focusLost(FocusEvent e) { } @Override public void caretUpdate(CaretEvent e) { String name = jTextField.getText(); if (unique.contains(name) && (editTag == null || !editTag.getName().equals(name))) { ColorSettings.config(jTextField, ColorEntry.GLOBAL_ENTRY_INVALID); jOK.setEnabled(false); } else { ColorSettings.configReset(jTextField); jOK.setEnabled(true); } } } public static class TagIcon implements Icon { private TagColor tagColor; private Image image = null; public TagIcon(TagColor tagColor) { this(tagColor, false); } public TagIcon(TagColor tagColor, boolean selected) { this.tagColor = tagColor; if (selected) { image = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(Images.TAG_TICK.getImage().getSource(), new ColorFilter(tagColor.getForeground()))); } } @Override public void paintIcon(Component c, Graphics g, int x, int y) { Graphics2D g2d = (Graphics2D) g; if (image != null) { //Selected //Render settings //g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //Border g2d.setColor(Color.BLACK); g2d.fillOval(x, y, getIconWidth() - 1, getIconHeight() - 1); //Background g2d.setColor(tagColor.getBackground()); g2d.fillOval(x + 1, y + 1, getIconWidth() - 3, getIconHeight() - 3); //Image g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); g.drawImage(image, x + 2, y + 2, null); } else { //Not selected //Render settings g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); //Background g2d.setColor(tagColor.getBackground()); g2d.fillRect(x, y, getIconWidth() - 1, getIconHeight() - 1); //Border g2d.setColor(Color.BLACK); g2d.drawRect(x, y, getIconWidth() - 1, getIconHeight() - 1); //Text g2d.setFont(new JLabel().getFont()); g2d.setColor(tagColor.getForeground()); g2d.drawString("a", x + 5, y + 11); } } @Override public int getIconWidth() { return 16; } @Override public int getIconHeight() { return 16; } public TagColor getTagColor() { return tagColor; } } private static class ColorFilter extends RGBImageFilter { private final int foreground; private final int white; public ColorFilter(Color foreground) { this.foreground = foreground.getRGB(); white = Color.WHITE.getRGB(); } @Override public int filterRGB(int x, int y, int rgb) { if ((rgb | 0xFFFFFF00) == white) { return (foreground & 0x00FFFFFF) | (rgb & 0xFF000000) ; } else { return rgb; } } } private static class ColorPicker { private JWindow jWindow; private JButton jButton; public ColorPicker(final Window owner, final JButton jButton) { this.jButton = jButton; jWindow = new JWindow(owner); JPanel jPanel = new JPanel(); jPanel.setBorder(new JPopupMenu().getBorder()); GroupLayout groupLayout = new GroupLayout(jPanel); groupLayout.setAutoCreateContainerGaps(true); groupLayout.setAutoCreateGaps(true); jPanel.setLayout(groupLayout); jWindow.add(jPanel); JPanel jButtonPanel = new JPanel(); GridLayout gridLayout = new GridLayout(0, 4, 5, 5); jButtonPanel.setLayout(gridLayout); for (TagColor tagColor : TagColor.getValues()) { final TagIcon tagIcon = new TagIcon(tagColor); JButton button = new JButton(tagIcon); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jButton.setIcon(tagIcon); jWindow.setVisible(false); } }); button.setBorder(null); button.setContentAreaFilled(false); jButtonPanel.add(button); } JButton jCustom = new JButton(GuiShared.get().custom()); //Custom... jCustom.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jWindow.setVisible(false); TagIcon icon = (TagIcon) jButton.getIcon(); Color background = JColorChooser.showDialog(owner, GuiShared.get().background(), icon.getTagColor().getBackground()); if (background == null) { return; } Color foreground = JColorChooser.showDialog(owner, GuiShared.get().foreground(), icon.getTagColor().getForeground()); if (foreground == null) { return; } icon = new TagIcon(new TagColor(background, foreground)); jButton.setIcon(icon); } }); groupLayout.setHorizontalGroup( groupLayout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jButtonPanel) .addComponent(jCustom) ); groupLayout.setVerticalGroup( groupLayout.createSequentialGroup() .addComponent(jButtonPanel) .addComponent(jCustom) ); } public void show() { Point point = jButton.getLocationOnScreen(); jWindow.pack(); jWindow.setLocation(point.x + 2, point.y + jButton.getHeight() - 1); jWindow.setVisible(true); } public void hide() { jWindow.setVisible(false); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/MenuData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.tag.Tag; import net.nikr.eve.jeveasset.data.settings.types.BlueprintType; import net.nikr.eve.jeveasset.data.settings.types.CorporationType; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.data.settings.types.LocationsType; import net.nikr.eve.jeveasset.data.settings.types.OwnersType; import net.nikr.eve.jeveasset.data.settings.types.PriceType; import net.nikr.eve.jeveasset.data.settings.types.TagsType; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class MenuData { private final Set typeIDs = new HashSet<>(); private final Set autopilotStationLocations = new HashSet<>(); private final Set systemLocations = new HashSet<>(); private final Set regionLocations = new HashSet<>(); private final Set constellationLocations = new HashSet<>(); private final Set editableCitadelLocations = new HashSet<>(); private final Set userLocations = new HashSet<>(); private final Map prices = new HashMap<>(); private final Set typeNames = new HashSet<>(); private final Set stationsAndCitadelsNames = new HashSet<>(); private final Set stationNames = new HashSet<>(); private final Set planetNames = new HashSet<>(); private final Set systemNames = new HashSet<>(); private final Set constellationNames = new HashSet<>(); private final Set regionNames = new HashSet<>(); private final Set marketTypeIDs = new HashSet<>(); private final Set blueprintTypeIDs = new HashSet<>(); private final Set inventionTypeIDs = new HashSet<>(); private final Set bpcTypeIDs = new HashSet<>(); private final Set ownerIDs = new HashSet<>(); private final Map tagCount = new HashMap<>(); private final List tags = new ArrayList<>(); private final List assets = new ArrayList<>(); private final Set contracts = new HashSet<>(); private final Map itemCounts = new HashMap<>(); private final Map counts = new HashMap<>(); private final Map runs = new HashMap<>(); private final Set corporationNames = new HashSet<>(); private final Set corporationIDs = new HashSet<>(); public MenuData() { } public MenuData(final List items) { if (items == null) { //Skip null return; } for (T t : items) { if (t == null) { //Skip null continue; } Set locations = new HashSet<>(); if (t instanceof LocationType) { LocationType type = (LocationType) t; locations.add(type.getLocation()); } if (t instanceof LocationsType) { LocationsType type = (LocationsType) t; locations.addAll(type.getLocations()); } Set owners = new HashSet<>(); if (t instanceof OwnersType) { OwnersType ownersType = (OwnersType) t; owners.addAll(ownersType.getOwners()); } ItemType itemType = null; if (t instanceof ItemType) { itemType = (ItemType) t; } BlueprintType blueprint = null; if (t instanceof BlueprintType) { blueprint = (BlueprintType) t; } Double price = null; if (t instanceof PriceType) { PriceType priceType = (PriceType) t; price = priceType.getDynamicPrice(); } TagsType tagsType = null; if (t instanceof TagsType) { tagsType = (TagsType) t; } CorporationType corporationType = null; if (t instanceof CorporationType) { corporationType = (CorporationType) t; } if (t instanceof Item) { Item item = (Item) t; if (items.size() == 1) { //Always zero for multiple items price = ApiIdConverter.getPrice(item.getTypeID(), false); } if (price == null || price == 0) { price = item.getPriceBase(); } } add(itemType, locations, price, blueprint, tagsType, owners, corporationType); } } private void add(final ItemType itemType, final Collection locations, final Double price, final BlueprintType blueprintType, final TagsType tagsType, Set owners, CorporationType corporationType) { if (itemType != null) { Item item = itemType.getItem(); if (item != null && !item.isEmpty()) { //Type Name typeNames.add(item.getTypeName()); //TypeID int typeID = item.getTypeID(); typeIDs.add(typeID); if (item.isBlueprint()) { blueprintTypeIDs.add(item.getTypeID()); if (item.getMeta() == 0 && item.getTypeName().contains(" I ")) { inventionTypeIDs.add(item.getTypeID()); } } else if (item.isProduct()) { blueprintTypeIDs.addAll(item.getBlueprintTypeIDs()); if (item.getMeta() == 0 && item.getTypeName().endsWith(" I")) { inventionTypeIDs.addAll(item.getBlueprintTypeIDs()); } } //Market TypeID if (item.isMarketGroup()) { marketTypeIDs.add(typeID); } //Blueprint TypeID int blueprintTypeID; if (blueprintType != null && blueprintType.isBPC()) { blueprintTypeID = -typeID; //Runs double r = blueprintType.getRuns(); if (r > 0) { r = r + runs.getOrDefault(blueprintTypeID, 0.0); runs.put(blueprintTypeID, r); } } else { blueprintTypeID = typeID; } bpcTypeIDs.add(blueprintTypeID); //Item Count Long itemCount = itemCounts.getOrDefault(item, 0L); itemCount = itemCount + itemType.getItemCount(); itemCounts.put(item, itemCount); //Count double count = counts.getOrDefault(blueprintTypeID, 0.0); count = count + itemType.getItemCount(); counts.put(blueprintTypeID, count); //Price TypeID if (price != null) { //Not unique prices.put(blueprintTypeID, price); } } } ownerIDs.addAll(owners); //Locations for (MyLocation location : locations) { if (location == null) { continue; } if ((location.isEmpty() && location.getLocationID() != 0) || location.isUserLocation()) { //Empty with locationID or user editableCitadelLocations.add(location); } if (location.isUserLocation()) { //User userLocations.add(location); } if (location.getLocationID() != 0 && (location.isStation() || location.isEmpty())) { //Any station with a locationID (not planets) stationsAndCitadelsNames.add(location.getStation()); //Assets Station (support citadels) autopilotStationLocations.add(location); //Autopilot Station (support citadels) } if (location.isEmpty()) { continue; //Ignore empty locations for the rest of the loop } //Staion if (location.isStation() && !location.isCitadel()) { //Not planet stationNames.add(location.getStation()); //Dotlan Station (does not support citadels) } //Planet if (location.isPlanet()) { planetNames.add(location.getLocation()); //Dotlan + Assets Planet } //System if (location.isStation() || location.isPlanet() || location.isSystem()) { //Station, Planet, or System systemNames.add(location.getSystem()); //Dotlan + Assets System //Jumps MyLocation system = ApiIdConverter.getLocation(location.getSystemID()); if (!system.isEmpty()) { systemLocations.add(system); //Jumps + Autopilot + zKillboard System } } //Constellation if (location.isStation() || location.isPlanet() || location.isSystem() || location.isConstellation()) { //Station, Planet, System or Constellation constellationNames.add(location.getConstellation()); //Assets Constellation MyLocation constellation = ApiIdConverter.getLocation(location.getConstellationID()); if (!constellation.isEmpty()) { constellationLocations.add(constellation); //Dotlan + zKillboard Constellation } } //Region if (location.isStation() || location.isPlanet() || location.isSystem() || location.isConstellation() || location.isRegion()) { //Station, Planet, System, Constellation or Region regionNames.add(location.getRegion()); //Dotlan + Assets Region MyLocation region = ApiIdConverter.getLocation(location.getRegionID()); if (!region.isEmpty()) { regionLocations.add(region); //zKillboard Region } } } //Tags if (tagsType != null && tagsType.getTags() != null) { tags.add(tagsType); for (Tag tagKey : tagsType.getTags()) { Integer count = tagCount.get(tagKey); if (count != null) { count++; } else { count = 1; } tagCount.put(tagKey, count); } } //Corporations if (corporationType != null) { Integer corporationID = corporationType.getCorporationID(); if (corporationID != null) { corporationIDs.add(corporationID); } String corporationName = corporationType.getCorporationName(); if (corporationName != null && !corporationName.isEmpty()) { corporationNames.add(corporationName); } } } public Map getTagCount() { return tagCount; } public List getTags() { return tags; } public Set getTypeIDs() { return typeIDs; } public Map getPrices() { return prices; } public Set getTypeNames() { return typeNames; } //JMenuAssetFilter public Set getStationAndCitadelNames() { return stationsAndCitadelsNames; } //JMenuLookup public Set getStationNames() { return stationNames; } //JMenuLookup + JMenuAssetFilter public Set getPlanetNames() { return planetNames; } //JMenuLookup + JMenuAssetFilter public Set getSystemNames() { return systemNames; } //JMenuAssetFilter public Set getConstellationNames() { return constellationNames; } //JMenuLookup + JMenuAssetFilter public Set getRegionNames() { return regionNames; } //JMenuLookup public Set getRegionLocations() { return regionLocations; } //JMenuLookup public Set getConstellationLocations() { return constellationLocations; } //JMenuJumps and JMenuUI public Set getSystemLocations() { return systemLocations; } //JMenuUI public Set getAutopilotStationLocations() { return autopilotStationLocations; } //JMenuLocation public Set getUserLocations() { return userLocations; } //JMenuLocation public Set getEditableCitadelLocations() { return editableCitadelLocations; } public Set getMarketTypeIDs() { return marketTypeIDs; } public Set getBpcTypeIDs() { return bpcTypeIDs; } public Set getBlueprintTypeIDs() { return blueprintTypeIDs; } public Set getInventionTypeIDs() { return inventionTypeIDs; } public Set getOwnerIDs() { return ownerIDs; } public void setAssets(List assets) { this.assets.clear(); this.assets.addAll(assets); } public List getAssets() { return assets; } public Set getContracts() { return contracts; } public void setContracts(Set contracts) { this.contracts.clear(); this.contracts.addAll(contracts); } public Map getItemCounts() { return itemCounts; } public Map getCounts() { return counts; } public Map getRuns() { return runs; } public Set getCorporationNames() { return corporationNames; } public Set getCorporationIDs() { return corporationIDs; } public static class AssetMenuData extends MenuData { public AssetMenuData(List items) { super(items); setAssets(items); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/menu/MenuManager.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.awt.Component; import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; import java.util.Map; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JTable; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.settings.types.CorporationType; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.data.settings.types.LocationsType; import net.nikr.eve.jeveasset.data.settings.types.PriceType; import net.nikr.eve.jeveasset.data.settings.types.TagsType; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeAsset; public class MenuManager & EnumTableColumn, Q> { private enum MenuEnum { ASSET_FILTER, TRANSACTION_FILTER, TAGS, STOCKPILE, LOOKUP, LOCATION, UI, PRICE, NAME, REPROCESSED, PRICE_HISTORY, JUMPS, ROUTING, COPY_PLUS, SUM, FORMULA, LOADOUT, } private boolean priceSupported = false; private boolean itemSupported = false; private boolean locationSupported = false; private boolean corporationSupported = false; private boolean jumpsSupported = false; private boolean assets = false; private boolean tree = false; private boolean transactions = false; private boolean stockpile = false; private boolean tagsSupported = false; private final Map> mainMenu = new EnumMap<>(MenuEnum.class); private final Map> tablePopupMenu = new EnumMap<>(MenuEnum.class); private final TableMenu tableMenu; private final JTable jTable; private final Program program; private final ColumnManager columnManager; private static final Map, MenuManager> MANAGERS = new HashMap, MenuManager>(); private static Boolean changed = null; public static & EnumTableColumn, Q> void install(final Program program, final TableMenu tableMenu, JTable jTable, final ColumnManager columnManager, final Class clazz) { MenuManager menuManager = new MenuManager<>(program, tableMenu, jTable, columnManager, clazz); MenuManager put = MANAGERS.put(clazz, menuManager); if (put != null) { throw new RuntimeException("Duplicated MenuManager Class"); } if (changed == null) { //Only do once changed = false; program.getMainWindow().getMenu().getTableMenu().addMenuListener(new MenuListener() { @Override public void menuSelected(MenuEvent e) { if (changed) { changed = false; Program.ensureEDT(new Runnable() { @Override public void run() { program.getMainWindow().getSelectedTab().createTableMenu(); } }); } } @Override public void menuDeselected(MenuEvent e) { } @Override public void menuCanceled(MenuEvent e) { } }); } } public static void update(final Program program, final Class clazz) { MenuManager menuManager = MANAGERS.get(clazz); JMenu jMenu = program.getMainWindow().getMenu().getTableMenu(); if (menuManager != null) { jMenu.setEnabled(true); changed = true; } else { //No table menu jMenu.removeAll(); jMenu.setEnabled(false); } } public static void create(final Program program, final Class clazz) { MenuManager menuManager = MANAGERS.get(clazz); if (menuManager != null) { menuManager.updateMainTableMenu(); } else { //No table menu JMenu jMenu = program.getMainWindow().getMenu().getTableMenu(); jMenu.removeAll(); jMenu.setEnabled(false); } } public static void updateFormula(final Class clazz) { MenuManager menuManager = MANAGERS.get(clazz); if (menuManager != null) { menuManager.columnManager.resetFormulaData(); } } public static void lock(final Class clazz) { MenuManager menuManager = MANAGERS.get(clazz); if (menuManager != null) { menuManager.columnManager.lock(); } } public static void unlock(final Class clazz) { MenuManager menuManager = MANAGERS.get(clazz); if (menuManager != null) { menuManager.columnManager.unlock(); } } public static void updateJumps(final Class clazz) { MenuManager menuManager = MANAGERS.get(clazz); if (menuManager != null) { menuManager.columnManager.updateJumpsData(); } } private MenuManager(final Program program, final TableMenu tableMenu, JTable jTable, ColumnManager columnManager, final Class clazz) { this.program = program; this.tableMenu = tableMenu; this.jTable = jTable; this.columnManager = columnManager; assets = MyAsset.class.equals(clazz); tree = TreeAsset.class.equals(clazz); transactions = MyTransaction.class.isAssignableFrom(clazz); stockpile = StockpileItem.class.isAssignableFrom(clazz); locationSupported = LocationType.class.isAssignableFrom(clazz) || LocationsType.class.isAssignableFrom(clazz); corporationSupported = CorporationType.class.isAssignableFrom(clazz); jumpsSupported = LocationType.class.isAssignableFrom(clazz); itemSupported = ItemType.class.isAssignableFrom(clazz); tagsSupported = TagsType.class.isAssignableFrom(clazz); priceSupported = PriceType.class.isAssignableFrom(clazz) || Item.class.isAssignableFrom(clazz); createCashe(program, mainMenu, columnManager); createCashe(program, tablePopupMenu, columnManager); ListenerClass listener = new ListenerClass(); jTable.addMouseListener(listener); jTable.getTableHeader().addMouseListener(listener); jTable.getSelectionModel().addListSelectionListener(listener); jTable.getColumnModel().getSelectionModel().addListSelectionListener(listener); updateMainTableMenu(); } private void createCashe(final Program program, final Map> menus, ColumnManager columnManager) { //COPY SIMPLE if (itemSupported) { menus.put(MenuEnum.COPY_PLUS, new JMenuCopyPlus<>(program)); } //ASSET FILTER if (!assets && (itemSupported || locationSupported)) { menus.put(MenuEnum.ASSET_FILTER, new JMenuAssetFilter<>(program)); } //TRANSACTION FILTER if (!transactions && (itemSupported || locationSupported)) { menus.put(MenuEnum.TRANSACTION_FILTER, new JMenuTransactionFilter<>(program)); } //STOCKPILE (Add To) if (!stockpile && itemSupported) { menus.put(MenuEnum.STOCKPILE, new JMenuStockpile<>(program)); } //LOOKUP if (itemSupported || locationSupported || corporationSupported) { menus.put(MenuEnum.LOOKUP, new JMenuLookup<>(program)); } //EDIT if (priceSupported) { menus.put(MenuEnum.PRICE, new JMenuPrice<>(program)); } if (assets || tree) { menus.put(MenuEnum.NAME, new JMenuName<>(program)); } if (tagsSupported) { menus.put(MenuEnum.TAGS, new JMenuTags<>(program)); } //LOADOUT if (assets || tree) { menus.put(MenuEnum.LOADOUT, new JMenuLoadout<>(program)); } //REPROCESSED if (itemSupported) { menus.put(MenuEnum.REPROCESSED, new JMenuReprocessed<>(program)); } //PRICE HISTORY if (itemSupported) { menus.put(MenuEnum.PRICE_HISTORY, new JMenuPriceHistory<>(program)); } //JUMPS if (jumpsSupported) { menus.put(MenuEnum.JUMPS, new JMenuJumps<>(program, columnManager)); } if (locationSupported) { menus.put(MenuEnum.ROUTING, new JMenuRouting<>(program)); } //LOCATION if (locationSupported) { menus.put(MenuEnum.LOCATION, new JMenuLocation<>(program)); } if (locationSupported || priceSupported || itemSupported) { menus.put(MenuEnum.UI, new JMenuUI<>(program)); } //FORMULA menus.put(MenuEnum.FORMULA, new JMenuFormula<>(program, columnManager)); //SUM menus.put(MenuEnum.SUM, new JMenuSum<>(program, jTable)); } private void createMenu(JPopupMenu jPopupMenu) { createMenu(jPopupMenu, tablePopupMenu); } public void createMenu(JMenu jMenu) { createMenu(jMenu, mainMenu); } private void createMenu(JComponent jComponent, Map> menus) { jComponent.removeAll(); boolean notEmpty = false; //UPDATE MenuData menuData = tableMenu.getMenuData(); for (AutoMenu jAutoMenu : menus.values()) { jAutoMenu.setMenuData(menuData); } //COPY if (jComponent instanceof JPopupMenu) { jComponent.add(new JMenuCopy(jTable)); addSeparator(jComponent); notEmpty = true; } //TOOL MENU tableMenu.addToolMenu(jComponent); //COPY+ AutoMenu jcopyPlus = menus.get(MenuEnum.COPY_PLUS); if (jcopyPlus != null) { for (JComponent c : jcopyPlus.getMenuItems()) { jComponent.add(c); } notEmpty = true; } //FILTER JMenu filterMenu = tableMenu.getFilterMenu(); if (filterMenu != null) { jComponent.add(filterMenu); notEmpty = true; } //ASSET FILTER AutoMenu jAssetFilter = menus.get(MenuEnum.ASSET_FILTER); if (jAssetFilter != null) { for (JComponent c : jAssetFilter.getMenuItems()) { jComponent.add(c); } notEmpty = true; if (jAssetFilter instanceof JMenuAssetFilter) { JMenuAssetFilter jMenuAssetFilter = (JMenuAssetFilter) jAssetFilter; jMenuAssetFilter.setTool(tableMenu); } } //TRANSACTION FILTER AutoMenu jTransactionFilter = menus.get(MenuEnum.TRANSACTION_FILTER); if (jTransactionFilter != null) { for (JComponent c : jTransactionFilter.getMenuItems()) { jComponent.add(c); } notEmpty = true; if (jTransactionFilter instanceof JMenuTransactionFilter) { JMenuTransactionFilter jMenuAssetFilter = (JMenuTransactionFilter) jTransactionFilter; jMenuAssetFilter.setTool(tableMenu); } } //STOCKPILE (Add To) AutoMenu jStockpile = menus.get(MenuEnum.STOCKPILE); if (jStockpile != null) { for (JComponent c : jStockpile.getMenuItems()) { jComponent.add(c); } notEmpty = true; } //LOOKUP AutoMenu jLookup = menus.get(MenuEnum.LOOKUP); if (jLookup != null) { for (JComponent c : jLookup.getMenuItems()) { jComponent.add(c); } notEmpty = true; if (jLookup instanceof JMenuLookup) { JMenuLookup jMenuLookup = (JMenuLookup) jLookup; jMenuLookup.setTool(tableMenu); } } //EDIT AutoMenu jPrice = menus.get(MenuEnum.PRICE); if (jPrice != null) { for (JComponent c : jPrice.getMenuItems()) { jComponent.add(c); } notEmpty = true; } AutoMenu jName = menus.get(MenuEnum.NAME); if (jName != null) { for (JComponent c : jName.getMenuItems()) { jComponent.add(c); } notEmpty = true; } AutoMenu jTags = menus.get(MenuEnum.TAGS); if (jTags != null) { for (JComponent c : jTags.getMenuItems()) { jComponent.add(c); } notEmpty = true; } //LOADOUT AutoMenu jLoadout = menus.get(MenuEnum.LOADOUT); if (jLoadout != null) { for (JComponent c : jLoadout.getMenuItems()) { jComponent.add(c); } notEmpty = true; } //REPROCESSED AutoMenu jReprocessed = menus.get(MenuEnum.REPROCESSED); if (jReprocessed != null) { for (JComponent c : jReprocessed.getMenuItems()) { jComponent.add(c); } notEmpty = true; } //PRICE HISTORY AutoMenu jPriceHistory = menus.get(MenuEnum.PRICE_HISTORY); if (jPriceHistory != null) { for (JComponent c : jPriceHistory.getMenuItems()) { jComponent.add(c); } notEmpty = true; } //JUMPS AutoMenu jJumps = menus.get(MenuEnum.JUMPS); if (jJumps != null) { for (JComponent c : jJumps.getMenuItems()) { jComponent.add(c); } notEmpty = true; } AutoMenu jRouting = menus.get(MenuEnum.ROUTING); if (jRouting != null) { for (JComponent c : jRouting.getMenuItems()) { jComponent.add(c); } notEmpty = true; } //FORMULA AutoMenu jFormula = menus.get(MenuEnum.FORMULA); if (jFormula != null) { for (JComponent c : jFormula.getMenuItems()) { jComponent.add(c); } notEmpty = true; } //LOCATION AutoMenu jLocation = menus.get(MenuEnum.LOCATION); if (jLocation != null) { for (JComponent c : jLocation.getMenuItems()) { jComponent.add(c); } notEmpty = true; } AutoMenu jUi = menus.get(MenuEnum.UI); if (jUi != null) { for (JComponent c : jUi.getMenuItems()) { jComponent.add(c); } notEmpty = true; } //COLUMNS JMenu columnMenu = tableMenu.getColumnMenu(); if (columnMenu != null) { jComponent.add(columnMenu); notEmpty = true; } //INFO if (jComponent instanceof JPopupMenu) { tableMenu.addInfoMenu((JPopupMenu) jComponent); } //SUM AutoMenu jSum = menus.get(MenuEnum.SUM); if (jSum != null) { addSeparator(jComponent); for (JComponent c : jSum.getMenuItems()) { jComponent.add(c); } notEmpty = true; } jComponent.setEnabled(notEmpty); } private void updateMainTableMenu() { createMenu(program.getMainWindow().getMenu().getTableMenu()); } private void showTableHeaderPopupMenu(final MouseEvent e) { JPopupMenu jTableHeaderPopupMenu = new JPopupMenu(); JMenu columnMenu = tableMenu.getColumnMenu(); if (columnMenu != null) { for (Component component : columnMenu.getMenuComponents()) { //Clone! jTableHeaderPopupMenu.add(component); } } //SUM jTableHeaderPopupMenu.addSeparator(); AutoMenu jSum = tablePopupMenu.get(MenuEnum.SUM); if (jSum instanceof JMenuSum) { ((JMenuSum)jSum).updateMenuDataColumn(jTable.columnAtPoint(e.getPoint())); for (JComponent c : jSum.getMenuItems()) { jTableHeaderPopupMenu.add(c); } } jTableHeaderPopupMenu.show(e.getComponent(), e.getX(), e.getY()); } private void showTablePopupMenu(final MouseEvent e) { JPopupMenu jTablePopupMenu = new JPopupMenu(); selectClickedCell(e); //updateTableMenu(jTablePopupMenu); createMenu(jTablePopupMenu); jTablePopupMenu.show(e.getComponent(), e.getX(), e.getY()); } private void selectClickedCell(final MouseEvent e) { Object source = e.getSource(); if (source instanceof JTable) { JTable jSelectTable = (JTable) source; Point point = e.getPoint(); if (!jSelectTable.getVisibleRect().contains(point)) { //Ignore clickes outside table return; } int clickedRow = jSelectTable.rowAtPoint(point); int clickedColumn = jSelectTable.columnAtPoint(point); //Rows boolean clickInRowsSelection; if (jSelectTable.getRowSelectionAllowed()) { //clicked in selected rows? clickInRowsSelection = false; int[] selectedRows = jSelectTable.getSelectedRows(); for (int i = 0; i < selectedRows.length; i++) { if (selectedRows[i] == clickedRow) { clickInRowsSelection = true; break; } } } else { //Row selection not allowed - all rows selected clickInRowsSelection = true; } //Column boolean clickInColumnsSelection; if (jSelectTable.getColumnSelectionAllowed()) { //clicked in selected columns? clickInColumnsSelection = false; int[] selectedColumns = jSelectTable.getSelectedColumns(); for (int i = 0; i < selectedColumns.length; i++) { if (selectedColumns[i] == clickedColumn) { clickInColumnsSelection = true; break; } } } else { //Column selection not allowed - all columns selected clickInColumnsSelection = true; } //Clicked outside selection, select clicked cell if ( (!clickInRowsSelection || !clickInColumnsSelection) && clickedRow >= 0 && clickedColumn >= 0) { jSelectTable.setRowSelectionInterval(clickedRow, clickedRow); jSelectTable.setColumnSelectionInterval(clickedColumn, clickedColumn); } } } private class ListenerClass implements MouseListener, ListSelectionListener { int[] selectedColumns; int[] selectedRows; @Override public void mouseClicked(final MouseEvent e) { } @Override public void mousePressed(final MouseEvent e) { if (e.isPopupTrigger()) { if (e.getSource().equals(jTable)) { showTablePopupMenu(e); } if (jTable != null && e.getSource().equals(jTable.getTableHeader())) { showTableHeaderPopupMenu(e); } } } @Override public void mouseReleased(final MouseEvent e) { if (e.isPopupTrigger()) { if (e.getSource().equals(jTable)) { showTablePopupMenu(e); } if (jTable != null && e.getSource().equals(jTable.getTableHeader())) { showTableHeaderPopupMenu(e); } } } @Override public void mouseEntered(final MouseEvent e) { } @Override public void mouseExited(final MouseEvent e) { } @Override public void valueChanged(final ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { if (changed) { return; //already changed } if (selectedColumns == null || selectedRows == null || !Arrays.equals(selectedColumns, jTable.getSelectedColumns()) || !Arrays.equals(selectedRows, jTable.getSelectedRows())) { selectedColumns = jTable.getSelectedColumns(); selectedRows = jTable.getSelectedRows(); changed = true; } } } } public static void addSeparator(final JComponent jComponent) { if (jComponent instanceof JMenu) { JMenu jMenu = (JMenu) jComponent; jMenu.addSeparator(); } if (jComponent instanceof JPopupMenu) { JPopupMenu jPopupMenu = (JPopupMenu) jComponent; jPopupMenu.addSeparator(); } if (jComponent instanceof JDropDownButton) { JDropDownButton jDropDownButton = (JDropDownButton) jComponent; jDropDownButton.addSeparator(); } } protected static interface AutoMenu { public void setMenuData(MenuData menuData); public Collection getMenuItems(); } protected abstract static class JAutoMenu extends JMenu implements AutoMenu { protected Program program; protected MenuData menuData; public JAutoMenu(final String s, final Program program) { super(s); this.program = program; } @Override public final void setMenuData(MenuData menuData) { this.menuData = menuData; updateMenuData(); } @Override public Collection getMenuItems() { return Collections.singleton(this); } protected abstract void updateMenuData(); } protected abstract static class JAutoMenuComponent implements AutoMenu { protected Program program; protected MenuData menuData; public JAutoMenuComponent(final Program program) { this.program = program; } @Override public final void setMenuData(MenuData menuData) { this.menuData = menuData; updateMenuData(); } @Override public abstract Collection getMenuItems(); protected abstract void updateMenuData(); } public static interface TableMenu { public MenuData getMenuData(); public JMenu getFilterMenu(); public JMenu getColumnMenu(); public void addInfoMenu(JPopupMenu jPopupMenu); public void addToolMenu(JComponent jComponent); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/ColumnManager.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.GlazedLists; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog.Formula; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuJumps.Jump; import net.nikr.eve.jeveasset.i18n.GuiShared; public class ColumnManager & EnumTableColumn, Q> implements SimpleColumnManager { private static final Map> COLUMN_MANAGERS = new HashMap<>(); private static final Set loaded = new HashSet<>(); private final Program program; private final String toolName; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventTableModel tableModel; private final JAutoColumnTable jTable; private final FilterControl filterControl; private final Map> formulaColumns = new HashMap<>(); private final Map> jumpColumns = new HashMap<>(); private boolean locked = false; public ColumnManager(Program program, String toolName, EnumTableFormatAdaptor tableFormat, DefaultEventTableModel tableModel, JAutoColumnTable jTable, EventList eventList, FilterControl filterControl) { this.program = program; this.toolName = toolName; this.tableFormat = tableFormat; this.tableModel = tableModel; this.jTable = jTable; this.filterControl = filterControl; //Load columns if (!loaded.contains(toolName)) { loaded.add(toolName); load(); } //Reset cached Formula values on list changes eventList.addListEventListener(new ListEventListener() { @Override @SuppressWarnings("deprecation") public void listChanged(ListEvent listChanges) { if (locked) { return; } try { eventList.getReadWriteLock().readLock().lock(); List reset = new ArrayList<>(); //For each list event while(listChanges.next()) { switch (listChanges.getType()) { case ListEvent.DELETE: Q q = listChanges.getOldValue(); if (q != null) { reset.add(q); } break; case ListEvent.UPDATE: int index = listChanges.getIndex(); if (index >= 0 && index < eventList.size()) { reset.add(eventList.get(index)); } break; } } //Remove changed values if (!reset.isEmpty()) { for (Formula formula : formulaColumns.keySet()) { formula.getValues().keySet().removeAll(reset); } } } finally { eventList.getReadWriteLock().readLock().unlock(); } } }); if (filterControl != null) { jTable.getColumnModel().addColumnModelListener( new TableColumnModelListener() { @Override public void columnAdded(TableColumnModelEvent e) {} @Override public void columnRemoved(TableColumnModelEvent e) {} @Override public void columnMoved(TableColumnModelEvent e) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { filterControl.updateColumns(false); } }); } @Override public void columnMarginChanged(ChangeEvent e) { } @Override public void columnSelectionChanged(ListSelectionEvent e) { } }); } COLUMN_MANAGERS.put(toolName, this); } public static ColumnManager getColumnManager(String toolName) { return COLUMN_MANAGERS.get(toolName); } public Set getFormulas() { return formulaColumns.keySet(); } public Set getJumps() { return jumpColumns.keySet(); } public T[] getEnumConstants() { return tableFormat.getEnumConstants(); } private FormulaColumn get(Formula formula) { FormulaColumn column = formulaColumns.get(formula); if (column == null) { //Better save than sorry column = new FormulaColumn<>(formula); } return column; } private JumpColumn get(Jump jump) { JumpColumn column = jumpColumns.get(jump); if (column == null) { //Better save than sorry column = new JumpColumn<>(jump); } return column; } private void updateGUI() { tableModel.fireTableStructureChanged(); jTable.autoResizeColumns(); if (filterControl != null) { filterControl.updateColumns(true); } } private void remove(Formula remove) { tableFormat.removeColumn(get(remove)); formulaColumns.remove(remove); } private void remove(Jump remove) { tableFormat.removeColumn(get(remove)); jumpColumns.remove(remove); } private FormulaColumn add(Formula add) { FormulaColumn toColumn = get(add); tableFormat.addColumn(toColumn); formulaColumns.put(add, toColumn); return toColumn; } private JumpColumn add(Jump add) { JumpColumn toColumn = get(add); tableFormat.addColumn(toColumn); jumpColumns.put(add, toColumn); //Update Data updateJumpsData(add); return toColumn; } private boolean contains(Jump add) { return jumpColumns.containsKey(add); } public void editColumn(Formula remove, Formula add) { //Remove old remove(remove); //Add new add(add); //Update GUI updateGUI(); //Settings Settings.lock("Formulas (Edit)"); Settings.get().getTableFormulas(toolName).remove(remove); Settings.get().getTableFormulas(toolName).add(add); Settings.unlock("Formulas (Edit)"); program.saveSettings("Formulas (Edit)"); } public void removeColumn(Formula remove) { //Remove remove(remove); //Update GUI updateGUI(); //Settings Settings.lock("Formulas (Remove)"); Settings.get().getTableFormulas(toolName).remove(remove); Settings.unlock("Formulas (Remove)"); program.saveSettings("Formulas (Remove)"); } public void removeColumn(Jump remove) { //Remove old remove(remove); //Update GUI updateGUI(); //ToDo //Settings Settings.lock("Jumps (remove)"); Settings.get().getTableJumps(toolName).remove(remove); Settings.unlock("Jumps (remove)"); program.saveSettings("Jumps (remove)"); } private void load() { //Add for (Formula add : Settings.get().getTableFormulas(toolName)) { add(add); } for (Jump add : Settings.get().getTableJumps(toolName)) { add(add); } //Update GUI updateGUI(); } @Override public FormulaColumn addColumn(Formula add) { //Add FormulaColumn column = add(add); //Update GUI updateGUI(); //Settings Settings.lock("Formulas (add)"); Settings.get().getTableFormulas(toolName).add(add); Settings.unlock("Formulas (add)"); program.saveSettings("Formulas (add)"); return column; } @Override public JumpColumn addColumn(Jump add) { if (contains(add)) { return null; //Skip existing } //Add JumpColumn column = add(add); //Update GUI updateGUI(); //Settings Settings.lock("Jumps (add)"); Settings.get().getTableJumps(toolName).add(add); Settings.unlock("Jumps (add)"); program.saveSettings("Jumps (add)"); return column; } public void addColumns(Collection locations) { //Convert List jumps = new ArrayList<>(); for (MyLocation location : locations) { Jump add = new Jump(location); if (contains(add)) { continue; //Skip existing } jumps.add(add); } //Add for (Jump add : jumps) { add(add); } //Update GUI updateGUI(); //Settings Settings.lock("Jumps (add)"); for (Jump add : jumps) { Settings.get().getTableJumps(toolName).add(add); } Settings.unlock("Jumps (add)"); program.saveSettings("Jumps (add)"); } public void clearJumpColumns() { //Remove for (Jump remove : Settings.get().getTableJumps(toolName)) { remove(remove); } //Update GUI updateGUI(); //Settings Settings.lock("Jumps (clear)"); Settings.get().getTableJumps(toolName).clear(); Settings.unlock("Jumps (clear)"); program.saveSettings("Jumps (clear)"); } public void resetFormulaData() { for (Formula formula : formulaColumns.keySet()) { formula.getValues().clear(); //Reset calculations } } public void lock() { locked = true; } public void unlock() { locked = false; } public void updateJumpsData(Jump jump) { for (LocationType locationType : program.getMainTabs().get(toolName).getLocations()) { MyLocation location = locationType.getLocation(); if (location == null) { continue; } long systemID = location.getSystemID(); if (systemID <= 0) { continue; } jump.addJump(locationType); } } public void updateJumpsData() { for (LocationType locationType : program.getMainTabs().get(toolName).getLocations()) { MyLocation location = locationType.getLocation(); if (location == null) { continue; } long systemID = location.getSystemID(); if (systemID <= 0) { continue; } for (Jump jump : Settings.get().getTableJumps(toolName)) { jump.addJump(locationType); } } } public static interface IndexColumn extends EnumTableColumn { public Integer getIndex(); public void setIndex(Integer index); } public static class FormulaColumn implements IndexColumn { private final Formula formula; public FormulaColumn(Formula formula) { this.formula = formula; } public Formula getFormula() { return formula; } @Override public Integer getIndex() { return formula.getIndex(); } @Override public void setIndex(Integer index) { formula.setIndex(index); } @Override public Class getType() { if (formula.isBoolean()) { return String.class; } else { return Double.class; } } @Override public Comparator getComparator() { return GlazedLists.comparableComparator(); } @Override public String getColumnName() { return formula.getColumnName(); } @Override public Object getColumnValue(Q from) { return formula; } @Override public String name() { return formula.getColumnName(); } @Override public String toString() { return getColumnName(); } @Override public int hashCode() { int hash = 7; hash = 37 * hash + Objects.hashCode(this.formula.getColumnName()); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final FormulaColumn other = (FormulaColumn) obj; if (!Objects.equals(this.formula.getColumnName(), other.formula.getColumnName())) { return false; } return true; } } public static class JumpColumn implements IndexColumn { private final Jump jump; public JumpColumn(Jump jump) { this.jump = jump; } public Jump getJump() { return jump; } @Override public Integer getIndex() { return jump.getIndex(); } @Override public void setIndex(Integer index) { jump.setIndex(index); } @Override public Class getType() { return Integer.class; } @Override public Comparator getComparator() { return GlazedLists.comparableComparator(); } @Override public String getColumnName() { return jump.getName(); } @Override public String getColumnToolTip() { return GuiShared.get().jumpsColumnToolTip(jump.getName()); } @Override public Object getColumnValue(Q from) { return jump.getJumps(from); } @Override public String name() { return jump.getName(); } @Override public String toString() { return getColumnName(); } @Override public int hashCode() { int hash = 3; hash = 59 * hash + (int) (this.jump.getSystemID() ^ (this.jump.getSystemID() >>> 32)); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final JumpColumn other = (JumpColumn) obj; return this.jump.getSystemID() == other.jump.getSystemID(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/EnumTableColumn.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table; import ca.odell.glazedlists.GlazedLists; import java.awt.Color; import java.awt.Component; import java.util.Comparator; import javax.swing.Icon; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.api.raw.RawNpcStanding; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.table.containers.ISK; import net.nikr.eve.jeveasset.gui.shared.table.containers.ModulePriceValue; /** * * @author Candle * @param */ public interface EnumTableColumn { public Class getType(); public Comparator getComparator(); public String getColumnName(); public Object getColumnValue(Q from); public String name(); public default boolean isColumnEditable(Object baseObject) { return false; } public default boolean isShowDefault() { return true; } public default boolean setColumnValue(Object baseObject, Object editedValue) { return false; } public default String getColumnToolTip() { return null; } public static Comparator getComparator(final Class type) { if (type.equals(String.class)) { return StringComparators.TO_STRING; } else if (type.equals(Icon.class)) { return null; //Not sortable } else if (type.equals(RawNpcStanding.FromType.class)) { return MyNpcStanding.FROM_TYPE_COMPARATOR; } else if (Comparable.class.isAssignableFrom(type)) { return GlazedLists.comparableComparator(); } else if (Component.class.isAssignableFrom(type) || ModulePriceValue.class.isAssignableFrom(type) || ISK.class.isAssignableFrom(type) || Color.class.isAssignableFrom(type) ) { return null; //Not sortable } else { throw new RuntimeException(type.getName() + " is not comparable"); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/EnumTableFormatAdaptor.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table; import ca.odell.glazedlists.gui.AdvancedTableFormat; import ca.odell.glazedlists.gui.WritableTableFormat; import com.udojava.evalex.Expression; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import net.nikr.eve.jeveasset.gui.shared.filter.SimpleTableFormat; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog.Formula; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager.IndexColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.NumberValue; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileTotal; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileTableFormat; import net.nikr.eve.jeveasset.i18n.GuiShared; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author Candle * @param * @param */ public class EnumTableFormatAdaptor & EnumTableColumn, Q> implements AdvancedTableFormat, WritableTableFormat, SimpleTableFormat { private static final Logger LOG = LoggerFactory.getLogger(EnumTableFormatAdaptor.class); public static enum ResizeMode { TEXT { @Override String getI18N() { return GuiShared.get().tableResizeText(); } }, WINDOW { @Override String getI18N() { return GuiShared.get().tableResizeWindow(); } }, NONE { @Override String getI18N() { return GuiShared.get().tableResizeNone(); } }; abstract String getI18N(); @Override public String toString() { return getI18N(); } } private final static Object NULL_PLACEHOLDER = new Object(); private final List listeners = new ArrayList<>(); private final Class enumClass; private final Map> extendedTableFormats = new HashMap<>(); private final List> shownColumns = new ArrayList<>(); private final Map> orderColumnsName = new HashMap<>(); private final List> allColumns = new ArrayList<>(); private final List> orderColumns = new ArrayList<>(); private final List> tempColumns = new ArrayList<>(); private final ColumnComparator columnComparator; private ResizeMode resizeMode; protected EnumTableFormatAdaptor(final Class enumClass) { this(enumClass, new ArrayList<>()); } protected EnumTableFormatAdaptor(final Class enumClass, final List> enumTableColumns) { this.enumClass = enumClass; for (EnumTableColumn column : enumTableColumns) { extendedTableFormats.put(column.name(), column); } allColumns.addAll(Arrays.asList(enumClass.getEnumConstants())); allColumns.addAll(extendedTableFormats.values()); columnComparator = new ColumnComparator(); resizeMode = ResizeMode.TEXT; reset(); } public T[] getEnumConstants() { return enumClass.getEnumConstants(); } public final void reset() { shownColumns.clear(); orderColumnsName.clear(); orderColumns.clear(); for (T t : enumClass.getEnumConstants()) { if (t.isShowDefault()) { shownColumns.add(t); } orderColumnsName.put(t.name(), t); } orderColumns.addAll(Arrays.asList(enumClass.getEnumConstants())); addTempColumns(); } private void addTempColumns() { for (EnumTableColumn column : tempColumns) { addColumn(column, false); } } /** * Used to add special columns (Ex: FormulaColumn and JumpColumn) * @param column */ @Override public void addColumn(EnumTableColumn column) { addColumn(column, true); } private void addColumn(EnumTableColumn column, boolean temp) { Integer index = null; if (column instanceof IndexColumn) { index = ((IndexColumn)column).getIndex(); } if (!shownColumns.contains(column)) { orderColumnsName.put(column.name(), column); shownColumns.add(column); if (index != null && index >= 0 && index < orderColumns.size()) { orderColumns.add(index, column); allColumns.add(index, column); updateColumns(); } else { orderColumns.add(column); allColumns.add(column); } if (temp) { tempColumns.add(column); } } } /** * Used to remove special columns (Ex: FormulaColumn and JumpColumn) * @param column */ public void removeColumn(EnumTableColumn column) { orderColumnsName.remove(column.name()); shownColumns.remove(column); orderColumns.remove(column); tempColumns.remove(column); allColumns.remove(column); } @Override public List> getShownColumns() { return shownColumns; } @Override public List> getAllColumns() { return allColumns; } public ResizeMode getResizeMode() { return resizeMode; } public void setResizeMode(final ResizeMode resizeMode) { if (resizeMode == null) { return; } this.resizeMode = resizeMode; } public void setColumns(final List columns) { if (columns == null) { return; } orderColumns.clear(); shownColumns.clear(); orderColumnsName.clear(); List originalColumns = new ArrayList<>(Arrays.asList(enumClass.getEnumConstants())); for (SimpleColumn column : columns) { try { T t = Enum.valueOf(enumClass, column.getEnumName()); orderColumns.add(t); orderColumnsName.put(t.name(), t); if (column.isShown()) { shownColumns.add(t); } } catch (IllegalArgumentException ex) { LOG.info("Removing column: " + column.getEnumName()); } } //Add new columns for (T t : originalColumns) { if (!orderColumns.contains(t)) { LOG.info("Adding column: " + t.getColumnName()); int index = originalColumns.indexOf(t); if (index > orderColumns.size()) { index = orderColumns.size(); } orderColumns.add(index, t); orderColumnsName.put(t.name(), t); if (t.isShowDefault()) { shownColumns.add(t); } } } addTempColumns(); updateColumns(); } public List getColumns() { List columns = new ArrayList<>(orderColumns.size()); for (EnumTableColumn t : orderColumns) { if (tempColumns.contains(t)) { //Ignore temp columns continue; } String columnName = t.getColumnName(); String enumName = t.name(); boolean shown = shownColumns.contains(t); columns.add(new SimpleColumn(enumName, columnName, shown)); } return columns; } public void moveColumn(final int from, final int to) { if (from == to) { return; } EnumTableColumn fromColumn = getColumn(from); EnumTableColumn toColumn = getColumn(to); int fromIndex = orderColumns.indexOf(fromColumn); orderColumns.remove(fromIndex); int toIndex = orderColumns.indexOf(toColumn); if (to > from) { toIndex++; } orderColumns.add(toIndex, fromColumn); //Update IndexColumn for (int i = 0; i < orderColumns.size(); i++) { EnumTableColumn column = orderColumns.get(i); if (column instanceof IndexColumn) { ((IndexColumn)column).setIndex(i); } } updateColumns(); } public void hideColumn(final T column) { if (!shownColumns.contains(column)) { return; } shownColumns.remove(column); updateColumns(); } public void showColumn(final T column) { if (shownColumns.contains(column)) { return; } shownColumns.add(column); updateColumns(); } public void addListener(ColumnValueChangeListener listener) { listeners.add(listener); } public void removeListener(ColumnValueChangeListener listener) { listeners.remove(listener); } private void notifyListeners() { for (ColumnValueChangeListener listener : listeners) { listener.columnValueChanged(); } } private EnumTableColumn getColumn(final int i) throws IndexOutOfBoundsException { return getShownColumns().get(i); } private void updateColumns() { Collections.sort(shownColumns, columnComparator); } @Override public Class getColumnClass(final int i) { try { return getColumn(i).getType(); } catch (IndexOutOfBoundsException ex) { return null; } } @Override public Comparator getColumnComparator(final int i) { try { return getColumn(i).getComparator(); } catch (IndexOutOfBoundsException ex) { return null; } } @Override public int getColumnCount() { return getShownColumns().size(); } @Override public String getColumnName(final int i) { try { return getColumn(i).getColumnName(); } catch (IndexOutOfBoundsException ex) { return null; } } public String getColumnToolTip(final int i) { try { return getColumn(i).getColumnToolTip(); } catch (IndexOutOfBoundsException ex) { return null; } } @Override public EnumTableColumn valueOf(String column) { EnumTableColumn enumTableColumn = extendedTableFormats.get(column); if (enumTableColumn != null) { return enumTableColumn; } return orderColumnsName.get(column); } @Override public Object getColumnValue(final Q e, final int i) { try { return getColumnValue(e, getColumn(i)); } catch (IndexOutOfBoundsException ex) { return null; } } @Override public Object getColumnValue(final Q e, final String columnName) { EnumTableColumn column = extendedTableFormats.get(columnName); if (column == null) { column = orderColumnsName.get(columnName); } return getColumnValue(e, column); } private Object getColumnValue(final Q e, final EnumTableColumn column) { if (column == null) { //Better safe than sorry return null; } Object object = column.getColumnValue(e); if (object instanceof Formula) { Formula formula = (Formula) object; Object value = formula.getValues().get(e); if (value == null) { //eval value = eval(formula, e); if (value == null) { value = NULL_PLACEHOLDER; } formula.getValues().put(e, value); } if (value.equals(NULL_PLACEHOLDER)) { //Handle NULL_PLACEHOLDER return null; } return value; } else { return object; } } private Object eval(Formula formula, Q e) { final Expression expression = formula.getExpression(); //Populate variableColumns if (formula.getVariableColumns().isEmpty()) { for (T t : enumClass.getEnumConstants()) { if (formula.getUsedVariables().contains(JFormulaDialog.getHardName(t))) { formula.getVariableColumns().add(t.name()); } } } //Set variables if (e instanceof StockpileTotal) { if (formula.isBoolean()) { return null; } StockpileTotal totalItem = (StockpileTotal) e; double total = 0.0; for (StockpileItem item : totalItem.getStockpile().getClaims()) { setVariables(formula, StockpileTableFormat.values(), item); BigDecimal value = safeEval(expression); if (value != null) { total = total + value.doubleValue(); } } return total; } else { //Default setVariables(formula, enumClass.getEnumConstants(), e); //Eval BigDecimal value = safeEval(expression); if (value == null) { return null; } else if (formula.isBoolean()) { return value.compareTo(BigDecimal.ZERO) > 0 ? "True" : "False"; } else { return value.doubleValue(); } } } public static BigDecimal safeEval(Expression expression) { try { return expression.eval(); } catch (RuntimeException ex) { return null; } } private static & EnumTableColumn, Q> void setVariables(Formula formula, T[] enumColumns, Q e) { final Expression expression = formula.getExpression(); for (T t : enumColumns) { if (!formula.getVariableColumns().contains(t.name())) { continue; } Number number = getValue(t, e); if (number != null) { expression.setVariable(JFormulaDialog.getHardName(t), new BigDecimal(number.toString())); } } } private static & EnumTableColumn, Q> Number getValue(T t, Q e) { if (Number.class.isAssignableFrom(t.getType())) { Number number = (Number) t.getColumnValue(e); if (number == null) { //Handle null return 0; } return number; } else if (NumberValue.class.isAssignableFrom(t.getType())) { NumberValue numberValue = (NumberValue) t.getColumnValue(e); if (numberValue == null) { //Handle null return 0; } Number number = numberValue.getNumber(); if (number == null) { //Handle null return 0; } return number; } else if (Date.class.isAssignableFrom(t.getType())) { Date date = (Date) t.getColumnValue(e); long diff = date.getTime() - System.currentTimeMillis(); return TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS); } return null; //Not a valid numeric column } //Used by the JSeparatorTable @Override public boolean isEditable(final Q baseObject, final int i) { try { return getColumn(i).isColumnEditable(baseObject); } catch (IndexOutOfBoundsException ex) { return false; } } @Override public Q setColumnValue(final Q baseObject, final Object editedValue, final int i) { try { boolean changed = getColumn(i).setColumnValue(baseObject, editedValue); if (changed) { notifyListeners(); } } catch (IndexOutOfBoundsException ex) { //No problem } return baseObject; } class ColumnComparator implements Comparator> { @Override public int compare(final EnumTableColumn o1, final EnumTableColumn o2) { return orderColumns.indexOf(o1) - orderColumns.indexOf(o2); } } public static class SimpleColumn { private final String enumName; private final String columnName; private boolean shown; public SimpleColumn(final String enumName, final boolean shown) { this.enumName = enumName; this.columnName = ""; this.shown = shown; } public SimpleColumn(final String enumName, final String columnName, final boolean shown) { this.enumName = enumName; this.columnName = columnName; this.shown = shown; } public String getColumnName() { return columnName; } public String getEnumName() { return enumName; } public boolean isShown() { return shown; } public void setShown(final boolean shown) { this.shown = shown; } } public static interface ColumnValueChangeListener { public void columnValueChanged(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/EventListManager.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table; import ca.odell.glazedlists.BasicEventList; import ca.odell.glazedlists.DebugList; import ca.odell.glazedlists.EventList; import java.util.ArrayList; import java.util.Collection; import java.util.List; import net.nikr.eve.jeveasset.CliOptions; public class EventListManager { private EventListManager() { } public static EventList create() { if (CliOptions.get().isDebug()) { DebugList debugList = new DebugList<>(); debugList.setLockCheckingEnabled(true); return debugList; } else { return new BasicEventList<>(); } } public static EventList create(Collection data) { EventList eventList = create(); try { eventList.getReadWriteLock().writeLock().lock(); eventList.addAll(data); } finally { eventList.getReadWriteLock().writeLock().unlock(); } return eventList; } public static List safeList(EventList eventList) { try { eventList.getReadWriteLock().readLock().lock(); return new ArrayList<>(eventList); } finally { eventList.getReadWriteLock().readLock().unlock(); } } public static boolean isEmpty(EventList eventList) { try { eventList.getReadWriteLock().readLock().lock(); return eventList.isEmpty(); } finally { eventList.getReadWriteLock().readLock().unlock(); } } public static boolean contains(EventList eventList, E e) { try { eventList.getReadWriteLock().readLock().lock(); return eventList.contains(e); } finally { eventList.getReadWriteLock().readLock().unlock(); } } public static int size(EventList eventList) { try { eventList.getReadWriteLock().readLock().lock(); return eventList.size(); } finally { eventList.getReadWriteLock().readLock().unlock(); } } public static E get(EventList eventList, int index) { try { eventList.getReadWriteLock().readLock().lock(); return eventList.get(index); } finally { eventList.getReadWriteLock().readLock().unlock(); } } public static int indexOf(EventList eventList, Object object) { try { eventList.getReadWriteLock().readLock().lock(); return eventList.indexOf(object); } finally { eventList.getReadWriteLock().readLock().unlock(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/EventModels.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.TextFilterator; import ca.odell.glazedlists.gui.TableFormat; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.GlazedListsSwing; import java.util.List; import javax.swing.JTable; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.gui.tabs.routing.SolarSystem; public class EventModels { //EventModels.createTableModel public static DefaultEventTableModel createTableModel(EventList source, TableFormat tableFormat) { // XXX - Workaround for java bug: https://bugs.openjdk.java.net/browse/JDK-8068824 //return new DefaultEventTableModel(createSwingThreadProxyList(source), tableFormat); return new FixedEventTableModel<>(createSwingThreadProxyList(source), tableFormat); } //EventModels.createSelectionModel public static DefaultEventSelectionModel createSelectionModel(EventList source) { return new DefaultEventSelectionModel<>(createSwingThreadProxyList(source)); } public static EventList createSwingThreadProxyList(EventList source) { final EventList result; source.getReadWriteLock().readLock().lock(); try { result = GlazedListsSwing.swingThreadProxyList(source); } finally { source.getReadWriteLock().readLock().unlock(); } return result; } // XXX - Workaround for java bug: https://bugs.openjdk.java.net/browse/JDK-8068824 public static class FixedEventTableModel extends DefaultEventTableModel { private JTable jTable; public FixedEventTableModel(EventList source, TableFormat tableFormat) { super(source, tableFormat); } public FixedEventTableModel(EventList source, boolean disposeSource, TableFormat tableFormat) { super(source, disposeSource, tableFormat); } public void setTable(JTable jTable) { this.jTable = jTable; } @Override public void fireTableStructureChanged() { if (jTable != null) { jTable.getTableHeader().setDraggedColumn(null); } super.fireTableStructureChanged(); } } public static class StringFilterator implements TextFilterator { @Override public void getFilterStrings(final List baseList, final String element) { if (element.length() > 0) { baseList.add(element); } } } public static class LocationFilterator implements TextFilterator { @Override public void getFilterStrings(final List baseList, final MyLocation element) { baseList.add(element.getLocation()); } } public static class ItemFilterator implements TextFilterator { @Override public void getFilterStrings(List baseList, Item element) { baseList.add(element.getTypeName()); } } public static class ViewFilterator implements TextFilterator { @Override public void getFilterStrings(final List baseList, final View element) { baseList.add(element.getName()); } } public static class SolarSystemFilterator implements TextFilterator { @Override public void getFilterStrings(final List baseList, final SolarSystem element) { baseList.add(element.getName()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/JAutoColumnTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table; import ca.odell.glazedlists.gui.TableFormat; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import java.awt.Container; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JViewport; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.table.TableModel; import javax.swing.text.JTextComponent; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.shared.CopyHandler; import net.nikr.eve.jeveasset.gui.shared.InstantToolTip; import net.nikr.eve.jeveasset.gui.shared.TextManager; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.ResizeMode; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.SimpleColumn; import net.nikr.eve.jeveasset.gui.shared.table.EventModels.FixedEventTableModel; import net.nikr.eve.jeveasset.gui.shared.table.SeparatorTableCell.JSeparatorPanel; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.BetterNumberEditor; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.ComponentEditor; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.ComponentRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.DateCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.DateOnlyCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.DoubleCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.FloatCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.IconTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.IntegerCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.LongCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.StandingTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.TagsCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.TextIconTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.ToStringCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.containers.AssetContainer; import net.nikr.eve.jeveasset.gui.shared.table.containers.DateOnly; import net.nikr.eve.jeveasset.gui.shared.table.containers.Duration; import net.nikr.eve.jeveasset.gui.shared.table.containers.ExpirerDate; import net.nikr.eve.jeveasset.gui.shared.table.containers.Standing; import net.nikr.eve.jeveasset.gui.shared.table.containers.TextIcon; import net.nikr.eve.jeveasset.gui.shared.table.containers.YesNo; public class JAutoColumnTable extends JTable { private JViewport jViewport = null; private int size = 0; private ResizeMode resizeMode = null; private boolean loadingWidth = false; private final Map columnsWidth = new HashMap<>(); private final Map rowsWidth = new HashMap<>(); protected Program program; private boolean autoResizeLock = false; private final Set disableColumnResizeCache = new HashSet<>(); private boolean overwrite; public JAutoColumnTable(final Program program, final TableModel tableModel) { super(tableModel); this.program = program; // XXX - Workaround for java bug: https://bugs.openjdk.java.net/browse/JDK-8068824 if (tableModel instanceof FixedEventTableModel) { FixedEventTableModel eventTableModel = (FixedEventTableModel) tableModel; eventTableModel.setTable(this); } try { overwrite = !getClass().getMethod("getCellRenderer", int.class, int.class).getDeclaringClass().equals(JTable.class); } catch (NoSuchMethodException ex) { overwrite = true; //should never happen, but, will use safe value if it does } catch (SecurityException ex) { overwrite = true; //should never happen, but, will use safe value if it does } //Listeners ListenerClass listener = new ListenerClass(); this.addHierarchyListener(listener); this.getModel().addTableModelListener(listener); this.addPropertyChangeListener("model", listener); this.getTableHeader().addMouseListener(listener); this.addPropertyChangeListener("tableHeader", listener); this.getColumnModel().addColumnModelListener(listener); this.addPropertyChangeListener("columnModel", listener); CopyHandler.installCopyFormatter(this); //Renders this.setDefaultRenderer(Float.class, new FloatCellRenderer()); this.setDefaultRenderer(Double.class, new DoubleCellRenderer()); this.setDefaultRenderer(Long.class, new LongCellRenderer()); this.setDefaultRenderer(Integer.class, new IntegerCellRenderer()); this.setDefaultRenderer(Date.class, new DateCellRenderer()); this.setDefaultRenderer(DateOnly.class, new DateOnlyCellRenderer()); this.setDefaultRenderer(Duration.class, new ToStringCellRenderer(SwingConstants.RIGHT)); this.setDefaultRenderer(String.class, new ToStringCellRenderer(SwingConstants.LEFT)); this.setDefaultRenderer(Object.class, new ToStringCellRenderer()); this.setDefaultRenderer(AssetContainer.class, new ToStringCellRenderer(SwingConstants.LEFT)); this.setDefaultRenderer(Enum.class, new ToStringCellRenderer(SwingConstants.LEFT)); this.setDefaultRenderer(Tags.class, new TagsCellRenderer()); this.setDefaultRenderer(YesNo.class, new ToStringCellRenderer(SwingConstants.CENTER)); this.setDefaultRenderer(ExpirerDate.class, new ToStringCellRenderer(SwingConstants.CENTER)); this.setDefaultRenderer(Icon.class, new IconTableCellRenderer()); this.setDefaultRenderer(TextIcon.class, new TextIconTableCellRenderer()); this.setDefaultRenderer(Standing.class, new StandingTableCellRenderer()); this.setDefaultRenderer(Component.class, new ComponentRenderer()); this.setDefaultEditor(Component.class, new ComponentEditor(this.getDefaultEditor(Component.class))); this.setDefaultEditor(Number.class, new BetterNumberEditor()); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { autoResizeColumns(); } }); fixScrollPaneRedraw(); } @Override protected JTableHeader createDefaultTableHeader() { JTableHeader jTableHeader = new JTableHeader(columnModel) { @Override public String getToolTipText(MouseEvent e) { java.awt.Point p = e.getPoint(); int index = columnModel.getColumnIndexAtX(p.x); if (index < 0 || index >= columnModel.getColumnCount()) { return null; } int realIndex = columnModel.getColumn(index).getModelIndex(); return getEnumTableFormatAdaptor().getColumnToolTip(realIndex); } }; InstantToolTip.install(jTableHeader); return jTableHeader; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); if (component instanceof JSeparatorPanel) { //Ignore Separator Panels return component; } //Default Colors if (isCellSelected(row, column)) { component.setForeground(this.getSelectionForeground()); component.setBackground(this.getSelectionBackground()); } else { component.setForeground(this.getForeground()); //Highlight selected row if (Settings.get().isHighlightSelectedRows() && this.isRowSelected(row)) { ColorSettings.config(component, ColorEntry.GLOBAL_SELECTED_ROW_HIGHLIGHTING); return component; } else { component.setBackground(this.getBackground()); } } return component; } @Override public Component prepareEditor(TableCellEditor editor, int row, int column) { Component component = super.prepareEditor(editor, row, column); if (component instanceof JTextComponent) { JTextComponent jTextComponent = (JTextComponent) component; TextManager.installTextComponent(jTextComponent); jTextComponent.selectAll(); } else if (component instanceof Container) { TextManager.installAll((Container) component); } return component; } public void lock() { autoResizeLock = true; } public void unlock() { if (isLocked()) { //only if locked autoResizeLock = false; //unlock autoResizeColumns(); //Update after unlock } } public boolean isLocked() { return autoResizeLock; } public final void autoResizeColumns() { if (isLocked()) { return; } EnumTableFormatAdaptor tableFormat = getEnumTableFormatAdaptor(); loadingWidth = true; if (tableFormat == null || tableFormat.getResizeMode() == ResizeMode.TEXT) { resizeColumnsText(); } else if (tableFormat.getResizeMode() == ResizeMode.WINDOW) { resizeColumnsWindow(); } else if (tableFormat.getResizeMode() == ResizeMode.NONE) { resizeColumnsNone(); } loadingWidth = false; } public void setColumnsWidth(final Map columnsWidth) { if (columnsWidth != null) { this.columnsWidth.putAll(columnsWidth); } } public Map getColumnsWidth() { return columnsWidth; } public void disableColumnResizeCache(EnumTableColumn column) { disableColumnResizeCache.add(column.getColumnName()); } public void enableColumnResizeCache(EnumTableColumn column) { disableColumnResizeCache.remove(column.getColumnName()); } private JTable getTable() { return this; } private DefaultEventTableModel getEventTableModel() { TableModel model = this.getModel(); if (model instanceof DefaultEventTableModel) { return (DefaultEventTableModel) model; } else { return null; } } private EnumTableFormatAdaptor getEnumTableFormatAdaptor() { if (getEventTableModel() != null) { TableFormat tableFormat = getEventTableModel().getTableFormat(); if (tableFormat instanceof EnumTableFormatAdaptor) { return (EnumTableFormatAdaptor) tableFormat; } } return null; } private JScrollPane getParentScrollPane() { Container container = this.getParent(); if (container != null) { container = container.getParent(); } if (container instanceof JScrollPane) { return (JScrollPane) container; } else { return null; } } /** * This is a work-around for issue #254. The JScrollPane viewport gets * corrupted when it is moved to the right with the horizontal scrollbar. * The following AdjustmentListener cannot fix the issue but it forces * AWT to repaint the viewport content. Because the event firing frequency * is lower than the viewport scroll rate, it may still flicker during * the scrolling, but at least ensures that the viewport is drawn properly * when the scrolling is stopped. * This is bug somewhere between OpenJDK and certain graphics drivers * under Linux and can be fixed by disabling the driver's acceleration. * @author Jan */ private void fixScrollPaneRedraw() { /* This component has not been added to the JScrollPanel at * construction time. This one listens to an ANCESTOR_ADD * event and registers the repaint method at the JScrollPanel * parent as soon as this component has been added to it. */ this.addAncestorListener(new AncestorListener() { @Override public void ancestorAdded(final AncestorEvent ae) { JComponent jComponent = ae.getComponent(); if (jComponent instanceof JAutoColumnTable) { JAutoColumnTable jTable = (JAutoColumnTable) jComponent; JScrollPane jScrollPane = jTable.getParentScrollPane(); if (jScrollPane != null) { jScrollPane.getHorizontalScrollBar().addAdjustmentListener(new JScrollPaneAdjustmentListener(jScrollPane)); } } } @Override public void ancestorMoved(final AncestorEvent event) { } @Override public void ancestorRemoved(final AncestorEvent event) { } }); } private JViewport getParentViewport() { Container container = this.getParent(); if (container instanceof JViewport) { return (JViewport) container; } else { return null; } } private void resizeColumnsText() { size = 0; if (resizeMode != ResizeMode.TEXT) { resizeMode = ResizeMode.TEXT; this.getTableHeader().setResizingAllowed(false); } for (int i = 0; i < getColumnCount(); i++) { size = size + resizeColumn(this, getColumnModel().getColumn(i), i); } updateScroll(); } public void resizeColumnsWindow() { if (resizeMode != ResizeMode.WINDOW) { //Only do once resizeMode = ResizeMode.WINDOW; this.getTableHeader().setResizingAllowed(true); for (int i = 0; i < getColumnCount(); i++) { getColumnModel().getColumn(i).setPreferredWidth(75); } } updateScroll(); } public void resizeColumnsNone() { if (resizeMode != ResizeMode.NONE) { //Only do once resizeMode = ResizeMode.NONE; this.getTableHeader().setResizingAllowed(true); } EnumTableFormatAdaptor tableFormat = getEnumTableFormatAdaptor(); List columns = tableFormat.getColumns(); int i = 0; for (SimpleColumn column : columns) { if (column.isShown()) { Integer width = columnsWidth.get(column.getEnumName()); if (width != null) { getColumnModel().getColumn(i).setPreferredWidth(width); } i++; } } updateScroll(); } private void updateScroll() { EnumTableFormatAdaptor tableFormat = getEnumTableFormatAdaptor(); if (tableFormat == null || tableFormat.getResizeMode() == ResizeMode.TEXT) { if (jViewport != null && size < jViewport.getSize().width) { this.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); } else { this.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); } } else if (tableFormat.getResizeMode() == ResizeMode.WINDOW) { this.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); } else if (tableFormat.getResizeMode() == ResizeMode.NONE) { this.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); } } private int resizeColumn(final JTable jTable, final TableColumn column, final int columnIndex) { //Header width TableCellRenderer renderer = column.getHeaderRenderer(); if (renderer == null) { renderer = jTable.getTableHeader().getDefaultRenderer(); } Component component = renderer.getTableCellRendererComponent(jTable, column.getHeaderValue(), false, false, 0, columnIndex); int maxWidth = component.getPreferredSize().width; if (!overwrite) { renderer = column.getCellRenderer(); if (renderer == null) { renderer = getDefaultRenderer(getColumnClass(columnIndex)); } } String columnName = (String) column.getHeaderValue(); boolean useCache = !disableColumnResizeCache.contains(columnName); //Rows width final int rowCount = jTable.getRowCount(); for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) { final Object cellValue = jTable.getValueAt(rowIndex, columnIndex); //Get cell value if (cellValue == null) { //Ignore null continue; } Integer savedWidth; if (useCache) { savedWidth = rowsWidth.get(cellValue); } else { savedWidth = null; } if (savedWidth != null) { //Load row width maxWidth = Math.max(maxWidth, savedWidth); } else { //Calculate the row width if (overwrite) { renderer = jTable.getCellRenderer(rowIndex, columnIndex); } //Ignore SeparatorTableCell if (renderer instanceof SeparatorTableCell) { continue; } component = renderer.getTableCellRendererComponent(jTable, jTable.getValueAt(rowIndex, columnIndex), false, false, rowIndex, columnIndex); int width = component.getPreferredSize().width; if (useCache) { rowsWidth.put(cellValue, width); } maxWidth = Math.max(maxWidth, width); } } //Add margin maxWidth = maxWidth + 4; //Set width column.setPreferredWidth(maxWidth); return maxWidth; //Return width } public void saveColumnsWidth() { EnumTableFormatAdaptor tableFormat = getEnumTableFormatAdaptor(); if (!loadingWidth && tableFormat != null && tableFormat.getResizeMode() == ResizeMode.NONE) { List columns = tableFormat.getColumns(); int i = 0; for (SimpleColumn column : columns) { if (column.isShown()) { int width = getColumnModel().getColumn(i).getPreferredWidth(); columnsWidth.put(column.getEnumName(), width); i++; } } program.saveSettings("Columns (Width)"); //Save Columns Width } } private class ListenerClass implements TableModelListener, ComponentListener, PropertyChangeListener, HierarchyListener, TableColumnModelListener, MouseListener { private boolean columnMoved = false; private boolean columnResized = false; private int from = 0; private int to = 0; private int rowsLastTime = 0; private int rowsCount = 0; @Override public void tableChanged(final TableModelEvent e) { //XXX - Workaround for Java 7 if (getTable().isEditing()) { getTable().getCellEditor().cancelCellEditing(); } if (e.getType() == TableModelEvent.DELETE) { rowsCount = rowsCount - (Math.abs(e.getFirstRow() - e.getLastRow()) + 1); } if (e.getType() == TableModelEvent.INSERT) { rowsCount = rowsCount + (Math.abs(e.getFirstRow() - e.getLastRow()) + 1); } if (Math.abs(rowsLastTime + rowsCount) == getRowCount() //Last Table Update && (e.getType() != TableModelEvent.UPDATE || (e.getType() == TableModelEvent.UPDATE && e.getFirstRow() >= 0))) { rowsLastTime = getRowCount(); rowsCount = 0; autoResizeColumns(); } } @Override public void componentResized(final ComponentEvent e) { updateScroll(); } @Override public void componentMoved(final ComponentEvent e) { } @Override public void componentShown(final ComponentEvent e) { } @Override public void componentHidden(final ComponentEvent e) { } @Override public void propertyChange(final PropertyChangeEvent evt) { Object newValue = evt.getNewValue(); Object oldValue = evt.getOldValue(); if (newValue instanceof JTableHeader && oldValue instanceof JTableHeader) { JTableHeader newModel = (JTableHeader) newValue; JTableHeader oldModel = (JTableHeader) oldValue; oldModel.removeMouseListener(this); newModel.addMouseListener(this); } if (newValue instanceof TableColumnModel && oldValue instanceof TableColumnModel) { TableColumnModel newModel = (TableColumnModel) newValue; TableColumnModel oldModel = (TableColumnModel) oldValue; oldModel.removeColumnModelListener(this); newModel.addColumnModelListener(this); } if (newValue instanceof TableModel && oldValue instanceof TableModel) { TableModel newModel = (TableModel) newValue; TableModel oldModel = (TableModel) oldValue; oldModel.removeTableModelListener(this); newModel.addTableModelListener(this); } } @Override public void hierarchyChanged(final HierarchyEvent e) { if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) == HierarchyEvent.PARENT_CHANGED) { if (jViewport != null) { jViewport.removeComponentListener(this); } jViewport = getParentViewport(); if (jViewport != null) { jViewport.addComponentListener(this); } } } @Override public void columnAdded(final TableColumnModelEvent e) { } @Override public void columnRemoved(final TableColumnModelEvent e) { } @Override public void columnMoved(final TableColumnModelEvent e) { if (e.getFromIndex() != e.getToIndex()) { if (!columnMoved) { from = e.getFromIndex(); } to = e.getToIndex(); columnMoved = true; } } @Override public void columnMarginChanged(final ChangeEvent e) { columnResized = true; } @Override public void columnSelectionChanged(final ListSelectionEvent e) { } @Override public void mouseClicked(final MouseEvent e) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { autoResizeColumns(); //Sorted! } }); } @Override public void mousePressed(final MouseEvent e) { columnMoved = false; columnResized = false; } @Override public void mouseReleased(final MouseEvent e) { if (columnMoved) { columnMoved = false; EnumTableFormatAdaptor tableFormat = getEnumTableFormatAdaptor(); DefaultEventTableModel model = getEventTableModel(); if (tableFormat != null && model != null) { tableFormat.moveColumn(from, to); model.fireTableStructureChanged(); if (from != to) { program.saveSettings("Columns (Moved)"); //Save Columns (Moved) } } autoResizeColumns(); } if (columnResized) { columnResized = false; saveColumnsWidth(); } } @Override public void mouseEntered(final MouseEvent e) { } @Override public void mouseExited(final MouseEvent e) { } } /** * @see JAutoColumnTable#fixScrollPaneRedraw() */ private class JScrollPaneAdjustmentListener implements AdjustmentListener { /** * Holds the JScrollPane we want to force repainting its content. */ private final JScrollPane jScrollPane; /** * Holds the last scrollbar position for direction tracking. */ private int lastValue; private boolean repaint; public JScrollPaneAdjustmentListener(final JScrollPane jScrollPane) { this.jScrollPane = jScrollPane; repaint = false; } @Override public void adjustmentValueChanged(final AdjustmentEvent e) { if (e.getValue() > lastValue) { // scrollbar has been dragged to the right repaint = true; } if (!e.getValueIsAdjusting() && repaint) { //Done scrolling - repaint if needed jScrollPane.repaint(); repaint = false; } lastValue = e.getValue(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/JEditColumnsDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import javax.swing.*; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Colors; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.SimpleColumn; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JEditColumnsDialog & EnumTableColumn, Q> extends JDialogCentered { private enum EditColumnsAction { OK, CANCEL, CHECK_ALL } private final DefaultListModel listModel = new DefaultListModel<>(); private final JList jColumns; private final JCheckBox jAll; private final JButton jOk; private final JButton jCancel; private final JTextArea jInfo; private final EnumTableFormatAdaptor adaptor; public JEditColumnsDialog(final Program program, final EnumTableFormatAdaptor adaptor) { super(program, GuiShared.get().tableColumnsTitle(), Images.TABLE_COLUMN_SHOW.getImage()); this.adaptor = adaptor; ListenerClass listener = new ListenerClass(); jInfo = new JTextArea(); jInfo.setFont(jPanel.getFont()); jInfo.setOpaque(false); jInfo.setBackground(Colors.COMPONENT_TRANSPARENT.getColor()); jInfo.setBorder(null); jInfo.setFocusable(false); jInfo.setEditable(false); jInfo.setLineWrap(true); jInfo.setWrapStyleWord(true); jInfo.setText(GuiShared.get().tableColumnsTip()); jColumns = new JList<>(listModel); jColumns.setCellRenderer(new JCheckBoxListRenderer(jColumns.getCellRenderer())); jColumns.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); //jList.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1)); jColumns.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(final MouseEvent event) { // Get index of item clicked int index = jColumns.locationToIndex(event.getPoint()); SimpleColumn column = jColumns.getModel().getElementAt(index); // Toggle selected state column.setShown(!column.isShown()); updateAll(); // Repaint cell jColumns.repaint(jColumns.getCellBounds(index, index)); } }); JScrollPane jColumnsScroll = new JScrollPane(jColumns); jCancel = new JButton(GuiShared.get().cancel()); jCancel.setActionCommand(EditColumnsAction.CANCEL.name()); jCancel.addActionListener(listener); jAll = new JCheckBox(GuiShared.get().checkAll()); jAll.setActionCommand(EditColumnsAction.CHECK_ALL.name()); jAll.addActionListener(listener); jOk = new JButton(GuiShared.get().ok()); jOk.setActionCommand(EditColumnsAction.OK.name()); jOk.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jAll) .addGroup(layout.createSequentialGroup() .addGap(2) .addComponent(jColumnsScroll, 300, 300, 300) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jInfo, 300, 300, 300) .addGroup(layout.createSequentialGroup() .addComponent(jOk, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jAll, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jColumnsScroll, 300, 400, Integer.MAX_VALUE) .addComponent(jInfo, 50, 50, 50) .addGroup(layout.createParallelGroup() .addComponent(jOk, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } @Override protected JComponent getDefaultFocus() { return jOk; } @Override protected JButton getDefaultButton() { return jOk; } @Override protected void windowShown() { } @Override public void setVisible(final boolean b) { if (b) { load(); } super.setVisible(b); } private void load() { listModel.clear(); for (SimpleColumn column : adaptor.getColumns()) { listModel.addElement(column); } updateAll(); } private void updateAll() { boolean allCheck = true; for (int i = 0; i < listModel.size(); i++) { SimpleColumn column = listModel.getElementAt(i); if (!column.isShown()) { allCheck = false; break; } } jAll.setSelected(allCheck); } @Override protected void save() { List columns = new ArrayList<>(); for (int i = 0; i < listModel.size(); i++) { columns.add(listModel.getElementAt(i)); } adaptor.setColumns(columns); program.saveSettings("Columns (Edit)"); //Save Columns (Changed - Edit Columns) setVisible(false); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (EditColumnsAction.OK.name().equals(e.getActionCommand())) { save(); } if (EditColumnsAction.CHECK_ALL.name().equals(e.getActionCommand())) { boolean check = jAll.isSelected(); for (int i = 0; i < listModel.size(); i++) { SimpleColumn column = listModel.getElementAt(i); column.setShown(check); } jColumns.repaint(); } if (EditColumnsAction.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); } } } private class JCheckBoxListRenderer implements ListCellRenderer { private final JCheckBox checkBox = new JCheckBox(); private final ListCellRenderer renderer; public JCheckBoxListRenderer(ListCellRenderer renderer) { this.renderer = renderer; } @Override public Component getListCellRendererComponent(JList list, SimpleColumn value, int index, boolean isSelected, boolean cellHasFocus) { JLabel jLabel = (JLabel) renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); //Formating checkBox.setEnabled(jLabel.isEnabled()); checkBox.setFont(jLabel.getFont()); checkBox.setBackground(jLabel.getBackground()); checkBox.setForeground(jLabel.getForeground()); checkBox.setBorder(jLabel.getBorder()); //Values checkBox.setSelected(value.isShown()); checkBox.setText(value.getColumnName()); return checkBox; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/JSeparatorTable.java ================================================ /* Glazed Lists (c) 2003-2006 */ /* http://publicobject.com/glazedlists/ publicobject.com,*/ /* O'Dell Engineering Ltd.*/ package net.nikr.eve.jeveasset.gui.shared.table; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.JComponent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.TableModelEvent; import javax.swing.plaf.basic.BasicTableUI; import javax.swing.table.*; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; /** * @author Jesse Wilson */ public class JSeparatorTable extends JAutoColumnTable { /** working with separator cells. */ private TableCellRenderer separatorRenderer; private TableCellEditor separatorEditor; private final SeparatorList separatorList; private final Map expandedSate = new HashMap<>(); private final List selectedRows = new ArrayList<>(); //XXX - Workaround for Autoscroller less then optimal behavior on SeparatorList.Separator private boolean defaultState = true; public JSeparatorTable(final Program program, final DefaultEventTableModel tableModel, SeparatorList separatorList) { super(program, tableModel); setUI(new SpanTableUI()); this.separatorList = separatorList; // use a toString() renderer for the separator this.separatorRenderer = getDefaultRenderer(Object.class); } public void expandSeparators(final boolean expand) { clearExpandedState(); //Reset defaultState = expand; final int newLimit = expand ? Integer.MAX_VALUE : 0; lock(); final DefaultEventSelectionModel selectModel = getEventSelectionModel(); if (selectModel != null) { selectModel.setEnabled(false); } try { separatorList.getReadWriteLock().readLock().lock(); for (int i = 0; i < separatorList.size(); i++) { Object object = separatorList.get(i); if (object instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) object; Object first = separator.first(); if (first instanceof StockpileItem && ((StockpileItem) first).isGroupCollapsed(expand)) { continue; } if (separator.getLimit() != newLimit) { try { separatorList.getReadWriteLock().readLock().unlock(); separatorList.getReadWriteLock().writeLock().lock(); separator.setLimit(newLimit); } finally { separatorList.getReadWriteLock().writeLock().unlock(); separatorList.getReadWriteLock().readLock().lock(); } } } } } finally { separatorList.getReadWriteLock().readLock().unlock(); } if (selectModel != null) { selectModel.setEnabled(true); } unlock(); } public void clearExpandedState() { expandedSate.clear(); defaultState = true; } public void saveExpandedState() { try { separatorList.getReadWriteLock().readLock().lock(); for (int i = 0; i < separatorList.size(); i++) { Object object = separatorList.get(i); if (object instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) object; final int limit = separator.getLimit(); if (limit == 0) { //Collapsed for (Object item : separator.getGroup()) { expandedSate.put(item, false); } } else { for (int x = i + 1; x < separatorList.size(); x++) { Object xObject = separatorList.get(x); if (xObject instanceof SeparatorList.Separator) { break; } expandedSate.put(xObject, true); } } } } } finally { separatorList.getReadWriteLock().readLock().unlock(); } } public void loadExpandedState() { try { separatorList.getReadWriteLock().readLock().lock(); for (int i = 0; i < separatorList.size(); i++) { Object object = separatorList.get(i); if (object instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) object; Boolean expanded = null; final int oldLimit = separator.getLimit(); if (separator.getLimit() == 0) { //Collapsed Object first = separator.first(); //Lets try first expanded = expandedSate.get(first); if (expanded == null) { //No luck, now it's going to get expensive for (Object item : separator.getGroup()) { expanded = expandedSate.get(item); if (expanded != null) { break; } } } } else { for (int x = i + 1; x < separatorList.size(); x++) { Object xObject = separatorList.get(x); if (xObject instanceof SeparatorList.Separator) { break; } expanded = expandedSate.get(xObject); if (expanded != null) { break; } } } if (expanded == null) { expanded = defaultState; } final int newLimit = expanded ? Integer.MAX_VALUE : 0; if (oldLimit != newLimit) { try { separatorList.getReadWriteLock().readLock().unlock(); separatorList.getReadWriteLock().writeLock().lock(); separator.setLimit(newLimit); } finally { separatorList.getReadWriteLock().writeLock().unlock(); separatorList.getReadWriteLock().readLock().lock(); } } } } } finally { separatorList.getReadWriteLock().readLock().unlock(); } } private DefaultEventSelectionModel getEventSelectionModel() { if (selectionModel instanceof DefaultEventSelectionModel) { return (DefaultEventSelectionModel) selectionModel; } else { return null; } } /** * A convenience method to cast the TableModel to the expected * EventTableModel implementation. * * @return the EventTableModel that backs this table */ private DefaultEventTableModel getEventTableModel() { return (DefaultEventTableModel) getModel(); } /** {@inheritDoc} */ @Override public Rectangle getCellRect(final int row, final int column, final boolean includeSpacing) { final DefaultEventTableModel eventTableModel = getEventTableModel(); // sometimes JTable asks for a cellrect that doesn't exist anymore, due // to an editor being installed before a bunch of rows were removed. // In this case, just return an empty rectangle, since it's going to // be discarded anyway if (row >= eventTableModel.getRowCount() || row < 0) { return new Rectangle(); } // if it's the separator row, return the entire row as one big rectangle Object rowValue = eventTableModel.getElementAt(row); if (rowValue instanceof SeparatorList.Separator) { Rectangle firstColumn = super.getCellRect(row, 0, includeSpacing); Rectangle lastColumn = super.getCellRect(row, getColumnCount() - 1, includeSpacing); return firstColumn.union(lastColumn); // otherwise it's business as usual } else { return super.getCellRect(row, column, includeSpacing); } } public Rectangle getCellRectWithoutSpanning(final int row, final int column, final boolean includeSpacing) { return super.getCellRect(row, column, includeSpacing); } /** {@inheritDoc} */ @Override public Object getValueAt(final int row, final int column) { final Object rowValue = getEventTableModel().getElementAt(row); // if it's the separator row, return the value directly if (rowValue instanceof SeparatorList.Separator) { return rowValue; } // otherwise it's business as usual return super.getValueAt(row, column); } @Override public void setValueAt(Object aValue, int row, int column) { final Object rowValue = getEventTableModel().getElementAt(row); // if it's the separator row, ignore the call if (rowValue instanceof SeparatorList.Separator) { return; } // otherwise it's business as usual super.setValueAt(aValue, row, column); } /** {@inheritDoc} */ @Override public TableCellRenderer getCellRenderer(final int row, final int column) { // if it's the separator row, use the separator renderer if (getEventTableModel().getElementAt(row) instanceof SeparatorList.Separator) { return separatorRenderer; } // otherwise it's business as usual return super.getCellRenderer(row, column); } /** {@inheritDoc} */ @Override public TableCellEditor getCellEditor(final int row, final int column) { // if it's the separator row, use the separator editor if (getEventTableModel().getElementAt(row) instanceof SeparatorList.Separator) { return separatorEditor; } // otherwise it's business as usual return super.getCellEditor(row, column); } /** {@inheritDoc} */ @Override public boolean isCellEditable(final int row, final int column) { // if it's the separator row, it is always editable (so that the separator can be collapsed/expanded) if (getEventTableModel().getElementAt(row) instanceof SeparatorList.Separator) { return true; } // otherwise it's business as usual return super.isCellEditable(row, column); } /** * Get the renderer for separator rows. * @return */ public TableCellRenderer getSeparatorRenderer() { return separatorRenderer; } public void setSeparatorRenderer(final TableCellRenderer separatorRenderer) { this.separatorRenderer = separatorRenderer; } /** * Get the editor for separator rows. * @return */ public TableCellEditor getSeparatorEditor() { return separatorEditor; } public void setSeparatorEditor(final TableCellEditor separatorEditor) { this.separatorEditor = separatorEditor; } //XXX - Workaround for Autoscroller less then optimal behavior on SeparatorList.Separator /** {@inheritDoc} */ @Override public void valueChanged(final ListSelectionEvent e) { if (e.getValueIsAdjusting()) { for (int row = e.getFirstIndex(); row <= e.getLastIndex(); row++) { if (this.isRowSelected(row)) { if (!selectedRows.contains(row)) { selectedRows.add(row); } } else { if (selectedRows.contains(row)) { selectedRows.remove(selectedRows.indexOf(row)); } } } } if (!selectedRows.isEmpty() && selectedRows.get(selectedRows.size() - 1) < getEventTableModel().getRowCount() && (getEventTableModel().getElementAt(selectedRows.get(selectedRows.size() - 1)) instanceof SeparatorList.Separator)) { setAutoscrolls(false); } else { setAutoscrolls(true); } super.valueChanged(e); } @Override public void unlock() { if (isLocked()) { //only if locked super.unlock(); //Unlock JAutoColumnTable autoResizeRows(); //Update after unlock } } private void autoResizeRows() { if (isLocked()) { return; } for (int row = 0; row < getEventTableModel().getRowCount(); row++) { autoResizeRow(row, getRowHeight()); } } private void autoResizeRow(final int row, int defaultHeight) { if (row < 0 || row > getEventTableModel().getRowCount()) { return; } int height; final Object rowValue = getEventTableModel().getElementAt(row); if (separatorRenderer != null && rowValue instanceof SeparatorList.Separator) { //Calculate the Separator row height //This is done every time, because Separator can never be identified 100% //Because elements is changed by filters and sorting //If saved: the list keep growing with useless hash keys Component component = separatorRenderer.getTableCellRendererComponent(this, getValueAt(row, 0), false, false, row, 0); height = component.getPreferredSize().height; } else { //Calculate the row height height = defaultHeight; } //Set row height, if needed (is expensive because repaint is needed) if (this.getRowHeight(row) != height) { this.setRowHeight(row, Math.max(1, height)); } } /** {@inheritDoc} */ @Override public void tableChanged(final TableModelEvent e) { // stop edits when the table changes, or else we might // get a relocated edit in the wrong cell! if (isEditing()) { super.getCellEditor().cancelCellEditing(); } // handle the change event super.tableChanged(e); //set row heigh autoResizeRows(); } } /** * Modified from BasicTableUI to allow for spanning cells. */ class SpanTableUI extends BasicTableUI { private JSeparatorTable separatorTable; @Override public void installUI(final JComponent c) { this.separatorTable = (JSeparatorTable) c; super.installUI(c); } /** Paint a representation of the table instance * that was set in installUI(). */ @Override public void paint(final Graphics g, final JComponent c) { Rectangle clip = g.getClipBounds(); Rectangle bounds = table.getBounds(); // account for the fact that the graphics has already been translated // into the table's bounds bounds.x = bounds.y = 0; if (table.getRowCount() <= 0 || table.getColumnCount() <= 0 // this check prevents us from painting the entire table // when the clip doesn't intersect our bounds at all || !bounds.intersects(clip)) { return; } Point upperLeft = clip.getLocation(); Point lowerRight = new Point(clip.x + clip.width - 1, clip.y + clip.height - 1); int rMin = table.rowAtPoint(upperLeft); int rMax = table.rowAtPoint(lowerRight); // This should never happen (as long as our bounds intersect the clip, // which is why we bail above if that is the case). if (rMin == -1) { rMin = 0; } // If the table does not have enough rows to fill the view we'll get -1. // (We could also get -1 if our bounds don't intersect the clip, // which is why we bail above if that is the case). // Replace this with the index of the last row. if (rMax == -1) { rMax = table.getRowCount() - 1; } boolean ltr = table.getComponentOrientation().isLeftToRight(); int cMin = table.columnAtPoint(ltr ? upperLeft : lowerRight); int cMax = table.columnAtPoint(ltr ? lowerRight : upperLeft); // This should never happen. if (cMin == -1) { cMin = 0; } // If the table does not have enough columns to fill the view we'll get -1. // Replace this with the index of the last column. if (cMax == -1) { cMax = table.getColumnCount() - 1; } // Paint the grid. paintGrid(g, rMin, rMax, cMin, cMax); // Paint the cells. paintCells(g, rMin, rMax, cMin, cMax); } private void paintCell(final Graphics g, final Rectangle cellRect, final int row, final int column) { if (table.isEditing() && table.getEditingRow() == row && table.getEditingColumn() == column) { Component component = table.getEditorComponent(); component.setBounds(cellRect); component.validate(); } else { TableCellRenderer renderer = table.getCellRenderer(row, column); Component component = table.prepareRenderer(renderer, row, column); rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y, cellRect.width, cellRect.height, true); } } private void paintCells(final Graphics g, final int rMin, final int rMax, final int cMin, final int cMax) { JTableHeader header = table.getTableHeader(); TableColumn draggedColumn = (header == null) ? null : header.getDraggedColumn(); TableColumnModel cm = table.getColumnModel(); int columnMargin = cm.getColumnMargin(); Rectangle cellRect; TableColumn aColumn; int columnWidth; if (table.getComponentOrientation().isLeftToRight()) { for (int row = rMin; row <= rMax; row++) { for (int column = 0; column <= cMax; column++) { aColumn = cm.getColumn(column); cellRect = table.getCellRect(row, column, false); if (aColumn != draggedColumn) { paintCell(g, cellRect, row, column); } } } } else { for (int row = rMin; row <= rMax; row++) { cellRect = table.getCellRect(row, cMin, false); aColumn = cm.getColumn(cMin); if (aColumn != draggedColumn) { columnWidth = aColumn.getWidth(); cellRect.width = columnWidth - columnMargin; paintCell(g, cellRect, row, cMin); } for (int column = cMin + 1; column <= cMax; column++) { aColumn = cm.getColumn(column); columnWidth = aColumn.getWidth(); cellRect.width = columnWidth - columnMargin; cellRect.x -= columnWidth; if (aColumn != draggedColumn) { paintCell(g, cellRect, row, column); } } } } // Paint the dragged column if we are dragging. if (draggedColumn != null) { paintDraggedArea(g, rMin, rMax, draggedColumn, header.getDraggedDistance()); } // Remove any renderers that may be left in the rendererPane. rendererPane.removeAll(); } /* * Paints the grid lines within aRect, using the grid * color set with setGridColor. Paints vertical lines * if getShowVerticalLines() returns true and paints * horizontal lines if getShowHorizontalLines() * returns true. */ private void paintGrid(final Graphics g, final int rMin, final int rMax, final int cMin, final int cMax) { g.setColor(table.getGridColor()); Rectangle minCell = table.getCellRect(rMin, cMin, true); Rectangle maxCell = table.getCellRect(rMax, cMax, true); Rectangle damagedArea = minCell.union(maxCell); if (table.getShowHorizontalLines()) { int tableWidth = damagedArea.x + damagedArea.width; int y = damagedArea.y; for (int row = rMin; row <= rMax; row++) { y += table.getRowHeight(row); g.drawLine(damagedArea.x, y - 1, tableWidth - 1, y - 1); } } if (table.getShowVerticalLines()) { TableColumnModel cm = table.getColumnModel(); int tableHeight = damagedArea.y + damagedArea.height; int x; if (table.getComponentOrientation().isLeftToRight()) { x = 0; //damagedArea.x; for (int column = 0; column <= cMax; column++) { x += cm.getColumn(column).getWidth(); // redraw the grid lines for this column if it is damaged if (column >= cMin) { g.drawLine(x - 1, 0, x - 1, tableHeight - 1); } } } else { x = damagedArea.x + damagedArea.width; for (int column = cMin; column < cMax; column++) { x -= cm.getColumn(column).getWidth(); g.drawLine(x - 1, 0, x - 1, tableHeight - 1); } x -= cm.getColumn(cMax).getWidth(); g.drawLine(x, 0, x, tableHeight - 1); } } } private int viewIndexForColumn(final TableColumn aColumn) { TableColumnModel cm = table.getColumnModel(); for (int column = 0; column < cm.getColumnCount(); column++) { if (cm.getColumn(column) == aColumn) { return column; } } return -1; } private void paintDraggedArea(final Graphics g, final int rMin, final int rMax, final TableColumn draggedColumn, final int distance) { int draggedColumnIndex = viewIndexForColumn(draggedColumn); for (int row = rMin; row <= rMax; row++) { // skip separator rows Object rowValue = ((DefaultEventTableModel) separatorTable.getModel()).getElementAt(row); // only paint the cell on non-separator rows if (!(rowValue instanceof SeparatorList.Separator)) { Rectangle cellRect = table.getCellRect(row, draggedColumnIndex, false); // Paint a gray well in place of the moving column. g.setColor(table.getParent().getBackground()); g.fillRect(cellRect.x, cellRect.y, cellRect.width, cellRect.height); // Move to the where the cell has been dragged. cellRect.x += distance; // Fill the background. g.setColor(table.getBackground()); g.fillRect(cellRect.x, cellRect.y, cellRect.width, cellRect.height); // Paint the vertical grid lines if necessary. if (table.getShowVerticalLines()) { g.setColor(table.getGridColor()); int x1 = cellRect.x; int y1 = cellRect.y; int x2 = x1 + cellRect.width - 1; int y2 = y1 + cellRect.height - 1; // Left g.drawLine(x1 - 1, y1, x1 - 1, y2); // Right g.drawLine(x2, y1, x2, y2); } // Render the cell value paintCell(g, cellRect, row, draggedColumnIndex); } // Paint the (lower) horizontal grid line if necessary. if (table.getShowHorizontalLines()) { g.setColor(table.getGridColor()); Rectangle rcr = table.getCellRect(row, draggedColumnIndex, true); rcr.x += distance; int x1 = rcr.x; int y1 = rcr.y; int x2 = x1 + rcr.width - 1; int y2 = y1 + rcr.height - 1; g.drawLine(x1, y2, x2, y2); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/JViewManagerDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table; import java.util.List; import java.util.Map; import javax.swing.table.AbstractTableModel; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.components.JManagerDialog; import net.nikr.eve.jeveasset.i18n.GuiShared; public class JViewManagerDialog extends JManagerDialog { private final EnumTableFormatAdaptor tableFormat; private final AbstractTableModel tableModel; private final JAutoColumnTable jTable; private Map views; public JViewManagerDialog(Program program, EnumTableFormatAdaptor tableFormat, AbstractTableModel tableModel, JAutoColumnTable jTable) { super(program, program.getMainWindow().getFrame(), GuiShared.get().manageViews(), true, false, false, false, false); this.tableFormat = tableFormat; this.tableModel = tableModel; this.jTable = jTable; } public final void updateData(Map views) { this.views = views; update(); } public final void update() { update(views.keySet()); program.updateTableMenu(); } public void loadView(View view) { tableFormat.setColumns(view.getColumns()); tableModel.fireTableStructureChanged(); jTable.autoResizeColumns(); program.updateTableMenu(); program.saveSettings("View (Load)"); //Save Columns (Changed - Load View) } @Override protected void load(String name) { View view = views.get(name); loadView(view); setVisible(false); } @Override protected void edit(String name) { //Edit is not supported... } @Override protected void merge(String name, List list) { //Merge is not supported... } @Override protected void copy(String fromName, String toName) { //Copy is not supported } @Override protected void rename(String name, String oldName) { View view = views.get(oldName); Settings.lock("View (Rename)"); //Lock for View (Rename) view.setName(name); views.remove(oldName); //Remove renamed filter (with old name) views.remove(name); //Remove overwritten filter views.put(name, view); //Add renamed filter (with new name) update(); Settings.unlock("View (Rename)");//Unlock for View (Rename) program.saveSettings("View (Rename)"); //Save View (Rename) } @Override protected void delete(List list) { Settings.lock("View (Delete)"); //Lock for View (Delete) for (String name : list) { views.remove(name); } update(); Settings.unlock("View (Delete)"); //Unlock for View (Delete) program.saveSettings("View (Delete)"); //Save View (Delete) } @Override protected void export(List list) { //Export is not supported } @Override protected void importData() { //Import is not supported } @Override protected String textDeleteMultipleMsg(int size) { return GuiShared.get().deleteViews(size); } @Override protected String textDelete() { return GuiShared.get().deleteView(); } @Override protected String textEnterName() { return GuiShared.get().enterViewName(); } @Override protected String textMerge() { return ""; } @Override protected String textRename() { return GuiShared.get().renameView(); } @Override protected String textOverwrite() { return GuiShared.get().overwriteView(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/PaddingTableCellRenderer.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table; import java.awt.Component; import java.util.EnumMap; import java.util.Map; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JTable; import javax.swing.border.Border; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.IconTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.TextIconTableCellRenderer; public final class PaddingTableCellRenderer implements TableCellRenderer { private enum BorderState { SELECTED_AND_FOCUSED(true, true), SELECTED_AND_NOT_FOCUSED(true, false), NOT_SELECTED_AND_FOCUSED(false, true), NOT_SELECTED_AND_NOT_FOCUSED(false, false); private final boolean selected; private final boolean focused; private BorderState(boolean selected, boolean focused) { this.selected = selected; this.focused = focused; } public static BorderState getState(final boolean isSelected, final boolean hasFocus) { for (BorderState borderState : values()) { if (borderState.selected == isSelected && borderState.focused == hasFocus) { return borderState; } } return BorderState.NOT_SELECTED_AND_NOT_FOCUSED; } } private final TableCellRenderer renderer; private final Border border; private final Map borders = new EnumMap<>(BorderState.class); public static void install(final JTable jTable, final int padding) { install(jTable, padding, padding, padding, padding); } public static void install(final JTable jTable, final int top, final int left, final int bottom, final int right) { for (int i = 0; i < jTable.getColumnCount(); i++) { Class clazz = jTable.getColumnClass(i); TableCellRenderer defaultRenderer = jTable.getDefaultRenderer(clazz); if (defaultRenderer == null) { defaultRenderer = new DefaultTableCellRenderer(); } if (!(defaultRenderer instanceof PaddingTableCellRenderer) && !(defaultRenderer instanceof TextIconTableCellRenderer) && !(defaultRenderer instanceof IconTableCellRenderer)) { jTable.setDefaultRenderer(clazz, new PaddingTableCellRenderer(defaultRenderer, top, left, bottom, right)); } } jTable.setRowHeight(jTable.getRowHeight() + top + bottom); } private PaddingTableCellRenderer(final TableCellRenderer renderer, final int top, final int left, final int bottom, final int right) { if (renderer != null) { this.renderer = renderer; } else { this.renderer = new DefaultTableCellRenderer(); } border = BorderFactory.createEmptyBorder(top, left, bottom, right); } @Override public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) { JComponent jComponent = (JComponent) renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); BorderState state = BorderState.getState(isSelected, hasFocus); Border compoundBorder = borders.get(state); if (compoundBorder == null) { compoundBorder = BorderFactory.createCompoundBorder(jComponent.getBorder(), border); borders.put(state, compoundBorder); } jComponent.setBorder(compoundBorder); return jComponent; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/SeparatorTableCell.java ================================================ /* Glazed Lists (c) 2003-2006 */ /* http://publicobject.com/glazedlists/ publicobject.com,*/ /* O'Dell Engineering Ltd.*/ package net.nikr.eve.jeveasset.gui.shared.table; import ca.odell.glazedlists.SeparatorList; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.*; import javax.swing.border.Border; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.ColorUtil; /** * * @author Jesse Wilson * @param */ public abstract class SeparatorTableCell extends AbstractCellEditor implements TableCellRenderer, TableCellEditor { protected static final Border EMPTY_TWO_PIXEL_BORDER = BorderFactory.createEmptyBorder(2, 2, 2, 2); /** the separator list to lock. */ protected final SeparatorList separatorList; protected SeparatorList.Separator currentSeparator; protected int currentRow; private final JSeparatorPanel jEditor; protected final JSeparatorPanel jPanel; protected final JButton jExpand; protected final GroupLayout layout; protected final JTable jTable; public SeparatorTableCell(final JTable jTable, final SeparatorList separatorList) { this.jTable = jTable; this.separatorList = separatorList; jPanel = new JSeparatorPanel(new BorderLayout()); if (ColorUtil.isBrightColor(jPanel.getBackground())) { //Light background color jPanel.setBackground(Color.LIGHT_GRAY); } else { //Dark background color jPanel.setBackground(Color.DARK_GRAY); } jPanel.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(final MouseEvent e) { if (e.getClickCount() >= 2) { expandSeparator(currentSeparator.getLimit() == 0); } } }); layout = new GroupLayout(jPanel); jPanel.setLayout(layout); layout.setAutoCreateGaps(false); layout.setAutoCreateContainerGaps(false); /* XXX - Workaround for square button borders in table with FlatLAF https://stackoverflow.com/questions/67657036/jbuttons-in-jtable-cell-change-shape-on-row-selection https://github.com/JFormDesigner/FlatLaf/blob/main/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java#L215 */ if (Settings.get().getColorSettings().isFlatLAF()) { JSeparatorPanel jLast = jPanel; for (int i = 0; i < 3; i++) { JSeparatorPanel jSeparatorPanel = new JSeparatorPanel(new BorderLayout()); jSeparatorPanel.add(jLast); jLast = jSeparatorPanel; } jEditor = jLast; } else { jEditor = jPanel; } jExpand = new JButton(Images.MISC_EXPANDED.getIcon()); jExpand.setOpaque(false); jExpand.setContentAreaFilled(false); jExpand.setBorder(EMPTY_TWO_PIXEL_BORDER); jExpand.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { expandSeparator(currentSeparator.getLimit() == 0); } }); } @Override public Component getTableCellEditorComponent(final JTable table, final Object value, final boolean isSelected, final int row, final int column) { configure(value, row); return jEditor; } @Override public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) { configure(value, row); return jEditor; } @Override public Object getCellEditorValue() { return this.currentSeparator; } private void configure(final Object value, final int row) { if (value instanceof SeparatorList.Separator) { this.currentRow = row; this.currentSeparator = (SeparatorList.Separator) value; jExpand.setIcon(currentSeparator.getLimit() == 0 ? Images.MISC_EXPANDED.getIcon() : Images.MISC_COLLAPSED.getIcon()); configure(currentSeparator); } } protected abstract void configure(final SeparatorList.Separator separator); protected void expandSeparator(final boolean expand) { try { separatorList.getReadWriteLock().writeLock().lock(); currentSeparator.setLimit(expand ? Integer.MAX_VALUE : 0); } finally { separatorList.getReadWriteLock().writeLock().unlock(); } if (expand) { scrollToRow(currentRow + currentSeparator.size()); } } private void scrollToRow(final int row) { if (!(jTable.getParent() instanceof JViewport)) { return; } JViewport viewport = (JViewport) jTable.getParent(); // This rectangle is relative to the table where the // northwest corner of cell (0,0) is always (0,0). Rectangle rect = jTable.getCellRect(row, 0, true); // The location of the viewport relative to the table Point pt = viewport.getViewPosition(); // Translate the cell location so that it is relative // to the view, assuming the northwest corner of the // view is (0,0) rect.setLocation(rect.x - pt.x, rect.y - pt.y); // Scroll the area into view viewport.scrollRectToVisible(rect); //Ensure stockpile cell is visible rect = jTable.getCellRect(currentRow, 0, true); pt = viewport.getViewPosition(); rect.setLocation(rect.x - pt.x, rect.y - pt.y); viewport.scrollRectToVisible(rect); } public class JSeparatorPanel extends JPanel { public JSeparatorPanel(LayoutManager layout, boolean isDoubleBuffered) { super(layout, isDoubleBuffered); } public JSeparatorPanel(LayoutManager layout) { super(layout); } public JSeparatorPanel(boolean isDoubleBuffered) { super(isDoubleBuffered); } public JSeparatorPanel() { super(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/SimpleColumnManager.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog.Formula; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuJumps.Jump; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager.FormulaColumn; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager.JumpColumn; public interface SimpleColumnManager { public FormulaColumn addColumn(Formula add); public JumpColumn addColumn(Jump add); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/TableCellRenderers.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.util.Date; import javax.swing.AbstractCellEditor; import javax.swing.DefaultCellEditor; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.SwingConstants; import javax.swing.border.LineBorder; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellEditor; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.components.JButtonComparable; import net.nikr.eve.jeveasset.gui.shared.table.containers.Standing; import net.nikr.eve.jeveasset.gui.shared.table.containers.TextIcon; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileTableFormat; public class TableCellRenderers { public static class LongCellRenderer extends DefaultTableCellRenderer { public LongCellRenderer() { this.setHorizontalTextPosition(DefaultTableCellRenderer.RIGHT); this.setHorizontalAlignment(DefaultTableCellRenderer.RIGHT); } @Override public void setValue(final Object value) { if (value == null) { setText(""); } else if (value instanceof Number) { setText(Formatter.longFormat(value)); } else { setText(value.toString()); } } } public static class DoubleCellRenderer extends DefaultTableCellRenderer { public DoubleCellRenderer() { this.setHorizontalTextPosition(DefaultTableCellRenderer.RIGHT); this.setHorizontalAlignment(DefaultTableCellRenderer.RIGHT); } @Override public void setValue(final Object value) { if (value == null) { setText(""); } else if (value instanceof Number) { setText(Formatter.doubleFormat(value)); } else { setText(value.toString()); } } } public static class IntegerCellRenderer extends DefaultTableCellRenderer { public IntegerCellRenderer() { this.setHorizontalTextPosition(DefaultTableCellRenderer.RIGHT); this.setHorizontalAlignment(DefaultTableCellRenderer.RIGHT); } @Override public void setValue(final Object value) { if (value == null) { setText(""); } else if (value instanceof Number) { setText(Formatter.integerFormat(value)); } else { setText(value.toString()); } } } public static class FloatCellRenderer extends DefaultTableCellRenderer { public FloatCellRenderer() { this.setHorizontalTextPosition(DefaultTableCellRenderer.RIGHT); this.setHorizontalAlignment(DefaultTableCellRenderer.RIGHT); } @Override public void setValue(final Object value) { if (value == null) { setText(""); } else if (value instanceof Number) { setText(Formatter.floatFormat(value)); } else { setText(value.toString()); } } } public static class DateCellRenderer extends DefaultTableCellRenderer { public DateCellRenderer() { this.setHorizontalTextPosition(DefaultTableCellRenderer.RIGHT); this.setHorizontalAlignment(DefaultTableCellRenderer.RIGHT); } @Override public void setValue(final Object value) { if (value == null) { setText(""); } else if (value instanceof Date) { setText(Formatter.columnDate(value)); } else { setText(value.toString()); } } } public static class DateOnlyCellRenderer extends DefaultTableCellRenderer { public DateOnlyCellRenderer() { this.setHorizontalTextPosition(DefaultTableCellRenderer.RIGHT); this.setHorizontalAlignment(DefaultTableCellRenderer.RIGHT); } @Override public void setValue(final Object value) { if (value == null) { setText(""); } else if (value instanceof Date) { setText(Formatter.columnDateOnly(value)); } else { setText(value.toString()); } } } public static class ToStringCellRenderer extends DefaultTableCellRenderer { public ToStringCellRenderer() { this(SwingConstants.RIGHT); } public ToStringCellRenderer(final int alignment) { this.setHorizontalTextPosition(alignment); this.setHorizontalAlignment(alignment); } @Override public void setValue(final Object value) { if (value == null) { setText(""); } else { setText(value.toString()); } } } public static class StandingTableCellRenderer extends DefaultTableCellRenderer { private static final int TICK_HEIGHT = 1; private final JStandingLabel jStandingLabel = new JStandingLabel(); @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (component instanceof JLabel) { JLabel jLabel = (JLabel) component; if (value instanceof Standing) { jStandingLabel.setup(jLabel, (Standing) value, isSelected); return jStandingLabel; } } return component; } private static class JStandingLabel extends JLabel { private double standing = 0; private boolean selected; public JStandingLabel() { this.setHorizontalTextPosition(DefaultTableCellRenderer.RIGHT); this.setHorizontalAlignment(DefaultTableCellRenderer.RIGHT); this.setOpaque(false); } public void setup(JLabel jLabel, Standing standing, boolean selected) { setBackground(jLabel.getBackground()); setForeground(jLabel.getForeground()); setBorder(jLabel.getBorder()); setText(jLabel.getText()); setFont(jLabel.getFont()); if (standing != null) { this.standing = standing.getStanding(); } else { this.standing = 0; } this.selected = selected; } @Override protected void paintComponent(Graphics g) { Graphics2D g2D = (Graphics2D) g; g2D.setBackground(getBackground()); Dimension size = getSize(); g2D.clearRect(0, 0, size.width, size.height); double tickSise = size.width / 20.0; int middle = size.width / 2; int width = (int)Math.ceil(tickSise * Math.abs(standing)); Color standingColor; Color middleColor; if (selected) { standingColor = getBackground().darker().darker(); middleColor = getBackground(); } else if (standing < 0) { standingColor = ColorSettings.background(ColorEntry.NPC_STANDING_NEGATIVE); middleColor = ColorSettings.background(ColorEntry.NPC_STANDING_NEGATIVE_MIDDLE); } else if (standing > 0) { standingColor = ColorSettings.background(ColorEntry.NPC_STANDING_POSITIVE); middleColor = ColorSettings.background(ColorEntry.NPC_STANDING_POSITIVE_MIDDLE); } else { standingColor = getBackground(); middleColor = getBackground(); } g2D.setColor(standingColor); if (standing < 0) { int start = middle - width; g2D.setPaint(new GradientPaint(0, 0, standingColor, middle, 0, middleColor)); g2D.fillRect(start, 0, width, size.height); } else if (standing > 0) { g2D.setPaint(new GradientPaint(middle, 0, middleColor, size.width, 0, standingColor)); g2D.fillRect(middle, 0, width, size.height); } g2D.setColor(new Color(getForeground().getRed(), getForeground().getGreen(), getForeground().getBlue(), 100)); //g2D.setColor(gridColor); g2D.drawLine(middle, 0, middle, size.height); int bottom = size.height - TICK_HEIGHT; int attack = middle - (int)(tickSise * 5); g2D.drawLine(attack, bottom, attack, size.height); g2D.drawLine(attack, 0, attack, TICK_HEIGHT); int level1 = middle - (int)(tickSise * 2); g2D.drawLine(level1, bottom, level1, size.height); g2D.drawLine(level1, 0, level1, TICK_HEIGHT); int level2 = middle + (int)(tickSise * 1); g2D.drawLine(level2, bottom, level2, size.height); g2D.drawLine(level2, 0, level2, TICK_HEIGHT); int level3 = middle + (int)(tickSise * 3); g2D.drawLine(level3, bottom, level3, size.height); g2D.drawLine(level3, 0, level3, TICK_HEIGHT); int level4 = middle + (int)(tickSise * 5); g2D.drawLine(level4, bottom, level4, size.height); g2D.drawLine(level4, 0, level4, TICK_HEIGHT); int level5 = middle + (int)(tickSise * 7); g2D.drawLine(level5, bottom, level5, size.height); g2D.drawLine(level5, 0, level5, TICK_HEIGHT); super.paintComponent(g); } } } public static class IconTableCellRenderer extends DefaultTableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (component instanceof JLabel) { JLabel jLabel = (JLabel) component; if (value instanceof Icon) { jLabel.setIcon((Icon) value); jLabel.setText(""); } else { jLabel.setIcon(null); } } return component; } } public static class TextIconTableCellRenderer extends DefaultTableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (component instanceof JLabel) { JLabel jLabel = (JLabel) component; if (value instanceof TextIcon) { TextIcon textIcon = (TextIcon) value; jLabel.setIcon(textIcon.getIcon()); jLabel.setText(textIcon.getText()); } else { jLabel.setIcon(null); } } return component; } } public static class TargetCellRenderer extends DefaultTableCellRenderer { public static final int MINIMUM_ICON_TEXT_GAP = 10; private final DefaultEventTableModel tableModel; public TargetCellRenderer(DefaultEventTableModel tableModel) { this.tableModel = tableModel; this.setHorizontalTextPosition(DefaultTableCellRenderer.RIGHT); this.setHorizontalAlignment(DefaultTableCellRenderer.RIGHT); } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { String columnName = (String) table.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); Object object = tableModel.getElementAt(row); Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (component instanceof JLabel) { JLabel jLabel = (JLabel) component; if (object instanceof StockpileItem) { StockpileItem stockpileItem = (StockpileItem) object; if (stockpileItem.isEditable() && columnName.equals(StockpileTableFormat.COUNT_MINIMUM.getColumnName())) { jLabel.setIcon(Images.EDIT_EDIT_BACKGROUND.getIcon()); jLabel.setHorizontalTextPosition(JLabel.TRAILING); jLabel.setIconTextGap(MINIMUM_ICON_TEXT_GAP); return component; } } jLabel.setIcon(null); jLabel.setIconTextGap(0); } return component; } @Override public void setValue(final Object value) { if (value == null) { setText(""); } else if (value instanceof Number) { setText(Formatter.doubleFormat(value)); } else { setText(value.toString()); } } } public static class TagsCellRenderer extends DefaultTableCellRenderer { public TagsCellRenderer() { this.setHorizontalTextPosition(SwingConstants.CENTER); this.setHorizontalAlignment(SwingConstants.CENTER); } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { JLabel jLabel = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); //To change body of generated methods, choose Tools | Templates. if (value instanceof Tags) { Tags tags = (Tags) value; Tags.setFont(jLabel.getFont()); tags.updateFont(); JPanel jPanel = tags.getPanel(); jPanel.setBackground(jLabel.getBackground()); jPanel.setForeground(jLabel.getForeground()); jPanel.setBorder(jLabel.getBorder()); return jPanel; } return jLabel; } } public static class ComponentRenderer extends DefaultTableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (value instanceof JButtonComparable) { JButtonComparable jButton = (JButtonComparable) value; if (isSelected && table.getSelectedColumns().length == 1 && table.getSelectedRows().length == 1) { jButton.getModel().setRollover(true); jButton.getModel().setSelected(true); } else { jButton.getModel().setRollover(false); jButton.getModel().setSelected(false); } return jButton; } else if (value instanceof Component) { return (Component) value; } else { return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); } } } public static class ComponentEditor extends AbstractCellEditor implements TableCellEditor { private final TableCellEditor defaultTableCellEditor; public ComponentEditor(TableCellEditor defaultTableCellEditor) { this.defaultTableCellEditor = defaultTableCellEditor; } @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { if (value instanceof Component) { return (Component) value; } else { return defaultTableCellEditor.getTableCellEditorComponent(table, value, isSelected, row, column); } } @Override public Object getCellEditorValue() { return null; } } /** * NumberEditor that handle space and comma thousand separator * Original code from JTable.GenericEditor and JTable.NumberEditor */ static class BetterNumberEditor extends DefaultCellEditor { Class[] argTypes = new Class[]{String.class}; java.lang.reflect.Constructor constructor; Object value; public BetterNumberEditor() { super(new JTextField()); getComponent().setName("Table.editor"); ((JTextField)getComponent()).setHorizontalAlignment(JTextField.RIGHT); } @Override public boolean stopCellEditing() { String s = (String)super.getCellEditorValue(); //Workaround start s = s.replace(",", ""); //Ignore thousands separator s = s.replace(" ", ""); //Ignore thousands separator //workaround end (All other code is directly from Java core) // Here we are dealing with the case where a user // has deleted the string value in a cell, possibly // after a failed validation. Return null, so that // they have the option to replace the value with // null or use escape to restore the original. // For Strings, return "" for backward compatibility. try { if ("".equals(s)) { if (constructor.getDeclaringClass() == String.class) { value = s; } return super.stopCellEditing(); } value = constructor.newInstance(new Object[]{s}); } catch (Exception e) { ((JComponent)getComponent()).setBorder(new LineBorder(Color.red)); return false; } return super.stopCellEditing(); } @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { this.value = null; ((JComponent)getComponent()).setBorder(new LineBorder(Color.black)); try { Class type = table.getColumnClass(column); // Since our obligation is to produce a value which is // assignable for the required type it is OK to use the // String constructor for columns which are declared // to contain Objects. A String is an Object. if (type == Object.class) { type = String.class; } constructor = type.getConstructor(argTypes); } catch (Exception e) { return null; } return super.getTableCellEditorComponent(table, value, isSelected, row, column); } @Override public Object getCellEditorValue() { return value; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/TableFormatFactory.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table; import java.util.Arrays; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyExtraction; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.api.my.MySkill; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.sde.Agent; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.settings.ColorSettings.ColorRow; import net.nikr.eve.jeveasset.gui.dialogs.account.AccountTableFormat; import net.nikr.eve.jeveasset.gui.dialogs.settings.ColorsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.agents.AgentsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetTableFormat; import net.nikr.eve.jeveasset.gui.tabs.contracts.ContractsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.items.ItemTableFormat; import net.nikr.eve.jeveasset.gui.tabs.jobs.IndustryJobTableFormat; import net.nikr.eve.jeveasset.gui.tabs.journal.JournalTableFormat; import net.nikr.eve.jeveasset.gui.tabs.loadout.Loadout; import net.nikr.eve.jeveasset.gui.tabs.loadout.LoadoutExtendedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.loadout.LoadoutTableFormat; import net.nikr.eve.jeveasset.gui.tabs.loyalty.LoyaltyPointsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.materials.Material; import net.nikr.eve.jeveasset.gui.tabs.materials.MaterialExtendedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.materials.MaterialTableFormat; import net.nikr.eve.jeveasset.gui.tabs.mining.ExtractionsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.mining.MiningTableFormat; import net.nikr.eve.jeveasset.gui.tabs.orders.MarketTableFormat; import net.nikr.eve.jeveasset.gui.tabs.overview.Overview; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTableFormat; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceChangesTab.PriceChange; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceChangesTableFormat; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedExtendedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedInterface; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.skills.SkillsOverviewTab.SkillsOverview; import net.nikr.eve.jeveasset.gui.tabs.skills.SkillsOverviewTableFormat; import net.nikr.eve.jeveasset.gui.tabs.skills.SkillsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.slots.Slots; import net.nikr.eve.jeveasset.gui.tabs.slots.SlotsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.standing.NpcStandingTableFormat; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileExtendedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileTableFormat; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerSkillPointFilter; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerSkillPointsFilterTableFormat; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTableFormat; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeAsset; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTableFormat; import net.nikr.eve.jeveasset.gui.tabs.values.Value; import net.nikr.eve.jeveasset.gui.tabs.values.ValueTableFormat; public class TableFormatFactory { public static EnumTableFormatAdaptor skillsOverviewTableFormat() { return new EnumTableFormatAdaptor<>(SkillsOverviewTableFormat.class); } public static EnumTableFormatAdaptor accountTableFormat() { return new EnumTableFormatAdaptor<>(AccountTableFormat.class); } public static EnumTableFormatAdaptor assetTableFormat() { return new EnumTableFormatAdaptor<>(AssetTableFormat.class); } public static EnumTableFormatAdaptor colorsTableFormat() { return new EnumTableFormatAdaptor<>(ColorsTableFormat.class); } //Extended public static EnumTableFormatAdaptor contractsTableFormat() { return new EnumTableFormatAdaptor<>(ContractsTableFormat.class); } public static EnumTableFormatAdaptor industryJobTableFormat() { return new EnumTableFormatAdaptor<>(IndustryJobTableFormat.class); } public static EnumTableFormatAdaptor slotTableFormat() { return new EnumTableFormatAdaptor<>(SlotsTableFormat.class); } public static EnumTableFormatAdaptor itemTableFormat() { return new EnumTableFormatAdaptor<>(ItemTableFormat.class); } public static EnumTableFormatAdaptor journalTableFormat() { return new EnumTableFormatAdaptor<>(JournalTableFormat.class); } //Extended public static EnumTableFormatAdaptor loadoutTableFormat() { return new EnumTableFormatAdaptor<>(LoadoutTableFormat.class, Arrays.asList(LoadoutExtendedTableFormat.values())); } public static EnumTableFormatAdaptor marketTableFormat() { return new EnumTableFormatAdaptor<>(MarketTableFormat.class); } //Extended public static EnumTableFormatAdaptor materialTableFormat() { return new EnumTableFormatAdaptor<>(MaterialTableFormat.class, Arrays.asList(MaterialExtendedTableFormat.values())); } public static EnumTableFormatAdaptor overviewTableFormat() { return new EnumTableFormatAdaptor<>(OverviewTableFormat.class); } //Extended public static EnumTableFormatAdaptor reprocessedTableFormat() { return new EnumTableFormatAdaptor<>(ReprocessedTableFormat.class, Arrays.asList(ReprocessedExtendedTableFormat.values())); } //Extended public static EnumTableFormatAdaptor stockpileTableFormat() { return new EnumTableFormatAdaptor<>(StockpileTableFormat.class, Arrays.asList(StockpileExtendedTableFormat.values())); } public static EnumTableFormatAdaptor trackerSkillPointsFilterTableFormat() { return new EnumTableFormatAdaptor<>(TrackerSkillPointsFilterTableFormat.class); } public static EnumTableFormatAdaptor transactionTableFormat() { return new EnumTableFormatAdaptor<>(TransactionTableFormat.class); } public static EnumTableFormatAdaptor treeTableFormat() { return new EnumTableFormatAdaptor<>(TreeTableFormat.class); } public static EnumTableFormatAdaptor valueTableFormat() { return new EnumTableFormatAdaptor<>(ValueTableFormat.class); } public static EnumTableFormatAdaptor skillsTableFormat() { return new EnumTableFormatAdaptor<>(SkillsTableFormat.class); } public static EnumTableFormatAdaptor loyaltyPointsTableFormat() { return new EnumTableFormatAdaptor<>(LoyaltyPointsTableFormat.class); } public static EnumTableFormatAdaptor npcStandingTableFormat() { return new EnumTableFormatAdaptor<>(NpcStandingTableFormat.class); } public static EnumTableFormatAdaptor agentsTableFormat() { return new EnumTableFormatAdaptor<>(AgentsTableFormat.class); } public static EnumTableFormatAdaptor miningTableFormat() { return new EnumTableFormatAdaptor<>(MiningTableFormat.class); } public static EnumTableFormatAdaptor extractionsTableFormat() { return new EnumTableFormatAdaptor<>(ExtractionsTableFormat.class); } public static EnumTableFormatAdaptor priceChangesTableFormat() { return new EnumTableFormatAdaptor<>(PriceChangesTableFormat.class); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/View.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table; import java.util.ArrayList; import java.util.List; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.SimpleColumn; public class View implements Comparable { private String name; private List columns = new ArrayList(); public View(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List getColumns() { return columns; } public void setColumns(List columns) { this.columns = columns; } @Override public String toString() { return getName(); } @Override public int compareTo(View o) { return this.getName().compareToIgnoreCase(o.getName()); } @Override public int hashCode() { int hash = 7; hash = 47 * hash + (this.name != null ? this.name.hashCode() : 0); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final View other = (View) obj; if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/AssetContainer.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; import java.util.Objects; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.i18n.General; public class AssetContainer implements Comparable{ private final String container; private final String containerSimple; //No ItemID public AssetContainer() { this.container = ""; this.containerSimple = ""; } public AssetContainer(MyAsset asset) { StringBuilder builder = new StringBuilder(); StringBuilder simpleBuilder = new StringBuilder(); if (asset.getParents().isEmpty()) { builder.append(General.get().none()); simpleBuilder.append(General.get().none()); } else { boolean first = true; for (MyAsset parentAsset : asset.getParents()) { if (first) { first = false; } else { builder.append(" > "); simpleBuilder.append(" > "); } simpleBuilder.append(parentAsset.getName()); builder.append(parentAsset.getName()); if (!parentAsset.isUserName()) { builder.append(" #"); builder.append(parentAsset.getItemID()); } } } this.container = builder.toString().intern(); this.containerSimple = simpleBuilder.toString().intern(); } public String getContainer() { return container; } @Override public int compareTo(AssetContainer o) { return this.container.compareTo(o.container); } @Override public String toString() { if (Settings.get().isContainersShowItemID()) { return container; } else { return containerSimple; } } @Override public int hashCode() { int hash = 7; if (Settings.get().isContainersShowItemID()) { hash = 37 * hash + Objects.hashCode(this.container); } else { hash = 37 * hash + Objects.hashCode(this.containerSimple); } return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final AssetContainer other = (AssetContainer) obj; if (Settings.get().isContainersShowItemID()) { return Objects.equals(this.container, other.container); } else { return Objects.equals(this.containerSimple, other.containerSimple); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/DateOnly.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; import java.util.Date; public class DateOnly extends Date { public DateOnly(Date date) { super(date.getTime()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/Duration.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; import com.google.common.primitives.Longs; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.i18n.GuiShared; public class Duration implements Comparable { public static final Duration NEVER = new Duration(GuiShared.get().durationNever()); public static final Duration DONE = new Duration(GuiShared.get().durationDone()); private final long duration; private final String formatted; public Duration(String formatted) { this.duration = 0; this.formatted = formatted; } public Duration(long time) { this(time, false, false, true, true, true, true); } public Duration(long time, boolean first, boolean verbose) { this(time, first, verbose, true, true, true, true); } public Duration(long time, boolean showDays, boolean showHours, boolean showMinutes, boolean showSeconds) { this(time, false, false, showDays, showHours, showMinutes, showSeconds); } public Duration(long time, boolean first, boolean verbose, boolean showDays, boolean showHours, boolean showMinutes, boolean showSeconds) { duration = time; formatted = Formatter.milliseconds(time, showDays, showHours, showMinutes, showSeconds); } public long getDuration() { return duration; } @Override public int hashCode() { int hash = 5; hash = 97 * hash + (int) (this.duration ^ (this.duration >>> 32)); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Duration other = (Duration) obj; return this.duration == other.duration; } @Override public String toString() { return formatted; } @Override public int compareTo(Duration o) { return Longs.compare(duration, o.duration); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/ExpirerDate.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; import java.util.Date; import java.util.Objects; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.Formatter; public class ExpirerDate implements Comparable { private final Date expirer; public ExpirerDate(final Date expirer) { this.expirer = expirer; } @Override public String toString() { if (expirer == null) { return "Never"; } else if (Settings.getNow().after(expirer)) { return "Expired"; } else { return Formatter.dateOnly(expirer); } } @Override public int compareTo(final ExpirerDate o) { return this.expirer.compareTo(o.expirer); } @Override public int hashCode() { int hash = 5; hash = 79 * hash + Objects.hashCode(this.expirer); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ExpirerDate other = (ExpirerDate) obj; if (!Objects.equals(this.expirer, other.expirer)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/HierarchyColumn.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; import java.util.Objects; public class HierarchyColumn implements Comparable{ private final String export; private final String gui; //private final String compare; public HierarchyColumn(String text, boolean parent) { this.gui = text.trim(); if (parent) { int split = text.indexOf(gui); this.export = text.substring(0, split) + "+" + text.substring(split); } else { this.export = text; } } public String getExport() { return export; } @Override public int compareTo(HierarchyColumn o) { return this.toString().compareTo(o.toString()); } @Override public String toString() { return gui; } @Override public int hashCode() { int hash = 5; hash = 67 * hash + Objects.hashCode(this.gui); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final HierarchyColumn other = (HierarchyColumn) obj; if (!Objects.equals(this.gui, other.gui)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/ISK.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; import java.util.Objects; public class ISK implements NumberValue { private final String price; private final double value; public ISK(final String price, double value) { this.price = price; this.value = value; } @Override public String toString() { return price; } @Override public Double getDouble() { return value; } @Override public Number getNumber() { return value; } @Override public int hashCode() { int hash = 7; hash = 29 * hash + Objects.hashCode(this.price); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ISK other = (ISK) obj; if (!Objects.equals(this.price, other.price)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/LongInt.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; import java.util.Objects; import net.nikr.eve.jeveasset.gui.shared.Formatter; public class LongInt implements NumberValue, Comparable { private final Long number; private final String formatted; public LongInt(final Long number) { if (number == null) { this.number = 0L; this.formatted = ""; } else { this.number = number; this.formatted = Formatter.integerFormat(number); } } @Override public Number getNumber() { return number; } @Override public Long getLong() { return number; } @Override public String toString() { return formatted; } @Override public int compareTo(final LongInt o) { return number.compareTo(o.getLong()); } @Override public int hashCode() { int hash = 7; hash = 53 * hash + Objects.hashCode(this.number); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final LongInt other = (LongInt) obj; if (!Objects.equals(this.number, other.number)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/ModulePriceValue.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; import java.util.Objects; import net.nikr.eve.jeveasset.gui.shared.Formatter; public class ModulePriceValue { private final Double price; private final double value; private final long count; public ModulePriceValue(final Double price, final double value, final long count) { this.price = price; this.value = value; this.count = count; } @Override public String toString() { if (count > 1 && price != null) { return Formatter.iskFormat(price) + " (" + Formatter.iskFormat(value) + ")"; } else { return Formatter.iskFormat(value); } } @Override public int hashCode() { int hash = 7; hash = 79 * hash + Objects.hashCode(this.price); hash = 79 * hash + (int) (Double.doubleToLongBits(this.value) ^ (Double.doubleToLongBits(this.value) >>> 32)); hash = 79 * hash + (int) (this.count ^ (this.count >>> 32)); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ModulePriceValue other = (ModulePriceValue) obj; if (Double.doubleToLongBits(this.value) != Double.doubleToLongBits(other.value)) { return false; } if (this.count != other.count) { return false; } if (!Objects.equals(this.price, other.price)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/NumberValue.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; public interface NumberValue { public default Double getDouble() { return null; } public default Long getLong() { return null; } public Number getNumber(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/Percent.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; import java.util.HashMap; import java.util.Map; import net.nikr.eve.jeveasset.gui.shared.Formatter; public class Percent implements NumberValue, Comparable { private final static Map CACHE = new HashMap<>(); private final double percent; private final String formatted; public static Percent create(final double decimalPercent) { Percent cached = CACHE.get(decimalPercent); if (cached == null) { cached = new Percent(decimalPercent); CACHE.put(decimalPercent, cached); } return cached; } private Percent(final double percent) { this.percent = percent; if (Double.isInfinite(percent)) { formatted = Formatter.integerFormat(percent); } else { formatted = Formatter.percentFormat(percent); } } @Override public Double getDouble() { return round(percent * 100.0, 2); } @Override public Number getNumber() { return getDouble(); } private static double round(final double value, int decimals) { double p = Math.pow(10, decimals); double tmp = value * p; tmp = Math.round(tmp); return tmp / p; } @Override public String toString() { return formatted; } @Override public int compareTo(final Percent o) { return Double.compare(percent, o.percent); } @Override public int hashCode() { int hash = 5; hash = 71 * hash + (int) (Double.doubleToLongBits(this.percent) ^ (Double.doubleToLongBits(this.percent) >>> 32)); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Percent other = (Percent) obj; if (Double.doubleToLongBits(this.percent) != Double.doubleToLongBits(other.percent)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/Runs.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; import java.util.Objects; public class Runs implements NumberValue, Comparable { private final String runsString; private final Long runs; public Runs(int runs) { if (runs > 0) { this.runs = (long) runs; this.runsString = String.valueOf(runs); } else if (runs == 0) { // Not Blueprint this.runsString = ""; this.runs = 0L; } else { this.runsString = "BPO"; this.runs = null; } } @Override public Number getNumber() { return runs; } @Override public Long getLong() { return runs; } @Override public int compareTo(Runs o) { if (this.runs == null && o.runs == null) { return 0; //Both BPO: Equals } else if (this.runs == null) { return 1; // This is BPO: This is Greater } else if (o.runs == null) { return -1; // Other is BPO: This is Less } return Long.compare(this.runs, o.runs); //Both BPC: Compare runs } @Override public String toString() { return runsString; } @Override public int hashCode() { int hash = 5; hash = 67 * hash + Objects.hashCode(this.runs); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Runs other = (Runs) obj; if (!Objects.equals(this.runs, other.runs)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/Security.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; import java.util.HashMap; import java.util.Map; import java.util.Objects; public class Security implements NumberValue, Comparable { private final static Map CACHE = new HashMap<>(); private final String security; private final Double securityValue; public static Security create(String key) { Security cached = CACHE.get(key); if (cached == null) { cached = new Security(key); CACHE.put(key, cached); } return cached; } private Security(String security) { this.security = security; Double d; try { d = Double.valueOf(security); } catch (NumberFormatException e) { d = null; } securityValue = d; } public String getSecurity() { return security; } @Override public Double getDouble() { return securityValue; //To change body of generated methods, choose Tools | Templates. } @Override public Number getNumber() { return securityValue; } @Override public String toString() { return security; } @Override public int compareTo(Security o) { return this.getSecurity().compareTo(o.getSecurity()); } @Override public int hashCode() { int hash = 7; hash = 37 * hash + Objects.hashCode(this.security); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Security other = (Security) obj; if (!Objects.equals(this.security, other.security)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/Standing.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; import java.util.HashMap; import java.util.Map; import net.nikr.eve.jeveasset.gui.shared.Formatter; public class Standing implements NumberValue, Comparable { private final static Map CACHE = new HashMap<>(); private final String standingFormatted; private final double standing; public static Standing create(final double standing) { String standingFormat = Formatter.doubleFormat(standing); Standing cached = CACHE.get(standingFormat); if (cached == null) { cached = new Standing(standing, standingFormat); CACHE.put(standingFormat, cached); } return cached; } private Standing(double standing, String standingFormat) { this.standing = standing; this.standingFormatted = standingFormat; } public double getStanding() { return standing; } @Override public Number getNumber() { return standing; } @Override public Double getDouble() { return standing; } @Override public int compareTo(Standing o) { return Double.compare(standing, o.standing); } @Override public String toString() { return standingFormatted; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/TextIcon.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; import java.util.Objects; import javax.swing.Icon; public class TextIcon implements Comparable { public final Icon icon; public final String text; public TextIcon(Icon icon, String text) { this.icon = icon; this.text = text; } public Icon getIcon() { return icon; } public String getText() { return text; } @Override public int compareTo(TextIcon o) { return text.compareToIgnoreCase(o.text); } @Override public String toString() { if (text == null) { return ""; } else { return text; } } @Override public int hashCode() { int hash = 5; hash = 29 * hash + Objects.hashCode(this.text); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final TextIcon other = (TextIcon) obj; return Objects.equals(this.text, other.text); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/shared/table/containers/YesNo.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.table.containers; import net.nikr.eve.jeveasset.i18n.DialoguesAccount; public class YesNo implements Comparable { private static final YesNo YES = new YesNo(true); private static final YesNo NO = new YesNo(false); public static YesNo get(final boolean b) { if (b) { return YES; } else { return NO; } } private final boolean b; private final String text; private YesNo(final boolean b) { this.b = b; if (b) { text = DialoguesAccount.get().tableFormatYes(); } else { text =DialoguesAccount.get().tableFormatNo(); } } @Override public String toString() { return text; } @Override public int compareTo(final YesNo o) { return this.toString().compareToIgnoreCase(o.toString()); } @Override public int hashCode() { int hash = 3; hash = 17 * hash + (this.b ? 1 : 0); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final YesNo other = (YesNo) obj; if (this.b != other.b) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/sounds/DefaultSound.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.sounds; import java.awt.Toolkit; import java.io.IOException; import java.io.InputStream; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; public enum DefaultSound implements Sound { NONE("") { @Override public void play() { } @Override public void stop() { } @Override public String getText() { return DialoguesSettings.get().soundsNone(); } }, ARMOR("armor.mp3") { @Override public String getText() { return DialoguesSettings.get().soundsEveArmor(); } }, CAPACITOR("capacitor.mp3") { @Override public String getText() { return DialoguesSettings.get().soundsEveCapacitor(); } }, CARGO("cargo.mp3") { @Override public String getText() { return DialoguesSettings.get().soundsEveCargo(); } }, CHARACTER_SELECT("character_select.mp3") { @Override public String getText() { return DialoguesSettings.get().soundsEveCharacterSelection(); } }, LOGIN("login.mp3") { @Override public String getText() { return DialoguesSettings.get().soundsEveLogin(); } }, NOTIFICATION_PING("notification_ping.mp3") { @Override public String getText() { return DialoguesSettings.get().soundsEveNotificationPing(); } }, SHIELD("shield.mp3") { @Override public String getText() { return DialoguesSettings.get().soundsEveShield(); } }, SKILL("skill.mp3") { @Override public String getText() { return DialoguesSettings.get().soundsEveSkill(); } }, START("start.mp3") { @Override public String getText() { return DialoguesSettings.get().soundsEveStart(); } }, STRUCTURE("structure.mp3") { @Override public String getText() { return DialoguesSettings.get().soundsEveStructure(); } }, BEEP("") { @Override public void play() { Toolkit.getDefaultToolkit().beep(); } @Override public void stop() { } @Override public String getText() { return DialoguesSettings.get().soundsBeep(); } },; public abstract String getText(); private final String filename; private SoundThread thread = null; private DefaultSound(String filename) { this.filename = filename; } protected String getFilename() { return filename; } @Override public boolean exist() { return true; } @Override public String getID() { return name(); } @Override public void play() { thread = new SoundThread(this); thread.start(); } @Override public InputStream createInputStream() throws IOException { return DefaultSound.class.getResourceAsStream(filename); } @Override public void stop() { if (thread != null) { thread.stopPlayback(); thread = null; } } @Override public String toString() { return getText(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/sounds/FileSound.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.sounds; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Objects; public class FileSound implements Sound { private final File file; private SoundThread thread = null; public FileSound(File file) { this.file = file; } @Override public String getID() { return file.getName(); } @Override public boolean exist() { return file.exists(); } @Override public InputStream createInputStream() throws IOException { return new FileInputStream(file); } @Override public void play() { thread = new SoundThread(this); thread.start(); } @Override public void stop() { if (thread != null) { thread.stopPlayback(); thread = null; } } @Override public String toString() { return file.getName(); } @Override public int hashCode() { int hash = 3; hash = 29 * hash + Objects.hashCode(this.file); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final FileSound other = (FileSound) obj; return Objects.equals(this.file, other.file); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/sounds/Sound.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.sounds; import java.io.IOException; import java.io.InputStream; public interface Sound { public void play(); public void stop(); public boolean exist(); public InputStream createInputStream() throws IOException; public String getID(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/sounds/SoundPlayer.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.sounds; import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.dialogs.settings.SoundsSettingsPanel.SoundOption; public class SoundPlayer { private static ScheduledExecutorService EXECUTOR = Executors.newSingleThreadScheduledExecutor(); private static boolean play = false; private SoundPlayer() { } public static void load() { SoundPlayer.play = true; } public static void play(SoundOption option) { play(Settings.get().getSoundSettings().get(option)); } public static void play(Sound sound) { if (!play) { return; } if (sound != null) { sound.play(); } } public synchronized static void playAt(Date date, SoundOption option) { if (date == null || date.before(Settings.getNow())) { return; //In the past } long diff = Math.abs(date.getTime() - Settings.getNow().getTime()); long ms = TimeUnit.MILLISECONDS.convert(diff, TimeUnit.MILLISECONDS); EXECUTOR.schedule(new Runnable(){ @Override public void run() { play(option); } }, ms, TimeUnit.MILLISECONDS); } public synchronized static void cancelAll() { EXECUTOR.shutdownNow(); EXECUTOR = Executors.newSingleThreadScheduledExecutor(); } public static void stop(Sound sound) { if (sound != null) { sound.stop(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/sounds/SoundThread.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.sounds; import java.io.IOException; import java.io.InputStream; import javazoom.jl.decoder.JavaLayerException; import javazoom.jl.player.Player; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SoundThread extends Thread { private static final Logger LOG = LoggerFactory.getLogger(SoundThread.class); private final Sound sound; private Player player = null; public SoundThread(Sound sound) { this.sound = sound; } @Override public void run() { try { InputStream is = sound.createInputStream(); if (is == null) { return; } player = new Player(is); player.play(); } catch (JavaLayerException ex) { LOG.error(ex.getMessage(), ex); } catch (IOException ex) { LOG.error(ex.getMessage(), ex); } finally { player.close(); } } public void stopPlayback() { if (player != null) { player.close(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/agents/AgentsTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.agents; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.Agent; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.tag.TagUpdate; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabPrimary; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.TabsAgents; public class AgentsTab extends JMainTabPrimary implements TagUpdate { //GUI private final JAutoColumnTable jTable; //Table private final AgentsFilterControl filterControl; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventTableModel tableModel; private final EventList eventList; private final FilterList filterList; private final DefaultEventSelectionModel selectionModel; public static final String NAME = "agents"; //Not to be changed! public AgentsTab(final Program program) { super(program, NAME, TabsAgents.get().agents(), Images.TOOL_AGENTS.getIcon(), true); layout.setAutoCreateGaps(true); //Table Format tableFormat = TableFormatFactory.agentsTableFormat(); //Backend eventList = EventListManager.create(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedList); eventList.getReadWriteLock().readLock().unlock(); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JAutoColumnTable(program, tableModel); jTable.setCellSelectionEnabled(true); jTable.setRowSelectionAllowed(true); jTable.setColumnSelectionAllowed(true); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new AgentsFilterControl(sortedList); //Menu installTableTool(new AgentsTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, Agent.class); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(StaticData.get().getAgents().values()); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } @Override public void updateTags() { beforeUpdateData(); tableModel.fireTableDataChanged(); filterControl.refilter(); afterUpdateData(); } @Override public void clearData() { } @Override public void updateCache() { filterControl.createCache(); } @Override public Collection getLocations() { return new ArrayList<>(); //LocationsType } public boolean isFiltersEmpty() { return filterControl.isFiltersEmpty(); } public void addFilters(final List filters) { filterControl.addFilters(filters); } public void clearFilters() { filterControl.clearCurrentFilters(); } public String getCurrentFilterName() { return filterControl.getCurrentFilterName(); } private class AgentsTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { } @Override public void addToolMenu(JComponent jComponent) { } } private class AgentsFilterControl extends FilterControl { public AgentsFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("Agents Table: " + msg); //Save Agents Filters and Export Settings } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/agents/AgentsTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.agents; import java.util.Comparator; import net.nikr.eve.jeveasset.data.sde.Agent; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.Security; import net.nikr.eve.jeveasset.gui.shared.table.containers.YesNo; import net.nikr.eve.jeveasset.i18n.TabsAgents; public enum AgentsTableFormat implements EnumTableColumn { AGENT(String.class) { @Override public String getColumnName() { return TabsAgents.get().columnName(); } @Override public Object getColumnValue(final Agent from) { return from.getAgent(); } }, CORPORATION(String.class) { @Override public String getColumnName() { return TabsAgents.get().columnCorporation(); } @Override public Object getColumnValue(final Agent from) { return from.getCorporationName(); } }, FACTION(String.class) { @Override public String getColumnName() { return TabsAgents.get().columnFaction(); } @Override public Object getColumnValue(final Agent from) { return from.getFaction(); } }, LEVEL(Integer.class) { @Override public String getColumnName() { return TabsAgents.get().columnLevel(); } @Override public Object getColumnValue(final Agent from) { return from.getLevel(); } }, LOCATION(String.class) { @Override public String getColumnName() { return TabsAgents.get().columnLocation(); } @Override public Object getColumnValue(final Agent from) { return from.getLocation().getLocation(); } }, SECURITY(Security.class) { @Override public String getColumnName() { return TabsAgents.get().columnSecurity(); } @Override public Object getColumnValue(final Agent from) { return from.getLocation().getSecurityObject(); } }, SYSTEM(String.class) { @Override public String getColumnName() { return TabsAgents.get().columnSystem(); } @Override public Object getColumnValue(final Agent from) { return from.getLocation().getSystem(); } }, CONSTELLATION(String.class) { @Override public String getColumnName() { return TabsAgents.get().columnConstellation(); } @Override public Object getColumnValue(final Agent from) { return from.getLocation().getConstellation(); } }, REGION(String.class) { @Override public String getColumnName() { return TabsAgents.get().columnRegion(); } @Override public Object getColumnValue(final Agent from) { return from.getLocation().getRegion(); } }, DIVISION(String.class) { @Override public String getColumnName() { return TabsAgents.get().columnDivision(); } @Override public Object getColumnValue(final Agent from) { return from.getDivision(); } }, AGENT_TYPE(String.class) { @Override public String getColumnName() { return TabsAgents.get().columnType(); } @Override public Object getColumnValue(final Agent from) { return from.getAgentType(); } }, LOCATOR(YesNo.class) { @Override public String getColumnName() { return TabsAgents.get().columnLocator(); } @Override public Object getColumnValue(final Agent from) { return YesNo.get(from.isLocator()); } }, AGENT_ID(Integer.class) { @Override public String getColumnName() { return TabsAgents.get().columnAgentID(); } @Override public Object getColumnValue(final Agent from) { return from.getAgentID(); } }, CORPORATION_ID(Integer.class) { @Override public String getColumnName() { return TabsAgents.get().columnCorporationID(); } @Override public Object getColumnValue(final Agent from) { return from.getCorporationID(); } }, FACTION_ID(Integer.class) { @Override public String getColumnName() { return TabsAgents.get().columnFactionID(); } @Override public Object getColumnValue(final Agent from) { return from.getFactionID(); } }; private final Class type; private final Comparator comparator; private AgentsTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/assets/AssetTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.assets; import java.util.Comparator; import java.util.Date; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.AssetContainer; import net.nikr.eve.jeveasset.gui.shared.table.containers.LongInt; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.gui.shared.table.containers.Runs; import net.nikr.eve.jeveasset.gui.shared.table.containers.Security; import net.nikr.eve.jeveasset.gui.shared.table.containers.YesNo; import net.nikr.eve.jeveasset.i18n.TabsAssets; public enum AssetTableFormat implements EnumTableColumn { NAME(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnName(); } @Override public Object getColumnValue(final MyAsset from) { return from.getName(); } }, NAME_TYPE(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnNameType(); } @Override public Object getColumnValue(final MyAsset from) { return from.getTypeName(); } @Override public boolean isShowDefault() { return false; } }, NAME_CUSTOM(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnNameCustom(); } @Override public Object getColumnValue(final MyAsset from) { return from.getItemName(); } @Override public boolean isShowDefault() { return false; } }, TAGS(Tags.class) { @Override public String getColumnName() { return TabsAssets.get().columnTags(); } @Override public Object getColumnValue(final MyAsset from) { return from.getTags(); } }, GROUP(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnGroup(); } @Override public Object getColumnValue(final MyAsset from) { return from.getItem().getGroup(); } }, CATEGORY(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnCategory(); } @Override public Object getColumnValue(final MyAsset from) { return from.getItem().getCategory(); } }, SLOT(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnSlot(); } @Override public Object getColumnValue(final MyAsset from) { return from.getItem().getSlot(); } }, CHARGE_SIZE(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnChargeSize(); } @Override public Object getColumnValue(final MyAsset from) { return from.getItem().getChargeSize(); } }, OWNER(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnOwner(); } @Override public Object getColumnValue(final MyAsset from) { return from.getOwnerName(); } }, LOCATION(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnLocation(); } @Override public Object getColumnValue(final MyAsset from) { return from.getLocation().getLocation(); } }, SECURITY(Security.class) { @Override public String getColumnName() { return TabsAssets.get().columnSecurity(); } @Override public Object getColumnValue(final MyAsset from) { return from.getLocation().getSecurityObject(); } }, SYSTEM(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnSystem(); } @Override public Object getColumnValue(final MyAsset from) { return from.getLocation().getSystem(); } }, CONSTELLATION(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnConstellation(); } @Override public Object getColumnValue(final MyAsset from) { return from.getLocation().getConstellation(); } }, REGION(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnRegion(); } @Override public Object getColumnValue(final MyAsset from) { return from.getLocation().getRegion(); } }, FACTION_WARFARE_SYSTEM_OWNER(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnFactionWarfareSystemOwner(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnFactionWarfareSystemOwnerToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getLocation().getFactionWarfareSystemOwner(); } }, CONTAINER(AssetContainer.class) { @Override public String getColumnName() { return TabsAssets.get().columnContainer(); } @Override public Object getColumnValue(final MyAsset from) { return from.getAssetContainer(); } }, FLAG(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnFlag(); } @Override public Object getColumnValue(final MyAsset from) { return from.getFlagName(); } }, PRICE(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnPrice(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getDynamicPrice(); } }, PRICE_SELL_MIN(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnPriceSellMin(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceSellMinToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getPriceSellMin(); } }, PRICE_BUY_MAX(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnPriceBuyMax(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceBuyMaxToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getPriceBuyMax(); } }, PRICE_REPROCESSED(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnPriceReprocessed(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceReprocessedToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getPriceReprocessed(); } }, PRICE_MANUFACTURING(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnPriceManufacturing(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceManufacturingToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getItem().getPriceManufacturing(); } }, TRANSACTION_PRICE_LATEST(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnTransactionPriceLatest(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnTransactionPriceLatestToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getMarketPriceData().getLatest(); } }, TRANSACTION_PRICE_AVERAGE(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnTransactionPriceAverage(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnTransactionPriceAverageToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getMarketPriceData().getAverage(); } }, TRANSACTION_PRICE_MAXIMUM(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnTransactionPriceMaximum(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnTransactionPriceMaximumToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getMarketPriceData().getMaximum(); } }, TRANSACTION_PRICE_MINIMUM(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnTransactionPriceMinimum(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnTransactionPriceMinimumToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getMarketPriceData().getMinimum(); } }, PRICE_BASE(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnPriceBase(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceBaseToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getItem().getPriceBase(); } }, VALUE_REPROCESSED(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnValueReprocessed(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnValueReprocessedToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getValueReprocessed(); } }, VALUE(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnValue(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnValueToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getValue(); } }, PRICE_REPROCESSED_DIFFERENCE(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnPriceReprocessedDifference(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceReprocessedDifferenceToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getPriceReprocessedDifference(); } }, PRICE_REPROCESSED_PERCENT(Percent.class) { @Override public String getColumnName() { return TabsAssets.get().columnPriceReprocessedPercent(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceReprocessedPercentToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return Percent.create(from.getPriceReprocessedPercent()); } }, COUNT(Long.class) { @Override public String getColumnName() { return TabsAssets.get().columnCount(); } @Override public Object getColumnValue(final MyAsset from) { return from.getCount(); } }, COUNT_TYPE(Long.class) { @Override public String getColumnName() { return TabsAssets.get().columnTypeCount(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnTypeCountToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getTypeCount(); } }, META(Integer.class) { @Override public String getColumnName() { return TabsAssets.get().columnMeta(); } @Override public Object getColumnValue(final MyAsset from) { return from.getItem().getMeta(); } }, TECH(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnTech(); } @Override public Object getColumnValue(final MyAsset from) { return from.getItem().getTech(); } }, VOLUME(Float.class) { @Override public String getColumnName() { return TabsAssets.get().columnVolume(); } @Override public Object getColumnValue(final MyAsset from) { return from.getVolume(); } }, VOLUME_TOTAL(Float.class) { @Override public String getColumnName() { return TabsAssets.get().columnVolumeTotal(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnVolumeTotalToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getVolumeTotal(); } }, VOLUME_PACKAGED(Float.class) { @Override public String getColumnName() { return TabsAssets.get().columnVolumePackaged(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnVolumePackagedToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getItem().getVolumePackaged(); } }, VALUE_PER_VOLUME(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnValuePerVolume(); } @Override public Object getColumnValue(final MyAsset from) { return from.getValuePerVolume(); } }, SINGLETON(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnSingleton(); } @Override public Object getColumnValue(final MyAsset from) { return from.getSingleton(); } }, ADDED(Date.class) { @Override public String getColumnName() { return TabsAssets.get().columnAdded(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnAddedToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getAdded(); } @Override public boolean isShowDefault() { return false; } }, MATERIAL_EFFICIENCY(Integer.class) { @Override public String getColumnName() { return TabsAssets.get().columnMaterialEfficiency(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnMaterialEfficiencyToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getMaterialEfficiency(); } }, TIME_EFFICIENCY(Integer.class) { @Override public String getColumnName() { return TabsAssets.get().columnTimeEfficiency(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnTimeEfficiencyToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getTimeEfficiency(); } }, RUNS(Runs.class) { @Override public String getColumnName() { return TabsAssets.get().columnRuns(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnRunsToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return new Runs(from.getRuns()); } }, CITADEL(YesNo.class) { @Override public String getColumnName() { return TabsAssets.get().columnStructure(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnStructureToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return YesNo.get(from.getLocation().isCitadel()); } @Override public boolean isShowDefault() { return false; } }, ITEM_ID(LongInt.class) { @Override public String getColumnName() { return TabsAssets.get().columnItemID(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnItemIDToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return new LongInt(from.getItemID()); } }, LOCATION_ID(LongInt.class) { @Override public String getColumnName() { return TabsAssets.get().columnLocationID(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnLocationIDToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return new LongInt(from.getLocationID()); } }, TYPE_ID(Integer.class) { @Override public String getColumnName() { return TabsAssets.get().columnTypeID(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnTypeIDToolTip(); } @Override public Object getColumnValue(final MyAsset from) { return from.getItem().getTypeID(); } }; private final Class type; private final Comparator comparator; private AssetTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/assets/AssetsTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.assets; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.awt.CardLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JToggleButton; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.tag.TagUpdate; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.JStatusLabel; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabPrimary; import net.nikr.eve.jeveasset.gui.shared.components.JTreemap; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.AutoNumberFormat; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData.AssetMenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTab; import net.nikr.eve.jeveasset.i18n.TabsAssets; public class AssetsTab extends JMainTabPrimary implements TagUpdate { private enum AssetsAction { REPROCESS_COLORS, TREEMAP_VIEW } //GUI private final JAssetTable jTable; private final JToggleButton jReprocessColors; private final JToggleButton jTreemap; private final JStatusLabel jValue; private final JStatusLabel jReprocessed; private final JStatusLabel jCount; private final JStatusLabel jAverage; private final JStatusLabel jVolume; private final JButton jClearNew; private final JTreemap jTreemapView; private final JPanel jViewPanel; private final CardLayout viewLayout; private static final String VIEW_TABLE = "table"; private static final String VIEW_TREEMAP = "treemap"; //Table private final AssetFilterControl filterControl; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventTableModel tableModel; private final EventList eventList; private final FilterList filterList; private final DefaultEventSelectionModel selectionModel; public static final String NAME = "assets"; //Not to be changed! public AssetsTab(final Program program) { super(program, NAME, TabsAssets.get().assets(), Images.TOOL_ASSETS.getIcon(), false); layout.setAutoCreateGaps(true); ListenerClass listener = new ListenerClass(); JFixedToolBar jToolBar = new JFixedToolBar(); jClearNew = new JButton(TabsAssets.get().clearNew(), Images.UPDATE_DONE_OK.getIcon()); jClearNew.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Settings.get().getTableChanged().put(NAME, new Date()); jTable.repaint(); jClearNew.setEnabled(false); program.saveSettings("Table Changed (assets cleared)"); } }); jToolBar.addButton(jClearNew); jReprocessColors = new JToggleButton(TabsAssets.get().reprocessColors(), Images.TOOL_REPROCESSED.getIcon()); jReprocessColors.setToolTipText(TabsAssets.get().reprocessColorsToolTip()); jReprocessColors.setSelected(Settings.get().isReprocessColors()); jReprocessColors.setActionCommand(AssetsAction.REPROCESS_COLORS.name()); jReprocessColors.addActionListener(listener); jToolBar.addButton(jReprocessColors); jTreemap = new JToggleButton(TabsAssets.get().treemap(), Images.TOOL_TREE.getIcon()); jTreemap.setToolTipText(TabsAssets.get().treemapToolTip()); jTreemap.setActionCommand(AssetsAction.TREEMAP_VIEW.name()); jTreemap.addActionListener(listener); jToolBar.addButton(jTreemap); //Table Format tableFormat = TableFormatFactory.assetTableFormat(); //Backend eventList = program.getProfileData().getAssetsEventList(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedList); eventList.getReadWriteLock().readLock().unlock(); filterList.addListEventListener(listener); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JAssetTable(program, tableModel); jTable.setCellSelectionEnabled(true); jTable.setRowSelectionAllowed(true); jTable.setColumnSelectionAllowed(true); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new AssetFilterControl(sortedList); //Menu installTableTool(new AssetTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, MyAsset.class); jTreemapView = new JTreemap(new JTreemap.SelectionListener() { @Override public void itemSelected(String group) { applyGroupFilter(group); } }); viewLayout = new CardLayout(); jViewPanel = new JPanel(viewLayout); jViewPanel.add(jTableScroll, VIEW_TABLE); jViewPanel.add(jTreemapView, VIEW_TREEMAP); viewLayout.show(jViewPanel, VIEW_TABLE); jVolume = StatusPanel.createLabel(TabsAssets.get().totalVolume(), Images.ASSETS_VOLUME.getIcon(), AutoNumberFormat.DOUBLE); this.addStatusbarLabel(jVolume); jCount = StatusPanel.createLabel(TabsAssets.get().totalCount(), Images.EDIT_ADD.getIcon(), AutoNumberFormat.ITEMS); this.addStatusbarLabel(jCount); jAverage = StatusPanel.createLabel(TabsAssets.get().average(), Images.ASSETS_AVERAGE.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jAverage); jReprocessed = StatusPanel.createLabel(TabsAssets.get().totalReprocessed(), Images.SETTINGS_REPROCESSING.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jReprocessed); jValue = StatusPanel.createLabel(TabsAssets.get().totalValue(), Images.TOOL_VALUES.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jValue); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar) .addComponent(jViewPanel, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jViewPanel, 0, 0, Short.MAX_VALUE) ); } @Override public void updateTags() { beforeUpdateData(); tableModel.fireTableDataChanged(); filterControl.refilter(); afterUpdateData(); } @Override public void clearData() { } @Override public void updateCache() { Date current = Settings.get().getTableChanged(NAME); boolean newFound = false; try { eventList.getReadWriteLock().readLock().lock(); for (MyAsset asset : eventList) { if (current.before(asset.getAdded())) { newFound = true; break; } } } finally { eventList.getReadWriteLock().readLock().unlock(); } filterControl.createCache(); final boolean found = newFound; Program.ensureEDT(new Runnable() { @Override public void run() { jClearNew.setEnabled(found); } }); } @Override public Collection getLocations() { try { eventList.getReadWriteLock().readLock().lock(); return new ArrayList<>(eventList); } finally { eventList.getReadWriteLock().readLock().unlock(); } } public boolean isFiltersEmpty() { return filterControl.isFiltersEmpty(); } public void addFilters(final List filters) { filterControl.addFilters(filters); } public void clearFilters() { filterControl.clearCurrentFilters(); } public String getCurrentFilterName() { return filterControl.getCurrentFilterName(); } private void updateStatusbar() { double averageValue = 0; double totalValue = 0; long totalCount = 0; double totalVolume = 0; double totalReprocessed = 0; try { filterList.getReadWriteLock().readLock().lock(); for (MyAsset asset : filterList) { totalValue = totalValue + (asset.getDynamicPrice() * asset.getCount()); totalCount = totalCount + asset.getCount(); totalVolume = totalVolume + asset.getVolumeTotal(); totalReprocessed = totalReprocessed + asset.getValueReprocessed(); } } finally { filterList.getReadWriteLock().readLock().unlock(); } if (totalCount > 0 && totalValue > 0) { averageValue = totalValue / totalCount; } jVolume.setNumber(totalVolume); jCount.setNumber(totalCount); jAverage.setNumber(averageValue); jReprocessed.setNumber(totalReprocessed); jValue.setNumber(totalValue); } public void updateReprocessColors() { jReprocessColors.setSelected(Settings.get().isReprocessColors()); } @Override public void tableDataChanged() { super.tableDataChanged(); if (jTreemap.isSelected()) { updateTreemapData(); } } private void updateTreemapData() { Map groupValues = new HashMap<>(); try { filterList.getReadWriteLock().readLock().lock(); for (MyAsset asset : filterList) { String group = asset.getItem().getGroup(); if (group == null || group.isEmpty()) { group = "Unknown"; } double value = asset.getValue(); if (value <= 0) { continue; } groupValues.put(group, groupValues.getOrDefault(group, 0.0) + value); } } finally { filterList.getReadWriteLock().readLock().unlock(); } jTreemapView.setItems(groupValues); } private void showTreemap(boolean show) { if (show) { updateTreemapData(); viewLayout.show(jViewPanel, VIEW_TREEMAP); } else { viewLayout.show(jViewPanel, VIEW_TABLE); } } private void applyGroupFilter(String group) { if (group == null || group.isEmpty()) { return; } if (jTreemap.isSelected()) { jTreemap.setSelected(false); showTreemap(false); } List filters = new ArrayList<>(); for (Filter filter : filterControl.getCurrentFilters()) { if (filter == null || filter.isEmpty()) { continue; } if (filter.getColumn() instanceof AssetTableFormat) { AssetTableFormat column = (AssetTableFormat) filter.getColumn(); if (column == AssetTableFormat.GROUP) { continue; } } filters.add(filter); } filters.add(new Filter(Filter.LogicType.AND, AssetTableFormat.GROUP, Filter.CompareType.EQUALS, group)); filterControl.clearCurrentFilters(); filterControl.addFilters(filters); } /** * returns a new list of the filtered assets, thus the list is modifiable. * @return a list of the filtered assets. */ public List getFilteredAssets() { return EventListManager.safeList(filterList); } private class AssetTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new AssetMenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { JMenuInfo.infoItem(jPopupMenu, selectionModel.getSelected()); } @Override public void addToolMenu(JComponent jComponent) { } } private class ListenerClass implements ListEventListener, ActionListener { @Override public void listChanged(final ListEvent listChanges) { updateStatusbar(); OverviewTab overviewTab = program.getOverviewTab(false); if (overviewTab != null) { overviewTab.updateTable(); } if (jTreemap.isSelected()) { updateTreemapData(); } } @Override public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals(AssetsAction.REPROCESS_COLORS.name())) { boolean oldValue = Settings.get().isReprocessColors(); boolean newValue = jReprocessColors.isSelected(); if (oldValue != newValue) { Settings.lock("Reprocess Colors"); Settings.get().setReprocessColors(newValue); Settings.unlock("Reprocess Colors"); program.saveSettings("Reprocess Colors"); jTable.repaint(); TreeTab treeTab = program.getTreeTab(false); if (treeTab != null) { treeTab.updateReprocessColors(); } } } else if (e.getActionCommand().equals(AssetsAction.TREEMAP_VIEW.name())) { showTreemap(jTreemap.isSelected()); } } } private class AssetFilterControl extends FilterControl { public AssetFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override protected void updateFilters() { if (program != null) { OverviewTab overviewTab = program.getOverviewTab(false); if (overviewTab != null) { overviewTab.updateFilters(); } } } @Override public void saveSettings(final String msg) { program.saveSettings("Assets Table: " + msg); //Save Asset Filters and Export Settings } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/assets/JAssetTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.assets; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; public class JAssetTable extends JAutoColumnTable { private final DefaultEventTableModel tableModel; public JAssetTable(final Program program, final DefaultEventTableModel tableModel) { super(program, tableModel); this.tableModel = tableModel; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); boolean isSelected = isCellSelected(row, column); MyAsset asset = tableModel.getElementAt(row); String columnName = (String) this.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); //User set price if (asset.isUserPrice() && columnName.equals(AssetTableFormat.PRICE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.CUSTOM_PRICE, isSelected); return component; } //User set name if (asset.isUserName() && columnName.equals(AssetTableFormat.NAME.getColumnName())) { ColorSettings.configCell(component, ColorEntry.CUSTOM_ASSET_NAME, isSelected); return component; } //User set location if (asset.getLocation().isUserLocation() && columnName.equals(AssetTableFormat.LOCATION.getColumnName())) { ColorSettings.configCell(component, ColorEntry.CUSTOM_USER_LOCATION, isSelected); return component; } //Blueprint Original if (asset.isBPO() && asset.getItem().isBlueprint() && (columnName.equals(AssetTableFormat.PRICE.getColumnName()) || columnName.equals(AssetTableFormat.PRICE_SELL_MIN.getColumnName()) || columnName.equals(AssetTableFormat.PRICE_BUY_MAX.getColumnName()) || columnName.equals(AssetTableFormat.NAME.getColumnName()))) { ColorSettings.configCell(component, ColorEntry.GLOBAL_BPO, isSelected); return component; } //Blueprint Copy if (asset.isBPC() && asset.getItem().isBlueprint() && (columnName.equals(AssetTableFormat.PRICE.getColumnName()) || columnName.equals(AssetTableFormat.PRICE_SELL_MIN.getColumnName()) || columnName.equals(AssetTableFormat.PRICE_BUY_MAX.getColumnName()) || columnName.equals(AssetTableFormat.NAME.getColumnName()))) { ColorSettings.configCell(component, ColorEntry.GLOBAL_BPC, isSelected); return component; } //Reprocessing Colors if (Settings.get().isReprocessColors() && !isSelected) { //Zero price (White) if (asset.getPriceReprocessed() == 0 || asset.getDynamicPrice() == 0) { return component; } //Equal price (Yellow) boolean rowSelection = (this.isRowSelected(row) && Settings.get().isHighlightSelectedRows()); if (asset.getPriceReprocessed() == asset.getDynamicPrice()) { ColorSettings.configCell(component, ColorEntry.ASSETS_REPROCESSING_EQUAL, rowSelection, true); return component; } //Reprocessed highest (Red) if (asset.getPriceReprocessed() > asset.getDynamicPrice()) { ColorSettings.configCell(component, ColorEntry.ASSETS_REPROCESSING_REPROCES, rowSelection, true); return component; } //Price highest (Green) if (asset.getPriceReprocessed() < asset.getDynamicPrice()) { ColorSettings.configCell(component, ColorEntry.ASSETS_REPROCESSING_SELL, rowSelection, true); return component; } } //Reproccessed is greater then price if (asset.getPriceReprocessed() > asset.getDynamicPrice() && columnName.equals(AssetTableFormat.PRICE_REPROCESSED.getColumnName())) { ColorSettings.configCell(component, ColorEntry.ASSETS_REPROCESS, isSelected); return component; } //Added date if (columnName.equals(AssetTableFormat.ADDED.getColumnName()) && Settings.get().getTableChanged(AssetsTab.NAME).before(asset.getAdded())) { ColorSettings.configCell(component, ColorEntry.ASSETS_NEW, isSelected); } return component; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/contracts/ContractsSeparatorTableCell.java ================================================ /* Glazed Lists (c) 2003-2006 */ /* http://publicobject.com/glazedlists/ publicobject.com,*/ /* O'Dell Engineering Ltd.*/ package net.nikr.eve.jeveasset.gui.tabs.contracts; import ca.odell.glazedlists.SeparatorList; import java.awt.Font; import java.awt.event.ActionListener; import javax.swing.GroupLayout; import javax.swing.JLabel; import javax.swing.JTable; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.gui.shared.table.SeparatorTableCell; import net.nikr.eve.jeveasset.i18n.TabsContracts; public class ContractsSeparatorTableCell extends SeparatorTableCell { private final JLabel jName; private final JLabel jType; public ContractsSeparatorTableCell(final JTable jTable, final SeparatorList separatorList, final ActionListener actionListener) { super(jTable, separatorList); jName = new JLabel(); Font font = jName.getFont(); jName.setFont(new Font(font.getName(), Font.BOLD, font.getSize() + 1)); JLabel jTypeLabel = new JLabel(TabsContracts.get().type()); jTypeLabel.setFont(new Font(font.getName(), Font.BOLD, font.getSize())); jType = new JLabel(); layout.setHorizontalGroup( layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addComponent(jExpand) .addGap(10) .addComponent(jName, 220, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addGap(10) .addComponent(jTypeLabel) .addGap(4) .addComponent(jType) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGap(2) .addGroup(layout.createParallelGroup() .addComponent(jExpand, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jName, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jTypeLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(2) ); } @Override protected void configure(SeparatorList.Separator separator) { MyContractItem item = (MyContractItem) separator.first(); if (item == null) { // handle 'late' rendering calls after this separator is invalid return; } jName.setText(item.getContract().getTitle()); jType.setText(item.getContract().getTypeName()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/contracts/ContractsTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.contracts; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.raw.RawContract.ContractStatus; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.JStatusLabel; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabPrimary; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.AutoNumberFormat; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuUI.ContractMenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JSeparatorTable; import net.nikr.eve.jeveasset.gui.shared.table.PaddingTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.TabsContracts; import net.nikr.eve.jeveasset.io.local.profile.ProfileDatabase; public class ContractsTab extends JMainTabPrimary { private enum ContractsAction { COLLAPSE, EXPAND } //GUI private final JSeparatorTable jTable; private final JStatusLabel jContractCount; private final JStatusLabel jSellingPrice; private final JStatusLabel jSellingAssets; private final JStatusLabel jBuying; private final JStatusLabel jSold; private final JStatusLabel jBought; private final JStatusLabel jCollateralIssuer; private final JStatusLabel jCollateralAcceptor; //Table private final EventList eventList; private final FilterList filterList; private final SeparatorList separatorList; private final DefaultEventSelectionModel selectionModel; private final DefaultEventTableModel tableModel; private final EnumTableFormatAdaptor tableFormat; private final ContractsFilterControl filterControl; public static final String NAME = "contracts"; //Not to be changed! public ContractsTab(Program program) { super(program, NAME, TabsContracts.get().title(), Images.TOOL_CONTRACTS.getIcon(), true); ListenerClass listener = new ListenerClass(); //StatusPanels must be initialized before the eventlist jContractCount = StatusPanel.createLabel(TabsContracts.get().contractCount(), Images.INCLUDE_CONTRACTS.getIcon(), AutoNumberFormat.LONG); addStatusbarLabel(jContractCount); jSellingPrice = StatusPanel.createLabel(TabsContracts.get().sellingPrice(), Images.ORDERS_SELL.getIcon(), AutoNumberFormat.ISK); addStatusbarLabel(jSellingPrice); jSellingAssets = StatusPanel.createLabel(TabsContracts.get().sellingAssets(), Images.TOOL_VALUES.getIcon(), AutoNumberFormat.ISK); addStatusbarLabel(jSellingAssets); jBuying = StatusPanel.createLabel(TabsContracts.get().buying(), Images.ORDERS_BUY.getIcon(), AutoNumberFormat.ISK); addStatusbarLabel(jBuying); jSold = StatusPanel.createLabel(TabsContracts.get().sold(), Images.ORDERS_SOLD.getIcon(), AutoNumberFormat.ISK); addStatusbarLabel(jSold); jBought = StatusPanel.createLabel(TabsContracts.get().bought(), Images.ORDERS_BOUGHT.getIcon(), AutoNumberFormat.ISK); addStatusbarLabel(jBought); jCollateralIssuer = StatusPanel.createLabel(TabsContracts.get().collateralIssuer(), Images.ORDERS_ESCROW.getIcon(), AutoNumberFormat.ISK); addStatusbarLabel(jCollateralIssuer); jCollateralAcceptor = StatusPanel.createLabel(TabsContracts.get().collateralAcceptor(), Images.UPDATE_WORKING.getIcon(), AutoNumberFormat.ISK); addStatusbarLabel(jCollateralAcceptor); JFixedToolBar jToolBar = new JFixedToolBar(); jToolBar.addGlue(); JButton jCollapse = new JButton(TabsContracts.get().collapse(), Images.MISC_COLLAPSED.getIcon()); jCollapse.setActionCommand(ContractsAction.COLLAPSE.name()); jCollapse.addActionListener(listener); jToolBar.addButton(jCollapse); JButton jExpand = new JButton(TabsContracts.get().expand(), Images.MISC_EXPANDED.getIcon()); jExpand.setActionCommand(ContractsAction.EXPAND.name()); jExpand.addActionListener(listener); jToolBar.addButton(jExpand); //Table Format tableFormat = TableFormatFactory.contractsTableFormat(); //Backend eventList = program.getProfileData().getContractItemEventList(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedListColumn = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Sorting Separator (ensure export always has the right order) eventList.getReadWriteLock().readLock().lock(); SortedList sortedListSeparator = new SortedList<>(sortedListColumn, new SeparatorComparator()); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedListColumn); eventList.getReadWriteLock().readLock().unlock(); //Statusbar updater filterList.addListEventListener(listener); //Separator eventList.getReadWriteLock().readLock().lock(); separatorList = new SeparatorList<>(filterList, new SeparatorComparator(), 1, Integer.MAX_VALUE); eventList.getReadWriteLock().readLock().unlock(); //Table Model tableModel = EventModels.createTableModel(separatorList, tableFormat); //Table jTable = new JContractsTable(program, tableModel, separatorList); jTable.setSeparatorRenderer(new ContractsSeparatorTableCell(jTable, separatorList, listener)); jTable.setSeparatorEditor(new ContractsSeparatorTableCell(jTable, separatorList, listener)); jTable.setCellSelectionEnabled(true); PaddingTableCellRenderer.install(jTable, 3); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedListColumn, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); comparatorChooser.addSortActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { separatorList.setComparator(new SeparatorComparator(comparatorChooser)); } }); //Selection Model selectionModel = EventModels.createSelectionModel(separatorList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new ContractsFilterControl(sortedListSeparator); //Menu installTableTool(new ContractsTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, MyContractItem.class); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(filterControl.getPanel()) .addComponent(jToolBar, jToolBar.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void clearData() { filterControl.clearCache(); } @Override public void updateCache() { filterControl.createCache(); } @Override public Collection getLocations() { return new ArrayList<>(); //LocationsType } private MyContract getSelectedContract() { int index = jTable.getSelectedRow(); if (index < 0 || index >= tableModel.getRowCount()) { return null; } Object o = tableModel.getElementAt(index); if (o instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) o; MyContractItem item = (MyContractItem) separator.first(); return item.getContract(); } else if (o instanceof MyContractItem) { MyContractItem item = (MyContractItem) o; return item.getContract(); } return null; } public void addFilters(final List filters) { filterControl.addFilters(filters); } private class ContractsTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new ContractMenuData(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { JMenuInfo.contracts(program, jPopupMenu, selectionModel.getSelected()); } @Override public void addToolMenu(JComponent jComponent) { MyContract contract = getSelectedContract(); boolean enabled = contract != null && !contract.isESI() && selectionModel.getSelected().size() == 1; JMenu jStatus = new JMenu(TabsContracts.get().status()); jStatus.setIcon(Images.MISC_STATUS.getIcon()); if (!enabled) { jStatus.setIcon(jStatus.getDisabledIcon()); } jComponent.add(jStatus); JRadioButtonMenuItem jMenuItem; for (ContractStatus status : ContractStatus.values()) { jMenuItem = new JRadioButtonMenuItem(MyContract.getStatusName(status)); jMenuItem.setEnabled(enabled); jMenuItem.setSelected(enabled && status == contract.getStatus()); jMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (contract == null || contract.isESI() || status == contract.getStatus()) { return; } boolean before = contract.isOpen(); contract.setStatus(status); if (before != contract.isOpen()) { program.updateEventListsWithProgress(); } else { tableModel.fireTableDataChanged(); } program.saveTable(ProfileDatabase.Table.CONTRACTS); } }); jStatus.add(jMenuItem); } MenuManager.addSeparator(jComponent); } } private class ListenerClass implements ActionListener, ListEventListener { @Override public void actionPerformed(final ActionEvent e) { if (ContractsAction.COLLAPSE.name().equals(e.getActionCommand())) { jTable.expandSeparators(false); } if (ContractsAction.EXPAND.name().equals(e.getActionCommand())) { jTable.expandSeparators(true); } } @Override public void listChanged(final ListEvent listChanges) { double contractCount = 0; double sellingPrice = 0; double sellingAssets = 0; double buying = 0; double sold = 0; double bought = 0; double collateralIssuer = 0; double collateralAcceptor = 0; try { filterList.getReadWriteLock().readLock().lock(); Set contracts = new HashSet<>(); for (MyContractItem contractItem : filterList) { contracts.add(contractItem.getContract()); MyContract contract = contractItem.getContract(); if (contract.isIgnoreContract()) { continue; } boolean isIssuer = contract.isForCorp() ? program.getOwners().keySet().contains(contract.getIssuerCorpID()) : program.getOwners().keySet().contains(contract.getIssuerID()); if (isIssuer && //Issuer contract.isOpen() //Not completed && contractItem.isIncluded()) { //Selling sellingAssets = sellingAssets + contractItem.getDynamicPrice() * contractItem.getQuantity(); } } contractCount = contracts.size(); for (MyContract contract : contracts) { boolean isIssuer = contract.isForCorp() ? program.getOwners().keySet().contains(contract.getIssuerCorpID()) : program.getOwners().keySet().contains(contract.getIssuerID()); boolean isAcceptor = contract.getAcceptorID() > 0 && program.getOwners().keySet().contains(contract.getAcceptorID()); if (contract.isCourierContract()) { if (isIssuer && (contract.isInProgress() || contract.isOpen())) { //Collateral Issuer collateralIssuer = collateralIssuer + contract.getCollateral(); } if (isAcceptor && contract.isInProgress()) { //Collateral Acceptor collateralAcceptor = collateralAcceptor + contract.getCollateral(); } } if (contract.isIgnoreContract()) { continue; } if (isIssuer //Issuer && contract.isOpen() //Not completed ) { //Selling/Buying sellingPrice = sellingPrice + contract.getPrice(); //Positive buying = buying - contract.getReward(); //Negative } else if (contract.isCompletedSuccessful()) { //Completed if (isIssuer) { //Sold/Bought sold = sold + contract.getPrice(); //Positive bought = bought - contract.getReward(); //Negative } if (isAcceptor) { //Reverse of the above sold = sold + contract.getReward(); //Positive bought = bought - contract.getPrice(); //Negative } } } } finally { filterList.getReadWriteLock().readLock().unlock(); } jContractCount.setNumber(contractCount); jSellingPrice.setNumber(sellingPrice); jSellingAssets.setNumber(sellingAssets); jSold.setNumber(sold); jBuying.setNumber(buying); jBought.setNumber(bought); jCollateralIssuer.setNumber(collateralIssuer); jCollateralAcceptor.setNumber(collateralAcceptor); } } public class SeparatorComparator implements Comparator { private final List> comparators = new ArrayList<>(); public SeparatorComparator() { } @SuppressWarnings({"unchecked", "rawtypes"}) public SeparatorComparator(TableComparatorChooser install) { if (install == null) { return; } Map formats = new HashMap<>(); for (ContractsTableFormat format : ContractsTableFormat.values()) { formats.put(format.ordinal(), format); } List sortingColumns = install.getSortingColumns(); for (Integer index : sortingColumns) { ContractsTableFormat format = formats.get(index); if (!format.isContract()) { continue; } boolean reverse = install.isColumnReverse(index); List columnComparators = install.getComparatorsForColumn(index); int comparatorIndex = install.getColumnComparatorIndex(index); if (comparatorIndex < 0 || comparatorIndex >= columnComparators.size()) { continue; } Comparator comparator; if (reverse) { comparator = columnComparators.get(comparatorIndex).reversed(); } else { comparator = columnComparators.get(comparatorIndex); } this.comparators.add(comparator); } } @Override public int compare(final MyContractItem o1, final MyContractItem o2) { Integer l1 = o1.getContract().getContractID(); Integer l2 = o2.getContract().getContractID(); int group = l1.compareTo(l2); if (group == 0) { return group; } for (Comparator comparator : comparators) { int order = comparator.compare(o1, o2); if (order != 0) { return order; } } return group; } } private class ContractsFilterControl extends FilterControl { public ContractsFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override protected void afterFilter() { jTable.loadExpandedState(); } @Override protected void beforeFilter() { jTable.saveExpandedState(); } @Override public void saveSettings(final String msg) { program.saveSettings("Contracts Table: " + msg); //Save Contract Filters and Export Settings } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/contracts/ContractsTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.contracts; import java.util.Comparator; import java.util.Date; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.LongInt; import net.nikr.eve.jeveasset.gui.shared.table.containers.Runs; import net.nikr.eve.jeveasset.gui.shared.table.containers.YesNo; import net.nikr.eve.jeveasset.i18n.TabsContracts; public enum ContractsTableFormat implements EnumTableColumn { NAME(String.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnName(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getName(); } }, TITLE(String.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnTitle(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getTitle(); } }, TYPE(String.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnType(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getTypeName(); } }, STATUS(String.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnStatus(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getStatusFormatted(); } }, AVAILABILITY(String.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnAvailability(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getAvailabilityFormatted(); } }, INCLUDED(String.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnIncluded(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getIncluded(); } }, QUANTITY(Long.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnQuantity(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getQuantity(); } }, SINGLETON(String.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnSingleton(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getSingleton(); } }, TYPE_ID(Integer.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnTypeID(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getTypeID(); } }, VOLUME(Double.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnVolume(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getVolume(); } }, Runs(Runs.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnRuns(); } @Override public String getColumnToolTip() { return TabsContracts.get().columnRunsToolTip(); } @Override public Object getColumnValue(final MyContractItem from) { return new Runs(from.getRuns()); } }, ME(Integer.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnMaterialEfficiency(); } @Override public String getColumnToolTip() { return TabsContracts.get().columnMaterialEfficiencyToolTip(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getME(); } }, TE(Integer.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnTimeEfficiency(); } @Override public String getColumnToolTip() { return TabsContracts.get().columnTimeEfficiencyToolTip(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getTE(); } }, MARKET_PRICE(Double.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnMarketPrice(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getDynamicPrice(); } }, PRICE_REPROCESSED(Double.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnPriceReprocessed(); } @Override public String getColumnToolTip() { return TabsContracts.get().columnPriceReprocessedToolTip(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getItem().getPriceReprocessed(); } }, PRICE_MANUFACTURING(Double.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnPriceManufacturing(); } @Override public String getColumnToolTip() { return TabsContracts.get().columnPriceManufacturingToolTip(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getItem().getPriceManufacturing(); } }, MARKET_VALUE(Double.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnMarketValue(); } @Override public String getColumnToolTip() { return TabsContracts.get().columnMarketValueToolTip(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getDynamicPrice() * from.getQuantity(); } }, REPROCESSED_VALUE(Double.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnValueReprocessed(); } @Override public String getColumnToolTip() { return TabsContracts.get().columnValueReprocessedToolTip(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getItem().getPriceReprocessed() * from.getQuantity(); } }, MANUFACTURING_VALUE(Double.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnValueManufacturing(); } @Override public String getColumnToolTip() { return TabsContracts.get().columnValueManufacturingToolTip(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getItem().getPriceManufacturing() * from.getQuantity(); } }, PRICE(Double.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnPrice(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getPrice(); } }, BUYOUT(Double.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnBuyout(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getBuyout(); } }, COLLATERAL(Double.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnCollateral(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getCollateral(); } }, NUM_DAYS(Integer.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnNumDays(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getDaysToComplete(); } }, REWARD(Double.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnReward(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getReward(); } }, FOR_CORP(YesNo.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnForCorp(); } @Override public Object getColumnValue(final MyContractItem from) { return YesNo.get(from.getContract().isForCorp()); } }, ISSUER(String.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnIssuer(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getIssuer(); } }, ISSUER_CORP(String.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnIssuerCorp(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getIssuerCorp(); } }, ASSIGNEE(String.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnAssignee(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getAssignee(); } }, ACCEPTOR(String.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnAcceptor(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getAcceptor(); } }, OWNED(YesNo.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnOwned(); } @Override public String getColumnToolTip() { return TabsContracts.get().columnOwnedToolTip(); } @Override public Object getColumnValue(final MyContractItem from) { return YesNo.get(from.getContract().isOwned()); } }, START_STATION(String.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnStartStation(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getStartLocation(); } }, END_STATION(String.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnEndStation(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getEndLocation(); } }, ISSUED_DATE(Date.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnIssued(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getDateIssued(); } }, EXPIRED_DATE(Date.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnExpired(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getDateExpired(); } }, ACCEPTED_DATE(Date.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnAccepted(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getDateAccepted(); } }, COMPLETED_DATE(Date.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnCompleted(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getDateCompleted(); } }, CONTRACT_ID(Integer.class, true) { @Override public String getColumnName() { return TabsContracts.get().columnContractID(); } @Override public Object getColumnValue(final MyContractItem from) { return from.getContract().getContractID(); } }, RECORD_ID(LongInt.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnRecordID(); } @Override public Object getColumnValue(final MyContractItem from) { return new LongInt(from.getRecordID()); } }, ITEM_ID(LongInt.class, false) { @Override public String getColumnName() { return TabsContracts.get().columnItemID(); } @Override public Object getColumnValue(final MyContractItem from) { return new LongInt(from.getItemID()); } }; private final Class type; private final boolean contract; private final Comparator comparator; private ContractsTableFormat(final Class type, boolean contract) { this.type = type; this.contract = contract; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } public boolean isContract() { return contract; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/contracts/JContractsTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.contracts; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.gui.shared.table.JSeparatorTable; public class JContractsTable extends JSeparatorTable { private final DefaultEventTableModel tableModel; public JContractsTable(final Program program, final DefaultEventTableModel tableModel, SeparatorList separatorList) { super(program, tableModel, separatorList); this.tableModel = tableModel; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); boolean isSelected = isCellSelected(row, column); Object object = tableModel.getElementAt(row); String columnName = (String) this.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); if (object instanceof MyContractItem) { MyContractItem item = (MyContractItem) object; if (!item.getContract().isCourierContract() && item.getTypeID() == 0) { ColorSettings.configCell(component, ColorEntry.GLOBAL_ENTRY_INVALID, isSelected); } else if (columnName.equals(ContractsTableFormat.NAME.getColumnName())) { if (item.getContract().isCourierContract()) { ColorSettings.configCell(component, ColorEntry.CONTRACTS_COURIER, isSelected); } else if (item.isIncluded()) { ColorSettings.configCell(component, ColorEntry.CONTRACTS_INCLUDED, isSelected); } else { ColorSettings.configCell(component, ColorEntry.CONTRACTS_EXCLUDED, isSelected); } } //User set location if ((item.getContract().getStartLocation() != null && item.getContract().getStartLocation().isUserLocation() && columnName.equals(ContractsTableFormat.START_STATION.getColumnName())) || (item.getContract().getEndLocation() != null && item.getContract().getEndLocation().isUserLocation() && columnName.equals(ContractsTableFormat.END_STATION.getColumnName()))) { ColorSettings.configCell(component, ColorEntry.CUSTOM_USER_LOCATION, isSelected); return component; } } return component; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/items/ItemTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.items; import java.util.Comparator; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.TabsItems; public enum ItemTableFormat implements EnumTableColumn { NAME(String.class) { @Override public String getColumnName() { return TabsItems.get().columnName(); } @Override public Object getColumnValue(final Item from) { return from.getTypeName(); } }, GROUP(String.class) { @Override public String getColumnName() { return TabsItems.get().columnGroup(); } @Override public Object getColumnValue(final Item from) { return from.getGroup(); } }, CATEGORY(String.class) { @Override public String getColumnName() { return TabsItems.get().columnCategory(); } @Override public Object getColumnValue(final Item from) { return from.getCategory(); } }, SLOT(String.class) { @Override public String getColumnName() { return TabsItems.get().columnSlot(); } @Override public Object getColumnValue(final Item from) { return from.getSlot(); } }, CHARGE_SIZE(String.class) { @Override public String getColumnName() { return TabsItems.get().columnChargeSize(); } @Override public Object getColumnValue(final Item from) { return from.getChargeSize(); } }, PRICE_BASE(Double.class) { @Override public String getColumnName() { return TabsItems.get().columnPriceBase(); } @Override public Object getColumnValue(final Item from) { return from.getPriceBase(); } }, PRICE_REPROCESSED(Double.class) { @Override public String getColumnName() { return TabsItems.get().columnPriceReprocessed(); } @Override public Object getColumnValue(final Item from) { return from.getPriceReprocessed(); } }, PRICE_MANUFACTURING(Double.class) { @Override public String getColumnName() { return TabsItems.get().columnPriceManufacturing(); } @Override public String getColumnToolTip() { return TabsItems.get().columnPriceManufacturingToolTip(); } @Override public Object getColumnValue(final Item from) { return from.getItem().getPriceManufacturing(); } }, META(Integer.class) { @Override public String getColumnName() { return TabsItems.get().columnMeta(); } @Override public Object getColumnValue(final Item from) { return from.getMeta(); } }, TECH(String.class) { @Override public String getColumnName() { return TabsItems.get().columnTech(); } @Override public Object getColumnValue(final Item from) { return from.getTech(); } }, VOLUME(Float.class) { @Override public String getColumnName() { return TabsItems.get().columnVolume(); } @Override public Object getColumnValue(final Item from) { return from.getVolume(); } }, VOLUME_PACKAGED(Float.class) { @Override public String getColumnName() { return TabsItems.get().columnVolumePackaged(); } @Override public Object getColumnValue(final Item from) { return from.getVolumePackaged(); } }, TYPE_ID(Integer.class) { @Override public String getColumnName() { return TabsItems.get().columnTypeID(); } @Override public Object getColumnValue(final Item from) { return from.getTypeID(); } }; private final Class type; private final Comparator comparator; private ItemTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/items/ItemsTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.items; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.util.ArrayList; import java.util.Collection; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabPrimary; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.TabsItems; public class ItemsTab extends JMainTabPrimary { private final JAutoColumnTable jTable; //Table private final ItemsFilterControl filterControl; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventTableModel tableModel; private final FilterList filterList; private final EventList eventList; private final DefaultEventSelectionModel selectionModel; public static final String NAME = "items"; //Not to be changed! public ItemsTab(final Program program) { super(program, NAME, TabsItems.get().items(), Images.TOOL_ITEMS.getIcon(), true); //Table Format tableFormat = TableFormatFactory.itemTableFormat(); //Backend eventList = EventListManager.create(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedList); eventList.getReadWriteLock().readLock().unlock(); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JAutoColumnTable(program, tableModel); jTable.setCellSelectionEnabled(true); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new ItemsFilterControl(sortedList); //Menu installTableTool(new ItemTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, Item.class); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(StaticData.get().getItems().values()); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } @Override public void clearData() { filterControl.clearCache(); } @Override public void updateCache() { filterControl.createCache(); } @Override public Collection getLocations() { return new ArrayList<>(); //No Location } private class ItemTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { } @Override public void addToolMenu(JComponent jComponent) { } } private class ItemsFilterControl extends FilterControl { public ItemsFilterControl(SortedList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("Items Table: " + msg); //Save Item Filters and Export Settings } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/jobs/IndustryJobTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.jobs; import java.util.Comparator; import java.util.Date; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.Duration; import net.nikr.eve.jeveasset.gui.shared.table.containers.YesNo; import net.nikr.eve.jeveasset.i18n.TabsJobs; public enum IndustryJobTableFormat implements EnumTableColumn { STATE(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnState(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getStatusFormatted(); } }, ACTIVITY(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnActivity(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getActivity(); } }, NAME(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnName(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getName(); } }, GROUP(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnGroup(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getItem().getGroup(); } }, OWNER(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnOwner(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getOwnerName(); } }, INSTALLER(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnInstaller(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getInstaller(); } }, OWNED(YesNo.class) { @Override public String getColumnName() { return TabsJobs.get().columnOwned(); } @Override public String getColumnToolTip() { return TabsJobs.get().columnOwnedToolTip(); } @Override public Object getColumnValue(final MyIndustryJob from) { return YesNo.get(from.isOwned()); } }, COMPLETED_CHARACTER(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnCompletedCharacter(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getCompletedCharacter(); } }, LOCATION(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnLocation(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getLocation().getLocation(); } }, SYSTEM(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnSystem(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getLocation().getSystem(); } }, CONSTELLATION(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnConstellation(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getLocation().getConstellation(); } }, REGION(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnRegion(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getLocation().getRegion(); } }, START_DATE(Date.class) { @Override public String getColumnName() { return TabsJobs.get().columnStartDate(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getStartDate(); } }, END_DATE(Date.class) { @Override public String getColumnName() { return TabsJobs.get().columnEndDate(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getEndDate(); } }, COMPLETED_DATE(Date.class) { @Override public String getColumnName() { return TabsJobs.get().columnCompletedDate(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getCompletedDate(); } }, TIME_LEFT(Duration.class) { @Override public String getColumnName() { return TabsJobs.get().columnTimeLeft(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getTimeLeft(); } }, PAUSE_DATE(Date.class) { @Override public String getColumnName() { return TabsJobs.get().columnPauseDate(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getPauseDate(); } }, RUNS(Integer.class) { @Override public String getColumnName() { return TabsJobs.get().columnRuns(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getRuns(); } }, OUTPUT_COUNT(Integer.class) { @Override public String getColumnName() { return TabsJobs.get().columnOutputCount(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getOutputCount(); } }, OUTPUT_VALUE(Double.class) { @Override public String getColumnName() { return TabsJobs.get().columnOutputValue(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getOutputValue(); } }, OUTPUT_VOLUME(Double.class) { @Override public String getColumnName() { return TabsJobs.get().columnOutputVolume(); } @Override public String getColumnToolTip() { return TabsJobs.get().columnOutputVolumeToolTip(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getOutputVolume(); } }, OUTPUT_TYPE(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnOutputType(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getOutputItem().getTypeName(); } }, OUTPUT_GROUP(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnOutputGroup(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getOutputItem().getGroup(); } }, OUTPUT_CATEGORY(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnOutputCategory(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getOutputItem().getCategory(); } }, BPO(String.class) { @Override public String getColumnName() { return TabsJobs.get().columnBPO(); } @Override public Object getColumnValue(final MyIndustryJob from) { if (from.isBPC()) { return TabsJobs.get().bpc(); } else { return TabsJobs.get().bpo(); } } }, MATERIAL_EFFICIENCY(Integer.class) { @Override public String getColumnName() { return TabsJobs.get().columnMaterialEfficiency(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getMaterialEfficiency(); } }, TIME_EFFICIENCY(Integer.class) { @Override public String getColumnName() { return TabsJobs.get().columnTimeEfficiency(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getTimeEfficiency(); } }, COST(Double.class) { @Override public String getColumnName() { return TabsJobs.get().columnCost(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getCost(); } }, JOB_ID(Integer.class) { @Override public String getColumnName() { return TabsJobs.get().columnJobID(); } @Override public Object getColumnValue(final MyIndustryJob from) { return from.getJobID(); } @Override public boolean isShowDefault() { return false; } }; private final Class type; private final Comparator comparator; private IndustryJobTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/jobs/IndustryJobsTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.jobs; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.Timer; import javax.swing.event.TableModelEvent; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob.IndustryJobStatus; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.JStatusLabel; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabPrimary; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.AutoNumberFormat; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.PaddingTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.TabsJobs; import net.nikr.eve.jeveasset.io.local.profile.ProfileDatabase; public class IndustryJobsTab extends JMainTabPrimary { private static final int TIME_LEFT_SECONDS = 63; private static final int TIME_LEFT_SECONDS_MS = TIME_LEFT_SECONDS * 1000; private final JAutoColumnTable jTable; private final JStatusLabel jCount; private final JStatusLabel jInventionSuccess; private final JStatusLabel jManufactureOutputValue; private final Timer updateTimeLeftColumnSeconds; private final Timer updateTimeLeftColumnMinutes; private Timer startTimeLeftColumnSeconds; private int updatedSeconds; //Table private final EventList eventList; private final FilterList filterList; private final DefaultEventTableModel tableModel; private final DefaultEventSelectionModel selectionModel; private final IndustryJobsFilterControl filterControl; private final EnumTableFormatAdaptor tableFormat; public static final String NAME = "industryjobs"; //Not to be changed! public IndustryJobsTab(final Program program) { super(program, NAME, TabsJobs.get().industry(), Images.TOOL_INDUSTRY_JOBS.getIcon(), true); ListenerClass listener = new ListenerClass(); updateTimeLeftColumnSeconds = new Timer(1000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updatedSeconds++; updateTimeLeft(); if (updatedSeconds > TIME_LEFT_SECONDS) { startTimeLeft(); } } }); updateTimeLeftColumnMinutes = new Timer(60 * 1000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateTimeLeft(); } }); //StatusPanels must be initialized before the eventlist jInventionSuccess = StatusPanel.createLabel(TabsJobs.get().inventionSuccess(), Images.JOBS_INVENTION_SUCCESS.getIcon(), AutoNumberFormat.PERCENT); this.addStatusbarLabel(jInventionSuccess); jManufactureOutputValue = StatusPanel.createLabel(TabsJobs.get().manufactureJobsValue(), Images.TOOL_VALUES.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jManufactureOutputValue); jCount = StatusPanel.createLabel(TabsJobs.get().count(), Images.EDIT_ADD.getIcon(), AutoNumberFormat.ITEMS); this.addStatusbarLabel(jCount); //Table Format tableFormat = TableFormatFactory.industryJobTableFormat(); //Backend eventList = program.getProfileData().getIndustryJobsEventList(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedList); eventList.getReadWriteLock().readLock().unlock(); filterList.addListEventListener(listener); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JIndustryJobsTable(program, tableModel); jTable.setCellSelectionEnabled(true); PaddingTableCellRenderer.install(jTable, 1); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new IndustryJobsFilterControl(sortedList); //Menu installTableTool(new JobsTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, MyIndustryJob.class); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 700, 700, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 100, 400, Short.MAX_VALUE) ); } @Override public void clearData() { filterControl.clearCache(); } @Override public void updateCache() { filterControl.createCache(); } @Override public Collection getLocations() { try { eventList.getReadWriteLock().readLock().lock(); return new ArrayList<>(eventList); } finally { eventList.getReadWriteLock().readLock().unlock(); } } public void addFilters(final List filters) { filterControl.addFilters(filters); } private MyIndustryJob getSelectedIndustryJob() { int index = jTable.getSelectedRow(); if (index < 0 || index >= tableModel.getRowCount()) { return null; } return tableModel.getElementAt(index); } public void tabChanged() { startTimeLeft(); } private void updateTimeLeft() { for (int column = 0; column < jTable.getColumnCount(); column++) { String columnName = (String) jTable.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); if (columnName.equals(IndustryJobTableFormat.TIME_LEFT.getColumnName())) { tableModel.fireTableChanged(new TableModelEvent(tableModel, 0, jTable.getRowCount() - 1, column)); return; } } } private void stopTimeLeft() { //Stop if (startTimeLeftColumnSeconds != null) { startTimeLeftColumnSeconds.stop(); startTimeLeftColumnSeconds = null; } updateTimeLeftColumnSeconds.stop(); updateTimeLeftColumnMinutes.stop(); } private void startTimeLeft() { stopTimeLeft(); if (!program.getMainWindow().getSelectedTab().equals(this)) { return; //No focus } //Find next complete Long duration = null; try { eventList.getReadWriteLock().readLock().lock(); for (MyIndustryJob industryJob : eventList) { if (industryJob.getTimeLeft().getDuration()<= 0) { continue; //Already completed } if (duration == null) { duration = industryJob.getTimeLeft().getDuration(); } else { duration = Math.min(duration, industryJob.getTimeLeft().getDuration()); } } } finally { eventList.getReadWriteLock().readLock().unlock(); } if (duration != null && duration < TIME_LEFT_SECONDS_MS) { updatedSeconds = 0; updateTimeLeftColumnSeconds.start(); } else { if (duration != null) { startTimeLeftColumnSeconds = new Timer((int) (duration - TIME_LEFT_SECONDS_MS), new ActionListener() { @Override public void actionPerformed(ActionEvent e) { stopTimeLeft(); updatedSeconds = 0; updateTimeLeftColumnSeconds.start(); } }); startTimeLeftColumnSeconds.start(); } //Else: No in-progress industry jobs updateTimeLeftColumnMinutes.start(); } } private class JobsTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { JMenuInfo.industryJob(jPopupMenu, selectionModel.getSelected()); } @Override public void addToolMenu(JComponent jComponent) { MyIndustryJob industryJob = getSelectedIndustryJob(); boolean enabled = industryJob != null && !industryJob.isESI() && selectionModel.getSelected().size() == 1; JMenu jStatus = new JMenu(TabsJobs.get().status()); jStatus.setIcon(Images.MISC_STATUS.getIcon()); if (!enabled) { jStatus.setIcon(jStatus.getDisabledIcon()); } jComponent.add(jStatus); JRadioButtonMenuItem jMenuItem; for (IndustryJobStatus status : IndustryJobStatus.values()) { jMenuItem = new JRadioButtonMenuItem(MyIndustryJob.getStatusName(status)); jMenuItem.setEnabled(enabled); jMenuItem.setSelected(enabled && status == industryJob.getStatus()); jMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (industryJob == null || industryJob.isESI() || industryJob.getStatus() == status) { return; } boolean before = industryJob.isNotDeliveredToAssets(); industryJob.setStatus(status); if (before != industryJob.isNotDeliveredToAssets()) { program.updateEventListsWithProgress(); } else { tableModel.fireTableDataChanged(); } program.saveTable(ProfileDatabase.Table.INDUSTRY_JOBS); } }); jStatus.add(jMenuItem); } MenuManager.addSeparator(jComponent); } } private class ListenerClass implements ListEventListener { @Override public void listChanged(final ListEvent listChanges) { startTimeLeft(); int inventionCount = 0; long count = 0; double success = 0; double outputValue = 0; try { filterList.getReadWriteLock().readLock().lock(); for (MyIndustryJob industryJob : filterList) { count++; if (industryJob.isInvention() && industryJob.isDone()) { inventionCount++; if (industryJob.isCompletedSuccessful()) { success++; } } if (industryJob.isNotDeliveredToAssets()) { //Only include active jobs outputValue += industryJob.getOutputValue(); } } } finally { filterList.getReadWriteLock().readLock().unlock(); } if (inventionCount <= 0) { jInventionSuccess.setNumber(0.0); } else { jInventionSuccess.setNumber(success / inventionCount); } jManufactureOutputValue.setNumber(outputValue); jCount.setNumber(count); } } public class IndustryJobsFilterControl extends FilterControl { public IndustryJobsFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("Industry Jobs Table: " + msg); //Save Industry Job Filters and Export Settings } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/jobs/JIndustryJobsTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.jobs; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob.IndustryJobStatus; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; public class JIndustryJobsTable extends JAutoColumnTable { private final DefaultEventTableModel tableModel; public JIndustryJobsTable(Program program, final DefaultEventTableModel tableModel) { super(program, tableModel); this.tableModel = tableModel; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); boolean isSelected = isCellSelected(row, column); MyIndustryJob industryJob = tableModel.getElementAt(row); String columnName = (String) this.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); //BPO if (industryJob.isBPO() && columnName.equals(IndustryJobTableFormat.NAME.getColumnName())) { ColorSettings.configCell(component, ColorEntry.GLOBAL_BPO, isSelected); return component; } //BPC if (industryJob.isBPC() && columnName.equals(IndustryJobTableFormat.NAME.getColumnName())) { ColorSettings.configCell(component, ColorEntry.GLOBAL_BPC, isSelected); return component; } //Completed if (industryJob.getStatus() == IndustryJobStatus.READY && columnName.equals(IndustryJobTableFormat.END_DATE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_JOBS_DONE, isSelected); return component; } if (columnName.equals(IndustryJobTableFormat.ACTIVITY.getColumnName())) { ColorEntry entry = null; switch (industryJob.getActivity()) { case ACTIVITY_MANUFACTURING: entry = ColorEntry.INDUSTRY_JOBS_ACTIVITY_MANUFACTURING; break; case ACTIVITY_RESEARCHING_TECHNOLOGY: entry = ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_TECHNOLOGY; break; case ACTIVITY_RESEARCHING_METERIAL_PRODUCTIVITY: entry = ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_METERIAL_PRODUCTIVITY; break; case ACTIVITY_RESEARCHING_TIME_PRODUCTIVITY: entry = ColorEntry.INDUSTRY_JOBS_ACTIVITY_RESEARCHING_TIME_PRODUCTIVITY; break; case ACTIVITY_COPYING: entry = ColorEntry.INDUSTRY_JOBS_ACTIVITY_COPYING; break; case ACTIVITY_DUPLICATING: entry = ColorEntry.INDUSTRY_JOBS_ACTIVITY_DUPLICATING; break; case ACTIVITY_REVERSE_ENGINEERING: entry = ColorEntry.INDUSTRY_JOBS_ACTIVITY_REVERSE_ENGINEERING; break; case ACTIVITY_REVERSE_INVENTION: entry = ColorEntry.INDUSTRY_JOBS_ACTIVITY_REVERSE_INVENTION; break; case ACTIVITY_REACTIONS: entry = ColorEntry.INDUSTRY_JOBS_ACTIVITY_REACTIONS; break; } if (entry != null) { ColorSettings.configCell(component, entry, isSelected); return component; } } //Delivered if (industryJob.getStatus()== IndustryJobStatus.DELIVERED && columnName.equals(IndustryJobTableFormat.END_DATE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_JOBS_DELIVERED, isSelected); return component; } //User set location if (industryJob.getLocation().isUserLocation() && columnName.equals(IndustryJobTableFormat.LOCATION.getColumnName())) { ColorSettings.configCell(component, ColorEntry.CUSTOM_USER_LOCATION, isSelected); return component; } return component; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/journal/JJournalTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.journal; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; public class JJournalTable extends JAutoColumnTable { private final DefaultEventTableModel tableModel; public JJournalTable(Program program, final DefaultEventTableModel tableModel) { super(program, tableModel); this.tableModel = tableModel; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); boolean isSelected = isCellSelected(row, column); MyJournal journal = tableModel.getElementAt(row); String columnName = (String) this.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); if (columnName.equals(JournalTableFormat.AMOUNT.getColumnName()) && journal.getAmount() < 0) { ColorSettings.configCell(component, ColorEntry.GLOBAL_VALUE_NEGATIVE, isSelected); } if (columnName.equals(JournalTableFormat.BALANCE.getColumnName()) && journal.getBalance() < 0) { ColorSettings.configCell(component, ColorEntry.GLOBAL_VALUE_NEGATIVE, isSelected); } //Added date if (columnName.equals(JournalTableFormat.ADDED.getColumnName()) && Settings.get().getTableChanged(JournalTab.NAME).before(journal.getAdded())) { ColorSettings.configCell(component, ColorEntry.JOURNAL_NEW, isSelected); } return component; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/journal/JournalChartDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.journal; import java.awt.Dimension; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.GroupLayout; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.JFreeChartUtil; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.i18n.TabsJournal; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.labels.XYToolTipGenerator; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.time.SimpleTimePeriod; import org.jfree.data.time.TimePeriodValues; import org.jfree.data.time.TimePeriodValuesCollection; import org.jfree.data.xy.XYDataset; public class JournalChartDialog extends JDialogCentered { private static final ZoneId CHART_ZONE = ZoneId.of("GMT"); private static final int MIN_WIDTH = 720; private static final int MIN_HEIGHT = 420; private final TimePeriodValuesCollection dataset = new TimePeriodValuesCollection(); private final XYLineAndShapeRenderer renderer; private final DateAxis domainAxis; private final NumberAxis rangeAxis; private final ChartPanel jChartPanel; private final JButton jClose; public JournalChartDialog(final Program program) { super(program, TabsJournal.get().chartTitle(), Images.TOOL_JOURNAL.getImage()); domainAxis = JFreeChartUtil.createDateAxis(); rangeAxis = JFreeChartUtil.createNumberAxis(true); renderer = JFreeChartUtil.createRenderer(); renderer.setDefaultToolTipGenerator(new XYToolTipGenerator() { @Override public String generateToolTip(XYDataset dataset, int series, int item) { Date date = new Date(dataset.getX(series, item).longValue()); Number value = dataset.getY(series, item); return "" + dataset.getSeriesKey(series) + ": " + Formatter.iskFormat(value) + "
Date: " + Formatter.columnDateOnly(date); } }); XYPlot plot = JFreeChartUtil.createPlot(dataset, domainAxis, rangeAxis, renderer); JFreeChart jFreeChart = JFreeChartUtil.createChart(plot); jChartPanel = JFreeChartUtil.createChartPanel(jFreeChart); jChartPanel.setPreferredSize(new Dimension(MIN_WIDTH, MIN_HEIGHT)); jClose = new JButton(TabsJournal.get().close()); jClose.addActionListener(e -> getDialog().setVisible(false)); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(jChartPanel) .addComponent(jClose, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jChartPanel) .addComponent(jClose, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ); getDialog().setResizable(true); getDialog().setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT)); getDialog().setModalityType(java.awt.Dialog.ModalityType.MODELESS); } public void showChart(final List journals) { updateData(journals); setVisible(true); } private void updateData(final List journals) { while (dataset.getSeriesCount() != 0) { dataset.removeSeries(0); } if (journals == null || journals.isEmpty()) { return; } TreeMap> values = new TreeMap<>(); Set owners = new HashSet<>(); for (MyJournal journal : journals) { Date day = toDay(journal.getDate()); Map map = values.get(day); if (map == null) { map = new HashMap<>(); values.put(day, map); } String ownerName = journal.getOwnerName(); owners.add(ownerName); double amount = journal.getAmount() != null ? journal.getAmount() : 0.0; map.put(ownerName, map.getOrDefault(ownerName, 0.0) + amount); } List names = new ArrayList<>(owners); Collections.sort(names, String.CASE_INSENSITIVE_ORDER); LocalDate startLocal = values.firstKey().toInstant().atZone(CHART_ZONE).toLocalDate(); LocalDate endLocal = values.lastKey().toInstant().atZone(CHART_ZONE).toLocalDate(); for (LocalDate date = startLocal; !date.isAfter(endLocal); date = date.plusDays(1)) { Date bucket = Date.from(date.atStartOfDay().atZone(CHART_ZONE).toInstant()); Map map = values.get(bucket); for (String name : names) { double value = map != null ? map.getOrDefault(name, 0.0) : 0.0; TimePeriodValues timePeriod = getSeries(name); timePeriod.add(new SimpleTimePeriod(bucket, bucket), value); } } double max = 0.0; int count = 0; for (int i = 0; i < dataset.getSeriesCount(); i++) { count = Math.max(count, dataset.getItemCount(i)); for (int j = 0; j < dataset.getItemCount(i); j++) { Number value = dataset.getY(i, j); if (value != null) { max = Math.max(max, value.doubleValue()); } } } JFreeChartUtil.updateTickScale(domainAxis, rangeAxis, max); renderer.setDefaultShapesVisible(count < 2); } private TimePeriodValues getSeries(final String name) { for (int i = 0; i < dataset.getSeriesCount(); i++) { if (dataset.getSeries(i).getKey().equals(name)) { return dataset.getSeries(i); } } TimePeriodValues series = new TimePeriodValues(name); dataset.addSeries(series); return series; } private Date toDay(Date date) { Instant instant = date.toInstant(); LocalDate localDate = instant.atZone(CHART_ZONE).toLocalDate(); return Date.from(localDate.atStartOfDay().atZone(CHART_ZONE).toInstant()); } @Override protected JComponent getDefaultFocus() { return jClose; } @Override protected JButton getDefaultButton() { return jClose; } @Override protected void windowShown() { } @Override protected void save() { } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/journal/JournalTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.journal; import ca.odell.glazedlists.*; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JOptionPane; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.tag.TagUpdate; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.JStatusLabel; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabPrimary; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.CompareType; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.filter.FilterMatcher; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuAssetFilter; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.PaddingTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.gui.tabs.contracts.ContractsTab; import net.nikr.eve.jeveasset.gui.tabs.contracts.ContractsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.jobs.IndustryJobTableFormat; import net.nikr.eve.jeveasset.gui.tabs.jobs.IndustryJobsTab; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTab; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTableFormat; import net.nikr.eve.jeveasset.i18n.TabsJournal; public class JournalTab extends JMainTabPrimary implements TagUpdate { private final JStatusLabel jPositiveTotal; private final JStatusLabel jBothTotal; private final JStatusLabel jNegativeTotal; private final JAutoColumnTable jTable; private final JButton jClearNew; private final JButton jChart; private final JournalChartDialog chartDialog; //Table private final JournalFilterControl filterControl; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventTableModel tableModel; private final EventList eventList; private final FilterList filterList; private final DefaultEventSelectionModel selectionModel; public static final String NAME = "journal"; //Not to be changed! public JournalTab(final Program program) { super(program, NAME, TabsJournal.get().title(), Images.TOOL_JOURNAL.getIcon(), true); ListenerClass listener = new ListenerClass(); //StatusPanels must be initialized before the eventlist //Positive jPositiveTotal = StatusPanel.createLabel(TabsJournal.get().totalPositive(), Images.ORDERS_SELL.getIcon(), JMenuInfo.AutoNumberFormat.ISK); this.addStatusbarLabel(jPositiveTotal); jBothTotal = StatusPanel.createLabel(TabsJournal.get().total(), Images.TOOL_TRANSACTION.getIcon(), JMenuInfo.AutoNumberFormat.ISK); this.addStatusbarLabel(jBothTotal); //Negative jNegativeTotal = StatusPanel.createLabel(TabsJournal.get().totalNegative(), Images.ORDERS_BUY.getIcon(), JMenuInfo.AutoNumberFormat.ISK); this.addStatusbarLabel(jNegativeTotal); JFixedToolBar jToolBar = new JFixedToolBar(); jClearNew = new JButton(TabsJournal.get().clearNew(), Images.UPDATE_DONE_OK.getIcon()); jClearNew.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Settings.get().getTableChanged().put(NAME, new Date()); jTable.repaint(); jClearNew.setEnabled(false); program.saveSettings("Table Changed (journal cleared)"); } }); jToolBar.addButton(jClearNew); jChart = new JButton(TabsJournal.get().chart(), Images.TOOL_MINING_GRAPH.getIcon()); jChart.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { showChart(); } }); jToolBar.addButton(jChart); //Table Format tableFormat = TableFormatFactory.journalTableFormat(); //Backend eventList = program.getProfileData().getJournalEventList(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedList); eventList.getReadWriteLock().readLock().unlock(); filterList.addListEventListener(listener); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JJournalTable(program, tableModel); jTable.setCellSelectionEnabled(true); PaddingTableCellRenderer.install(jTable, 1); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll Panels JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new JournalFilterControl(sortedList); //Menu installTableTool(new JournalTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, MyJournal.class); chartDialog = new JournalChartDialog(program); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, jToolBar.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } private void showChart() { List journals = new ArrayList<>(); filterList.getReadWriteLock().readLock().lock(); try { journals.addAll(filterList); } finally { filterList.getReadWriteLock().readLock().unlock(); } if (journals.isEmpty()) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsJournal.get().noDataFound(), TabsJournal.get().chartTitle(), JOptionPane.PLAIN_MESSAGE); return; } chartDialog.showChart(journals); } @Override public void updateTags() { beforeUpdateData(); tableModel.fireTableDataChanged(); filterControl.refilter(); afterUpdateData(); } @Override public void clearData() { filterControl.clearCache(); } @Override public void updateCache() { Date current = Settings.get().getTableChanged(NAME); boolean newFound = false; try { eventList.getReadWriteLock().readLock().lock(); for (MyJournal journal : eventList) { if (current.before(journal.getAdded())) { newFound = true; break; } } } finally { eventList.getReadWriteLock().readLock().unlock(); } filterControl.createCache(); final boolean found = newFound; Program.ensureEDT(new Runnable() { @Override public void run() { jClearNew.setEnabled(found); } }); } @Override public Collection getLocations() { return new ArrayList<>(); //No Location } private class JournalTableMenu implements TableMenu { @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { } @Override public void addToolMenu(JComponent jComponent) { JMenu jJournal = new JMenu(TabsJournal.get().findIn()); jJournal.setIcon(Images.TOOL_JOURNAL.getIcon()); jComponent.add(jJournal); Set contractIDs = new HashSet<>(); Set industryJobIDs = new HashSet<>(); Set transactionIDs = new HashSet<>(); for (MyJournal journal : selectionModel.getSelected()) { if (null == journal.getContextType()) { continue; } switch (journal.getContextType()) { case CONTRACT_ID: addSafe(contractIDs, journal.getContextID()); break; case INDUSTRY_JOB_ID: addSafe(industryJobIDs, journal.getContextID()); break; case MARKET_TRANSACTION_ID: addSafe(transactionIDs, journal.getContextID()); break; } } JMenuItem jContracts = new JMenuItem(TabsJournal.get().contracts(), Images.TOOL_CONTRACTS.getIcon()); jContracts.setEnabled(!contractIDs.isEmpty()); jContracts.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { List filters = JMenuAssetFilter.getFilters(contractIDs, ContractsTableFormat.CONTRACT_ID, CompareType.EQUALS); ContractsTab contractsTab = program.getContractsTab(true); contractsTab.addFilters(filters); program.getMainWindow().addTab(contractsTab); } }); jJournal.add(jContracts); JMenuItem jIndustryJobs = new JMenuItem(TabsJournal.get().industryJobs(), Images.TOOL_INDUSTRY_JOBS.getIcon()); jIndustryJobs.setEnabled(!industryJobIDs.isEmpty()); jIndustryJobs.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { List filters = JMenuAssetFilter.getFilters(industryJobIDs, IndustryJobTableFormat.JOB_ID, CompareType.EQUALS); IndustryJobsTab industryJobsTab = program.getIndustryJobsTab(true); industryJobsTab.addFilters(filters); program.getMainWindow().addTab(industryJobsTab); } }); jJournal.add(jIndustryJobs); JMenuItem jTransactions = new JMenuItem(TabsJournal.get().transactions(), Images.TOOL_TRANSACTION.getIcon()); jTransactions.setEnabled(!transactionIDs.isEmpty()); jTransactions.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { List filters = JMenuAssetFilter.getFilters(transactionIDs, TransactionTableFormat.TRANSACTION_ID, CompareType.EQUALS); TransactionTab transactionsTab = program.getTransactionsTab(true); transactionsTab.addFilters(filters); program.getMainWindow().addTab(transactionsTab); } }); jJournal.add(jTransactions); } } private void addSafe(Set set, Long value) { if (value == null || value < 100) { return; } set.add(FilterMatcher.formatFilter(value)); } private class ListenerClass implements ListEventListener { @Override public void listChanged(ListEvent listChanges) { double positiveTotal = 0; double negativeTotal = 0; try { filterList.getReadWriteLock().readLock().lock(); for (MyJournal journal : filterList) { Double amount = journal.getAmount(); if (amount > 0) { //Sell positiveTotal += journal.getAmount(); } else { //Buy negativeTotal += journal.getAmount(); } } } finally { filterList.getReadWriteLock().readLock().unlock(); } double bothTotal = positiveTotal + negativeTotal; jPositiveTotal.setNumber(positiveTotal); jBothTotal.setNumber(bothTotal); jNegativeTotal.setNumber(negativeTotal); } } private class JournalFilterControl extends FilterControl { public JournalFilterControl(SortedList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("Journal Table: " + msg); //Save Journal Filters and Export Settings } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/journal/JournalTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.journal; import java.util.Comparator; import java.util.Date; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.LongInt; import net.nikr.eve.jeveasset.i18n.TabsJournal; public enum JournalTableFormat implements EnumTableColumn { DATE(Date.class) { @Override public String getColumnName() { return TabsJournal.get().columnDate(); } @Override public Object getColumnValue(final MyJournal from) { return from.getDate(); } }, TAGS(Tags.class) { @Override public String getColumnName() { return TabsJournal.get().columnTags(); } @Override public Object getColumnValue(final MyJournal from) { return from.getTags(); } }, ADDED(Date.class) { @Override public String getColumnName() { return TabsJournal.get().columnAdded(); } @Override public String getColumnToolTip() { return TabsJournal.get().columnAddedToolTip(); } @Override public Object getColumnValue(final MyJournal from) { return from.getAdded(); } }, REF_TYPE(String.class) { @Override public String getColumnName() { return TabsJournal.get().columnRefType(); } @Override public Object getColumnValue(final MyJournal from) { return from.getRefTypeFormatted(); } }, AMOUNT(Double.class) { @Override public String getColumnName() { return TabsJournal.get().columnAmount(); } @Override public Object getColumnValue(final MyJournal from) { return from.getAmount(); } }, BALANCE(Double.class) { @Override public String getColumnName() { return TabsJournal.get().columnBalance(); } @Override public Object getColumnValue(final MyJournal from) { return from.getBalance(); } }, OWNER(String.class) { @Override public String getColumnName() { return TabsJournal.get().columnOwner(); } @Override public Object getColumnValue(final MyJournal from) { return from.getOwnerName(); } }, OWNER_NAME_1(String.class) { @Override public String getColumnName() { return TabsJournal.get().columnOwnerName1(); } @Override public Object getColumnValue(final MyJournal from) { return from.getFirstPartyName(); } }, OWNER_NAME_2(String.class) { @Override public String getColumnName() { return TabsJournal.get().columnOwnerName2(); } @Override public Object getColumnValue(final MyJournal from) { return from.getSecondPartyName(); } }, ACCOUNT_KEY(Integer.class) { @Override public String getColumnName() { return TabsJournal.get().columnAccountKey(); } @Override public Object getColumnValue(final MyJournal from) { return from.getAccountKeyFormatted(); } }, TAX_AMOUNT(Double.class) { @Override public String getColumnName() { return TabsJournal.get().columnTaxAmount(); } @Override public Object getColumnValue(final MyJournal from) { return from.getTaxAmount(); } }, REASON(String.class) { @Override public String getColumnName() { return TabsJournal.get().columnReason(); } @Override public Object getColumnValue(final MyJournal from) { return from.getReason(); } }, CONTEXT_NAME(String.class) { @Override public String getColumnName() { return TabsJournal.get().columnContextName(); } @Override public Object getColumnValue(final MyJournal from) { return from.getContext(); } }, CONTEXT_TYPE(String.class) { @Override public String getColumnName() { return TabsJournal.get().columnContextType(); } @Override public Object getColumnValue(final MyJournal from) { return from.getContextTypeName(); } @Override public boolean isShowDefault() { return false; } }, CONTEXT_ID(LongInt.class) { @Override public String getColumnName() { return TabsJournal.get().columnContextID(); } @Override public Object getColumnValue(final MyJournal from) { return new LongInt(from.getContextID()); } @Override public boolean isShowDefault() { return false; } }; private final Class type; private final Comparator comparator; private JournalTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/loadout/Loadout.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.loadout; import ca.odell.glazedlists.matchers.Matcher; import java.util.Collections; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.SimpleOwner; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.data.settings.types.OwnersType; import net.nikr.eve.jeveasset.data.settings.types.PriceType; import net.nikr.eve.jeveasset.gui.shared.CopyHandler.CopySeparator; import net.nikr.eve.jeveasset.gui.shared.table.containers.ModulePriceValue; import net.nikr.eve.jeveasset.i18n.TabsLoadout; public class Loadout implements Comparable, LocationType, ItemType, PriceType, CopySeparator, OwnersType { public enum FlagType { TOTAL_VALUE("Total Value") { @Override String i18n() { return TabsLoadout.get().flagTotalValue(); } }, HIGH_SLOT("HiSlot") { @Override String i18n() { return TabsLoadout.get().flagHighSlot(); } }, MEDIUM_SLOT("MedSlot") { @Override String i18n() { return TabsLoadout.get().flagMediumSlot(); } }, LOW_SLOT("LoSlot") { @Override String i18n() { return TabsLoadout.get().flagLowSlot(); } }, RIG_SLOTS("RigSlot") { @Override String i18n() { return TabsLoadout.get().flagRigSlot(); } }, SUB_SYSTEMS("SubSystem") { @Override String i18n() { return TabsLoadout.get().flagSubSystem(); } }, DRONE_BAY("DroneBay") { @Override String i18n() { return TabsLoadout.get().flagDroneBay(); } }, CARGO("Cargo") { @Override String i18n() { return TabsLoadout.get().flagCargo(); } }, OTHER("") { @Override String i18n() { return TabsLoadout.get().flagOther(); } }; private final String flag; private FlagType(String flag) { this.flag = flag; } abstract String i18n(); public String getFlag() { return flag; } @Override public String toString() { return i18n(); } } private final Item item; private final MyLocation location; //New objects are created by updateData() - no need to update private final SimpleOwner owner; private final String name; private final String shipTypeName; private final String shipItemName; private final Integer shipTypeID; private final String key; private final FlagType flag; private final Double price; private double value; private long count; private final boolean first; private final Set owners; public Loadout(Item item, MyLocation location, SimpleOwner owner, String name, MyAsset ship, String flag, Double price, double value, long count, boolean first) { this.item = item; this.location = location; this.owner = owner; this.name = name; this.shipTypeName = ship.getItem().getTypeName(); //MyAsset.getTypeName() does not return the exact name this.shipItemName = ship.getItemName(); this.shipTypeID = ship.getTypeID(); this.key = ship.getName() + " #" + ship.getItemID(); this.flag = convertFlag(flag); this.price = price; this.value = value; this.count = count; this.first = first; this.owners = Collections.singleton(owner.getOwnerID()); } private FlagType convertFlag(final String s) { for (FlagType type : FlagType.values()) { if (s.contains(type.getFlag())) { return type; } } return FlagType.OTHER; } private String convertName(final String nameFix) { if (nameFix.equals(TabsLoadout.get().totalShip())) { return "1"; } else if (nameFix.equals(TabsLoadout.get().totalModules())) { return "2"; } else if (nameFix.equals(TabsLoadout.get().totalAll())) { return "3"; } else { return nameFix; } } public void addCount(final long addCount) { this.count = this.count + addCount; } public void addValue(final double addValue) { this.value = this.value + addValue; } public long getCount() { return count; } public String getShipTypeName() { return shipTypeName; } public String getShipItemName() { return shipItemName; } public Integer getShipTypeID() { return shipTypeID; } @Override public Double getDynamicPrice() { return price; } public double getValue() { return value; } public String getFlag() { return flag.toString(); } public String getName() { if (getCount() > 1 && flag != FlagType.TOTAL_VALUE) { return getCount() + "x " + name; } else { return name; } } @Override public Item getItem() { return item; } @Override public long getItemCount() { return getCount(); } @Override public MyLocation getLocation() { return location; } @Override public Set getOwners() { return owners; } public String getOwnerName() { return owner.getOwnerName(); } public ModulePriceValue getModulePriceValue() { return new ModulePriceValue(price, value, count); } public boolean isFirst() { return first; } public String getKey() { return key; } public String getSeparator() { return String.valueOf(flag.ordinal()); } protected String getCompare() { return key + flag.ordinal() + convertName(name); } @Override public String getCopyString() { StringBuilder builder = new StringBuilder(); builder.append(getFlag()); return builder.toString(); } @Override public boolean equals(final Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Loadout other = (Loadout) obj; if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { return false; } if ((this.key == null) ? (other.key != null) : !this.key.equals(other.key)) { return false; } if ((this.location == null) ? (other.location != null) : !this.location.equals(other.location)) { return false; } if ((this.flag == null) ? (other.flag != null) : !this.flag.equals(other.flag)) { return false; } return true; } @Override public int hashCode() { int hash = 3; hash = 67 * hash + (this.name != null ? this.name.hashCode() : 0); hash = 67 * hash + (this.key != null ? this.key.hashCode() : 0); hash = 67 * hash + (this.location != null ? this.location.hashCode() : 0); hash = 67 * hash + (this.flag != null ? this.flag.hashCode() : 0); return hash; } /*** * Used by Collections.sort(...). * @param o * @return */ @Override public int compareTo(final Loadout o) { return this.getCompare().compareTo(o.getCompare()); } public static class LoadoutMatcher implements Matcher { private final String key; public LoadoutMatcher(final String key) { this.key = key; } @Override public boolean matches(final Loadout item) { return item.getKey().equals(key); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/loadout/LoadoutData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.loadout; import ca.odell.glazedlists.EventList; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.profile.TableData; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.i18n.TabsLoadout; public class LoadoutData extends TableData { public LoadoutData(Program program) { super(program); } public LoadoutData(ProfileManager profileManager, ProfileData profileData) { super(profileManager, profileData); } public EventList getData() { EventList eventList = EventListManager.create(); updateData(eventList); return eventList; } public void updateData(EventList eventList) { List ship = new ArrayList<>(); for (MyAsset asset : profileData.getAssetsList()) { if (!asset.getItem().isShip() || !asset.isSingleton()) { continue; } Loadout moduleShip = new Loadout(asset.getItem(), asset.getLocation(), asset.getOwner(), TabsLoadout.get().totalShip(), asset, TabsLoadout.get().flagTotalValue(), null, asset.getDynamicPrice(), 1, true); Loadout moduleModules = new Loadout(new Item(0), asset.getLocation(), asset.getOwner(), TabsLoadout.get().totalModules(), asset, TabsLoadout.get().flagTotalValue(), null, 0, 0, false); Loadout moduleTotal = new Loadout(new Item(0), asset.getLocation(), asset.getOwner(), TabsLoadout.get().totalAll(), asset, TabsLoadout.get().flagTotalValue(), null, asset.getDynamicPrice(), 1, false); ship.add(moduleShip); ship.add(moduleModules); ship.add(moduleTotal); Map modules = new HashMap<>(); for (MyAsset assetModule : asset.getAssets()) { Loadout module = modules.get(assetModule.getTypeID()); if (module == null //New || assetModule.getFlag().contains(Loadout.FlagType.HIGH_SLOT.getFlag()) || assetModule.getFlag().contains(Loadout.FlagType.MEDIUM_SLOT.getFlag()) || assetModule.getFlag().contains(Loadout.FlagType.LOW_SLOT.getFlag()) || assetModule.getFlag().contains(Loadout.FlagType.RIG_SLOTS.getFlag()) || assetModule.getFlag().contains(Loadout.FlagType.SUB_SYSTEMS.getFlag()) ) { module = new Loadout(assetModule.getItem(), assetModule.getLocation(), assetModule.getOwner(), assetModule.getName(), asset, assetModule.getFlag(), assetModule.getDynamicPrice(), (assetModule.getDynamicPrice() * assetModule.getCount()), assetModule.getCount(), false); modules.put(assetModule.getTypeID(), module); ship.add(module); } else { //Add count module.addCount(assetModule.getCount()); module.addValue(assetModule.getDynamicPrice() * assetModule.getCount()); } moduleModules.addValue(assetModule.getDynamicPrice() * assetModule.getCount()); moduleModules.addCount(assetModule.getCount()); moduleTotal.addValue(assetModule.getDynamicPrice() * assetModule.getCount()); moduleTotal.addCount(assetModule.getCount()); } } //Update list try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(ship); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/loadout/LoadoutExtendedTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.loadout; import java.util.Comparator; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.TabsLoadout; public enum LoadoutExtendedTableFormat implements EnumTableColumn { LOCATION(String.class) { @Override public String getColumnName() { return TabsLoadout.get().columnLocation(); } @Override public Object getColumnValue(final Loadout from) { return from.getLocation().getLocation(); } }, SLOT(String.class) { @Override public String getColumnName() { return TabsLoadout.get().columnSlot(); } @Override public Object getColumnValue(final Loadout from) { return from.getFlag(); } }, OWNER(String.class) { @Override public String getColumnName() { return TabsLoadout.get().columnOwner(); } @Override public Object getColumnValue(final Loadout from) { return from.getOwnerName(); } }, SHIP(String.class) { @Override public String getColumnName() { return TabsLoadout.get().columnShip(); } @Override public Object getColumnValue(final Loadout from) { return from.getKey(); } }; private final Class type; private final Comparator comparator; private LoadoutExtendedTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/loadout/LoadoutSeparatorComparator.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.loadout; import java.util.Comparator; public class LoadoutSeparatorComparator implements Comparator { @Override public int compare(final Loadout o1, final Loadout o2) { return o1.getSeparator().compareTo(o2.getSeparator()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/loadout/LoadoutSeparatorTableCell.java ================================================ /* Glazed Lists (c) 2003-2006 */ /* http://publicobject.com/glazedlists/ publicobject.com,*/ /* O'Dell Engineering Ltd.*/ package net.nikr.eve.jeveasset.gui.tabs.loadout; import ca.odell.glazedlists.SeparatorList; import java.awt.Color; import java.awt.Font; import javax.swing.JLabel; import javax.swing.JTable; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.shared.table.SeparatorTableCell; import net.nikr.eve.jeveasset.i18n.TabsLoadout; /** * * @author Jesse Wilson */ public class LoadoutSeparatorTableCell extends SeparatorTableCell { private final JLabel jOwner; private final JLabel jLocation; private final JLabel jFlag; public LoadoutSeparatorTableCell(final JTable jTable, final SeparatorList separatorList) { super(jTable, separatorList); jOwner = new JLabel(); Font largeFont = new Font(jOwner.getFont().getName(), Font.BOLD, jOwner.getFont().getSize() + 1); jOwner.setBorder(null); jOwner.setBackground(Color.BLACK); jOwner.setForeground(Color.WHITE); jOwner.setOpaque(true); jOwner.setFont(largeFont); jLocation = new JLabel(); jLocation.setBorder(null); jLocation.setBackground(Color.BLACK); jLocation.setForeground(Color.WHITE); jLocation.setOpaque(true); jLocation.setFont(largeFont); jFlag = new JLabel(); jFlag.setBorder(null); jFlag.setOpaque(false); jFlag.setBackground(Color.BLACK); jFlag.setFont(largeFont); layout.setHorizontalGroup( layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addGap(1) .addComponent(jOwner, 0, 0, Integer.MAX_VALUE) .addGap(1) ) .addGroup(layout.createSequentialGroup() .addGap(1) .addComponent(jLocation, 0, 0, Integer.MAX_VALUE) .addGap(1) ) .addGroup(layout.createSequentialGroup() .addComponent(jExpand) .addGap(1) .addComponent(jFlag, 0, 0, Integer.MAX_VALUE) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGap(1) .addComponent(jOwner, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jLocation, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGap(1) .addGroup(layout.createParallelGroup() .addComponent(jExpand, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFlag, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(2) ); } @Override protected void configure(final SeparatorList.Separator separator) { Loadout module = (Loadout) separator.first(); if (module == null) { // handle 'late' rendering calls after this separator is invalid return; } jLocation.setVisible(module.isFirst()); jLocation.setText(TabsLoadout.get().whitespace10(module.getLocation().getLocation())); jOwner.setVisible(module.isFirst()); jOwner.setText(TabsLoadout.get().whitespace10(module.getOwnerName())); jFlag.setText(module.getFlag()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/loadout/LoadoutTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.loadout; import java.util.Comparator; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.ModulePriceValue; import net.nikr.eve.jeveasset.i18n.TabsLoadout; /** * * @author Candle */ public enum LoadoutTableFormat implements EnumTableColumn { NAME(String.class) { @Override public String getColumnName() { return TabsLoadout.get().columnName(); } @Override public Object getColumnValue(final Loadout from) { return from.getName(); } }, VALUE(ModulePriceValue.class) { @Override public String getColumnName() { return TabsLoadout.get().columnValue(); } @Override public Object getColumnValue(final Loadout from) { return from.getModulePriceValue(); } }; private final Class type; private final Comparator comparator; private LoadoutTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/loadout/LoadoutsExportDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.loadout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.DocumentFactory; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.i18n.TabsLoadout; public class LoadoutsExportDialog extends JDialogCentered { private enum LoadoutsExportAction { OK, CANCEL } private final JTextField jName; private final JTextPane jDescription; private final JButton jOK; private final LoadoutsTab loadoutsDialog; public LoadoutsExportDialog(final Program program, final LoadoutsTab loadoutsDialog) { super(program, TabsLoadout.get().export(), Images.TOOL_SHIP_LOADOUTS.getImage()); this.loadoutsDialog = loadoutsDialog; ListenerClass listener = new ListenerClass(); JLabel jNameLabel = new JLabel(TabsLoadout.get().name()); jPanel.add(jNameLabel); jName = new JTextField(); jName.setDocument(DocumentFactory.getMaxLengthPlainDocument(40)); //max length: 40 jPanel.add(jName); JLabel jDescriptionLabel = new JLabel(TabsLoadout.get().description()); jPanel.add(jDescriptionLabel); jDescription = new JTextPane(); jDescription.setDocument(DocumentFactory.getMaxLengthStyledDocument(400)); //max length: 400 JScrollPane jDescriptionScrollPane = new JScrollPane(jDescription); jPanel.add(jDescriptionScrollPane); jOK = new JButton(TabsLoadout.get().oK()); jOK.setActionCommand(LoadoutsExportAction.OK.name()); jOK.addActionListener(listener); jPanel.add(jOK); JButton jCancel = new JButton(TabsLoadout.get().cancel()); jCancel.setActionCommand(LoadoutsExportAction.CANCEL.name()); jCancel.addActionListener(listener); jPanel.add(jCancel); layout.setHorizontalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jNameLabel) .addComponent(jName, 373, 373, 373) .addComponent(jDescriptionLabel) .addComponent(jDescriptionScrollPane, 373, 373, 373) ) .addGroup(layout.createSequentialGroup() .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jNameLabel) .addComponent(jName, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDescriptionLabel) .addComponent(jDescriptionScrollPane, 110, 110, 110) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } public String getFittingName() { return jName.getText(); } public String getFittingDescription() { String text = jDescription.getText(); text = text.replace("\r\n", "<br>"); text = text.replace("\r", "<br>"); text = text.replace("\n", "<br>"); return text; } @Override protected JComponent getDefaultFocus() { return jName; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { } @Override protected void save() { loadoutsDialog.exportXml(); } @Override public void setVisible(final boolean b) { if (b) { jName.setText(""); jDescription.setText(""); } super.setVisible(b); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (LoadoutsExportAction.OK.name().equals(e.getActionCommand())) { save(); } if (LoadoutsExportAction.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/loadout/LoadoutsTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.loadout; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.JOptionInput; import net.nikr.eve.jeveasset.gui.shared.components.JCustomFileChooser; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog; import net.nikr.eve.jeveasset.gui.shared.components.ListComboBoxModel; import net.nikr.eve.jeveasset.gui.shared.filter.ExportDialog; import net.nikr.eve.jeveasset.gui.shared.filter.SimpleFilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JSeparatorTable; import net.nikr.eve.jeveasset.gui.shared.table.PaddingTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.gui.tabs.loadout.Loadout.LoadoutMatcher; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.i18n.TabsLoadout; import net.nikr.eve.jeveasset.io.local.EveFittingWriter; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LoadoutsTab extends JMainTabSecondary { private static final Logger LOG = LoggerFactory.getLogger(LoadoutsTab.class); private enum LoadoutsAction { FILTER, OWNERS, EXPORT, EXPORT_EVE_SELECTED, EXPORT_EVE_ALL, EXPORT_EFT, COLLAPSE, EXPAND } //GUI private final JComboBox jOwners; private final JComboBox jShips; private final JButton jExpand; private final JButton jCollapse; private final JSeparatorTable jTable; private final JDropDownButton jExport; private final LoadoutsExportDialog loadoutsExportDialog; private final JCustomFileChooser jXmlFileChooser; private final JTextDialog jEftDialog; //Table private final EventList eventList; private final FilterList filterList; private final SeparatorList separatorList; private final DefaultEventSelectionModel selectionModel; private final DefaultEventTableModel tableModel; private final EnumTableFormatAdaptor tableFormat; //Dialog private final ExportDialog exportDialog; private final LoadoutData loadoutData; public static final String NAME = "loadouts"; //Not to be changed! public LoadoutsTab(final Program program) { super(program, NAME, TabsLoadout.get().ship(), Images.TOOL_SHIP_LOADOUTS.getIcon(), true); loadoutData = new LoadoutData(program); loadoutsExportDialog = new LoadoutsExportDialog(program, this); ListenerClass listener = new ListenerClass(); jXmlFileChooser = new JCustomFileChooser("xml"); jEftDialog = new JTextDialog(program.getMainWindow().getFrame()); JFixedToolBar jToolBarTop = new JFixedToolBar(); JLabel jOwnersLabel = new JLabel(TabsLoadout.get().owner()); jToolBarTop.add(jOwnersLabel); jToolBarTop.addSpace(5); jOwners = new JComboBox<>(); jOwners.setActionCommand(LoadoutsAction.OWNERS.name()); jOwners.addActionListener(listener); jToolBarTop.addComboBox(jOwners, 200); jToolBarTop.addSpace(15); JLabel jShipsLabel = new JLabel(TabsLoadout.get().ship1()); jToolBarTop.add(jShipsLabel); jToolBarTop.addSpace(5); jShips = new JComboBox<>(); jShips.setActionCommand(LoadoutsAction.FILTER.name()); jShips.addActionListener(listener); jToolBarTop.addComboBox(jShips, 0); JFixedToolBar jToolBarBottom = new JFixedToolBar(); jExport = new JDropDownButton(GuiShared.get().export(), Images.DIALOG_CSV_EXPORT.getIcon()); jToolBarBottom.addButton(jExport); JMenuItem jExportSqlCsvHtml = new JMenuItem(TabsLoadout.get().exportTableData(), Images.DIALOG_CSV_EXPORT.getIcon()); jExportSqlCsvHtml.setActionCommand(LoadoutsAction.EXPORT.name()); jExportSqlCsvHtml.addActionListener(listener); jExport.add(jExportSqlCsvHtml); JMenu jMenu = new JMenu(TabsLoadout.get().exportEveXml()); jMenu.setIcon(Images.MISC_EVE.getIcon()); jExport.add(jMenu); JMenuItem jExportEveXml = new JMenuItem(TabsLoadout.get().exportEveXmlSelected()); jExportEveXml.setActionCommand(LoadoutsAction.EXPORT_EVE_SELECTED.name()); jExportEveXml.addActionListener(listener); jMenu.add(jExportEveXml); JMenuItem jExportEveXmlAll = new JMenuItem(TabsLoadout.get().exportEveXmlAll()); jExportEveXmlAll.setActionCommand(LoadoutsAction.EXPORT_EVE_ALL.name()); jExportEveXmlAll.addActionListener(listener); jMenu.add(jExportEveXmlAll); JMenuItem jExportEft = new JMenuItem(TabsLoadout.get().exportEft()); jExportEft.setActionCommand(LoadoutsAction.EXPORT_EFT.name()); jExportEft.addActionListener(listener); jExportEft.setIcon(Images.TOOL_SHIP_LOADOUTS.getIcon()); jExport.add(jExportEft); jToolBarBottom.addGlue(); jCollapse = new JButton(TabsLoadout.get().collapse(), Images.MISC_COLLAPSED.getIcon()); jCollapse.setActionCommand(LoadoutsAction.COLLAPSE.name()); jCollapse.addActionListener(listener); jToolBarBottom.addButton(jCollapse); jExpand = new JButton(TabsLoadout.get().expand(), Images.MISC_EXPANDED.getIcon()); jExpand.setActionCommand(LoadoutsAction.EXPAND.name()); jExpand.addActionListener(listener); jToolBarBottom.addButton(jExpand); //Table Format tableFormat = TableFormatFactory.loadoutTableFormat(); //Backend eventList = EventListManager.create(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Separator separatorList = new SeparatorList<>(filterList, new LoadoutSeparatorComparator(), 1, Integer.MAX_VALUE); //Table Model tableModel = EventModels.createTableModel(separatorList, tableFormat); //Table jTable = new JSeparatorTable(program, tableModel, separatorList); jTable.setSeparatorRenderer(new LoadoutSeparatorTableCell(jTable, separatorList)); jTable.setSeparatorEditor(new LoadoutSeparatorTableCell(jTable, separatorList)); PaddingTableCellRenderer.install(jTable, 3); //Selection Model selectionModel = EventModels.createSelectionModel(separatorList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Menu installTableTool(new LoadoutTableMenu(), tableFormat, null, tableModel, jTable, eventList, Loadout.class); exportDialog = new ExportDialog<>(program.getMainWindow().getFrame(), NAME, null, new LoadoutsFilterControl(), tableFormat, filterList); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jToolBarTop, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jToolBarBottom, jToolBarBottom.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jToolBarTop, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jToolBarBottom, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void updateData() { if (!program.getOwnerNames(false).isEmpty()) { jOwners.setEnabled(true); String selectedItem = (String) jOwners.getSelectedItem(); jOwners.setModel(new ListComboBoxModel<>(program.getOwnerNames(true))); if (selectedItem != null && program.getOwnerNames(true).contains(selectedItem)) { jOwners.setSelectedItem(selectedItem); } else { jOwners.setSelectedIndex(0); } } else { jOwners.setEnabled(false); jOwners.setModel(new ListComboBoxModel<>()); jOwners.getModel().setSelectedItem(TabsLoadout.get().no()); jShips.setModel(new ListComboBoxModel<>()); jShips.getModel().setSelectedItem(TabsLoadout.get().no()); } updateTable(); } @Override public void clearData() { try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } @Override public void updateCache() { } @Override public Collection getLocations() { try { eventList.getReadWriteLock().readLock().lock(); return new ArrayList<>(eventList); } finally { eventList.getReadWriteLock().readLock().unlock(); } } public void selectShip(MyAsset asset) { String owner = (String) jOwners.getSelectedItem(); //Select the owner (if all is not selected) if (!owner.equals(General.get().all())) { jOwners.setSelectedItem(asset.getOwnerName()); } //Select Ship String selecctedShip = asset.getName() + " #" + asset.getItemID(); jShips.setSelectedItem(selecctedShip); } private String browse() { File windows = new File(javax.swing.filechooser.FileSystemView.getFileSystemView().getDefaultDirectory() + File.separator + "EVE" + File.separator + "fittings" ); File mac = new File(System.getProperty("user.home", ".") + File.separator + "Library" + File.separator + "Preferences" + File.separator + "EVE Online Preferences" + File.separator + "p_drive" + File.separator + "My Documents" + File.separator + "EVE" + File.separator + "fittings" ); LOG.info("Mac Browsing: {}", mac.getAbsolutePath()); if (windows.exists()) { //Windows jXmlFileChooser.setCurrentDirectory(windows); } else if (mac.exists()) { //Mac //PENDING TEST if fittings path is set correct on mac // should open: ~library/preferences/eve online preferences/p_drive/my documents/eve/overview jXmlFileChooser.setCurrentDirectory(mac); } else { //Others: use program directory is there is only Win & Mac clients jXmlFileChooser.setCurrentDirectory(new File(FileUtil.getUserDirectory())); } int bFound = jXmlFileChooser.showSaveDialog(program.getMainWindow().getFrame()); if (bFound == JCustomFileChooser.APPROVE_OPTION) { File file = jXmlFileChooser.getSelectedFile(); return file.getAbsolutePath(); } else { return null; } } public void exportXml() { String fitName = loadoutsExportDialog.getFittingName(); String fitDescription = loadoutsExportDialog.getFittingDescription(); if (!fitName.isEmpty()) { String selectedShip = (String) jShips.getSelectedItem(); MyAsset exportAsset = null; for (MyAsset asset : program.getAssetsList()) { String key = asset.getName() + " #" + asset.getItemID(); if (selectedShip.equals(key)) { exportAsset = asset; break; } } loadoutsExportDialog.setVisible(false); if (exportAsset == null) { return; } String filename = browse(); if (filename != null) { EveFittingWriter.save(Collections.singletonList(exportAsset), filename, fitName, fitDescription); } } else { JOptionPane.showMessageDialog(loadoutsExportDialog.getDialog(), TabsLoadout.get().name1(), TabsLoadout.get().empty(), JOptionPane.PLAIN_MESSAGE); } } private void exportEFT() { String selectedShip = (String) jShips.getSelectedItem(); MyAsset exportAsset = null; for (MyAsset asset : program.getAssetsList()) { String key = asset.getName() + " #" + asset.getItemID(); if (selectedShip.equals(key)) { exportAsset = asset; break; } } if (exportAsset == null) { return; } String buildName = getBuildName(exportAsset.getName()); if (buildName == null) { return; //Cancel } Map droneBay = new HashMap<>(); Map cargo = new HashMap<>(); Map> modulesByFlag = new HashMap<>(); for (MyAsset asset : exportAsset.getAssets()) { if (asset.getFlag().equals("DroneBay")) { Long count = droneBay.get(asset.getTypeName()); if (count == null) { count = 0L; } droneBay.put(asset.getTypeName(), count + asset.getCount()); } else if (asset.getFlag().equals("Cargo")) { Long count = cargo.get(asset.getTypeName()); if (count == null) { count = 0L; } cargo.put(asset.getTypeName(), count + asset.getCount()); } else if (asset.getItem().getCategory().equals("Charge")){ Long count = cargo.get(asset.getTypeName()); if (count == null) { count = 0L; } cargo.put(asset.getTypeName(), count + asset.getCount()); } else { String flag = asset.getFlag().replaceAll("\\d", ""); int index; try { index = Integer.valueOf(asset.getFlag().replaceAll("\\D", "")); } catch (NumberFormatException ex) { continue; } Map modules = modulesByFlag.get(flag); if (modules == null) { modules = new HashMap<>(); modulesByFlag.put(flag, modules); } if (asset.getCount() > 1) { modules.put(index, asset.getTypeName() + " x" + asset.getCount() + "\r\n"); } else { modules.put(index, asset.getTypeName() + "\r\n"); } } } StringBuilder builder = new StringBuilder(); //Type and Name builder.append("["); builder.append(exportAsset.getTypeName()); builder.append(", "); builder.append(buildName); builder.append("]\r\n"); writeModuls(builder, modulesByFlag.get("LoSlot")); writeModuls(builder, modulesByFlag.get("MedSlot")); writeModuls(builder, modulesByFlag.get("HiSlot")); writeModuls(builder, modulesByFlag.get("RigSlot")); writeModuls(builder, modulesByFlag.get("SubSystem")); writeCount(builder, droneBay); writeCount(builder, cargo); jEftDialog.exportText(builder.toString()); } private void writeModuls(StringBuilder builder, Map modules) { if (modules == null || modules.isEmpty()) { return; } builder.append("\r\n"); for (String module : modules.values()) { builder.append(module); } } private void writeCount(StringBuilder builder, Map modules) { if (modules == null || modules.isEmpty()) { return; } builder.append("\r\n"); for (Map.Entry entry : modules.entrySet()) { if (entry.getValue() > 1) { builder.append(entry.getKey()); builder.append(" x"); builder.append(entry.getValue()); builder.append("\r\n"); } else { builder.append(entry.getKey()); builder.append("\r\n"); } } } private String getBuildName(String shipName) { String defaultName = shipName.replaceFirst("\\s*\\([^)]*\\)\\s*$", ""); String buildName = (String) JOptionInput.showInputDialog(program.getMainWindow().getFrame(), "Enter Build Name", "Export EFT", JOptionPane.PLAIN_MESSAGE, null, null, defaultName); if (buildName == null) { return null; //Cancel } else if (buildName.isEmpty()) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsLoadout.get().name1(), TabsLoadout.get().empty(), JOptionPane.PLAIN_MESSAGE); return getBuildName(defaultName); } else { return buildName; } } private void updateTable() { //Save separator expanded/collapsed state jTable.saveExpandedState(); //Update Data loadoutData.updateData(eventList); //Restore separator expanded/collapsed state jTable.loadExpandedState(); } private class LoadoutTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return null; } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME, false); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { JMenuInfo.module(jPopupMenu, selectionModel.getSelected()); } @Override public void addToolMenu(JComponent jComponent) { } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (LoadoutsAction.OWNERS.name().equals(e.getActionCommand())) { String owner = (String) jOwners.getSelectedItem(); List charShips = new ArrayList<>(); for (MyAsset asset : program.getAssetsList()) { String key = asset.getName() + " #" + asset.getItemID(); if (!asset.getItem().isShip() || !asset.isSingleton()) { continue; } if (!owner.equals(asset.getOwnerName()) && !owner.equals(General.get().all())) { continue; } charShips.add(key); } if (!charShips.isEmpty()) { Collections.sort(charShips, StringComparators.CASE_INSENSITIVE); jExpand.setEnabled(true); jCollapse.setEnabled(true); jExport.setEnabled(true); jOwners.setEnabled(true); jShips.setEnabled(true); String selectedItem = (String) jShips.getSelectedItem(); jShips.setModel(new ListComboBoxModel<>(charShips)); if (selectedItem != null && charShips.contains(selectedItem)) { jShips.setSelectedItem(selectedItem); } else { jShips.setSelectedIndex(0); } } else { jExpand.setEnabled(false); jCollapse.setEnabled(false); jExport.setEnabled(false); jShips.setEnabled(false); jShips.setModel(new ListComboBoxModel<>()); jShips.getModel().setSelectedItem(TabsLoadout.get().no1()); } } else if (LoadoutsAction.FILTER.name().equals(e.getActionCommand())) { String selectedShip = (String) jShips.getSelectedItem(); filterList.setMatcher(new LoadoutMatcher(selectedShip)); } else if (LoadoutsAction.COLLAPSE.name().equals(e.getActionCommand())) { jTable.expandSeparators(false); } else if (LoadoutsAction.EXPAND.name().equals(e.getActionCommand())) { jTable.expandSeparators(true); } else if (LoadoutsAction.EXPORT_EVE_SELECTED.name().equals(e.getActionCommand())) { loadoutsExportDialog.setVisible(true); } else if (LoadoutsAction.EXPORT_EVE_ALL.name().equals(e.getActionCommand())) { String filename = browse(); List ships = new ArrayList<>(); for (MyAsset asset : program.getAssetsList()) { if (!asset.getItem().isShip() || !asset.isSingleton() || asset.getAssets().isEmpty()) { continue; } ships.add(asset); } if (filename != null) { EveFittingWriter.save(new ArrayList<>(ships), filename); } } else if (LoadoutsAction.EXPORT_EFT.name().equals(e.getActionCommand())) { exportEFT(); } else if (LoadoutsAction.EXPORT.name().equals(e.getActionCommand())) { exportDialog.setVisible(true); } } } private class LoadoutsFilterControl implements SimpleFilterControl { @Override public void saveSettings(final String msg) { program.saveSettings("Ship Loudouts Table: " + msg); //Save Ship Loudout Export Settings (Filters not used) } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/loyalty/LoyaltyPointsTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.loyalty; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.data.settings.tag.TagUpdate; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabPrimary; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.PaddingTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.TabsLoyaltyPoints; public class LoyaltyPointsTab extends JMainTabPrimary implements TagUpdate { //GUI private final JAutoColumnTable jTable; //Table private final LoyaltyPointsFilterControl filterControl; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventTableModel tableModel; private final EventList eventList; private final FilterList filterList; private final DefaultEventSelectionModel selectionModel; public static final String NAME = "loyaltypoints"; //Not to be changed! public LoyaltyPointsTab(final Program program) { super(program, NAME, TabsLoyaltyPoints.get().loyaltyPoints(), Images.TOOL_LOYALTY_POINTS.getIcon(), true); layout.setAutoCreateGaps(true); //Table Format tableFormat = TableFormatFactory.loyaltyPointsTableFormat(); //Backend eventList = program.getProfileData().getLoyaltyPointsEventList(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedList); eventList.getReadWriteLock().readLock().unlock(); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JAutoColumnTable(program, tableModel); jTable.setCellSelectionEnabled(true); jTable.setRowSelectionAllowed(true); jTable.setColumnSelectionAllowed(true); jTable.setRowHeight(MyLoyaltyPoints.IMAGE_SIZE.getSize()); PaddingTableCellRenderer.install(jTable, 0, 5, 0, 5); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new LoyaltyPointsFilterControl(sortedList); //Menu installTableTool(new LoyaltyPointsTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, MyLoyaltyPoints.class); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void updateTags() { beforeUpdateData(); tableModel.fireTableDataChanged(); filterControl.refilter(); afterUpdateData(); } @Override public void clearData() { } @Override public void updateCache() { filterControl.createCache(); } @Override public Collection getLocations() { return new ArrayList<>(); //LocationsType } public boolean isFiltersEmpty() { return filterControl.isFiltersEmpty(); } public void addFilters(final List filters) { filterControl.addFilters(filters); } public void clearFilters() { filterControl.clearCurrentFilters(); } public String getCurrentFilterName() { return filterControl.getCurrentFilterName(); } private class LoyaltyPointsTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { } @Override public void addToolMenu(JComponent jComponent) { } } private class LoyaltyPointsFilterControl extends FilterControl { public LoyaltyPointsFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("Loyalty Points Table: " + msg); //Save Loyalty Points Filters and Export Settings } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/loyalty/LoyaltyPointsTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.loyalty; import java.util.Comparator; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.TextIcon; import net.nikr.eve.jeveasset.i18n.TabsLoyaltyPoints; public enum LoyaltyPointsTableFormat implements EnumTableColumn { OWNER(String.class) { @Override public String getColumnName() { return TabsLoyaltyPoints.get().columnOwner(); } @Override public Object getColumnValue(final MyLoyaltyPoints from) { return from.getOwnerName(); } }, CORPORATION_NAME(TextIcon.class) { @Override public String getColumnName() { return TabsLoyaltyPoints.get().columnCorporationName(); } @Override public Object getColumnValue(final MyLoyaltyPoints from) { return from.getTextIcon(); } }, LOYALTY_POINTS(Long.class) { @Override public String getColumnName() { return TabsLoyaltyPoints.get().columnLoyaltyPoints(); } @Override public Object getColumnValue(final MyLoyaltyPoints from) { return from.getLoyaltyPoints(); } }; private final Class type; private final Comparator comparator; private LoyaltyPointsTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/loyalty/TotalLoyaltyPoints.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.loyalty; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.i18n.TabsLoyaltyPoints; public class TotalLoyaltyPoints extends MyLoyaltyPoints { private int totalLoyaltyPoints = 0; public TotalLoyaltyPoints(MyLoyaltyPoints rawLoyaltyPoints) { super(rawLoyaltyPoints, null); setCorporationName(rawLoyaltyPoints.getCorporationName()); } @Override public String getOwnerName() { return TabsLoyaltyPoints.get().total(); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody } @Override public Integer getLoyaltyPoints() { return totalLoyaltyPoints; } public void add(MyLoyaltyPoints loyaltyPoints) { totalLoyaltyPoints += loyaltyPoints.getLoyaltyPoints(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/materials/Material.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.materials; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.data.settings.types.PriceType; import net.nikr.eve.jeveasset.gui.shared.CopyHandler.CopySeparator; import net.nikr.eve.jeveasset.gui.shared.Formatter; public class Material implements Comparable, LocationType, ItemType, PriceType, CopySeparator { public enum MaterialType { LOCATIONS(2, 1, 1), LOCATIONS_TOTAL(2, 2, 1), LOCATIONS_ALL(2, 2, 2), SUMMARY(1, 1, 1), SUMMARY_TOTAL(1, 2, 1), SUMMARY_ALL(1, 2, 2); private final int headerOrder; private final int goupeOrder; private final int nameOrder; private MaterialType(final int headerOrder, final int goupeOrder, final int nameOrder) { this.headerOrder = headerOrder; this.goupeOrder = goupeOrder; this.nameOrder = nameOrder; } public int getHeaderOrder() { return headerOrder; } public int getGoupeOrder() { return goupeOrder; } public int getNameOrder() { return nameOrder; } } private final String header; private final String group; private final String name; private final MyLocation location; //New objects are created by updateData() - no need to update private final Item item; private final Integer typeID; private double value = 0; private long count = 0; private boolean first = false; private final Double price; private final MaterialType type; public Material(final MaterialType type, final MyAsset asset, final String header, final String group, final String name) { this.type = type; this.header = header; this.group = group; this.name = name; if (asset != null) { //Has item if (type == MaterialType.LOCATIONS || type == MaterialType.SUMMARY) { this.item = asset.getItem(); this.typeID = asset.getTypeID(); this.price = asset.getDynamicPrice(); } else { this.item = new Item(0); this.price = null; this.typeID = null; } //Has location if (type == MaterialType.LOCATIONS || type == MaterialType.LOCATIONS_TOTAL || type == MaterialType.LOCATIONS_ALL) { location = asset.getLocation(); } else { location = MyLocation.create(0); } } else { location = MyLocation.create(0); this.item = new Item(0); this.price = null; this.typeID = null; } } public void updateValue(final long updateCount, final double updatePrice) { this.count = this.count + updateCount; this.value = this.value + (updateCount * updatePrice); } public long getCount() { return count; } public String getHeader() { return header; } @Override public Item getItem() { return item; } @Override public long getItemCount() { return getCount(); } @Override public MyLocation getLocation() { return location; } public Integer getTypeID() { return typeID; } public String getGroup() { return group; } public String getName() { return name; } public MaterialType getType() { return type; } public boolean isFirst() { return first; } public void first() { first = true; } @Override public Double getDynamicPrice() { return price; } public double getValue() { return Formatter.round(value, 2); } public String getSeparator() { return type.getHeaderOrder() + header + type.getGoupeOrder() + group; } protected String getCompare() { return type.getHeaderOrder() + header + type.getGoupeOrder() + group + type.getNameOrder() + name; } @Override public String getCopyString() { StringBuilder builder = new StringBuilder(); builder.append(getHeader()); builder.append("\t"); builder.append(getGroup()); return builder.toString(); } @Override public boolean equals(final Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Material other = (Material) obj; if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { return false; } if ((this.header == null) ? (other.header != null) : !this.header.equals(other.header)) { return false; } if ((this.group == null) ? (other.group != null) : !this.group.equals(other.group)) { return false; } return true; } @Override public int hashCode() { int hash = 3; hash = 29 * hash + (this.name != null ? this.name.hashCode() : 0); hash = 29 * hash + (this.header != null ? this.header.hashCode() : 0); hash = 29 * hash + (this.group != null ? this.group.hashCode() : 0); return hash; } @Override public int compareTo(final Material o) { return this.getCompare().compareToIgnoreCase(o.getCompare()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/materials/MaterialExtendedTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.materials; import java.util.Comparator; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.TabsMaterials; public enum MaterialExtendedTableFormat implements EnumTableColumn { LOCATION(String.class) { @Override public String getColumnName() { return TabsMaterials.get().columnLocation(); } @Override public Object getColumnValue(final Material from) { return from.getHeader(); } }, GROUP(String.class) { @Override public String getColumnName() { return TabsMaterials.get().columnGroup(); } @Override public Object getColumnValue(final Material from) { return from.getGroup(); } }; private final Class type; private final Comparator comparator; private MaterialExtendedTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/materials/MaterialSeparatorComparator.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.materials; import java.util.Comparator; public class MaterialSeparatorComparator implements Comparator { @Override public int compare(final Material o1, final Material o2) { return o1.getSeparator().compareTo(o2.getSeparator()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/materials/MaterialTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.materials; import java.util.Comparator; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.ISK; import net.nikr.eve.jeveasset.i18n.TabsMaterials; public enum MaterialTableFormat implements EnumTableColumn { NAME(String.class) { @Override public String getColumnName() { return TabsMaterials.get().columnName(); } @Override public Object getColumnValue(final Material from) { return from.getName(); } }, COUNT(Long.class) { @Override public String getColumnName() { return TabsMaterials.get().columnCount(); } @Override public Object getColumnValue(final Material from) { return from.getCount(); } }, PRICE(ISK.class) { @Override public String getColumnName() { return TabsMaterials.get().columnPrice(); } @Override public Object getColumnValue(final Material from) { if (from.getDynamicPrice() != null) { return new ISK(Formatter.iskFormat(from.getDynamicPrice()), from.getDynamicPrice()); } else { return new ISK("(" + Formatter.iskFormat(from.getValue() / from.getCount()) + ")", from.getValue() / from.getCount()); } } }, VALUE(ISK.class) { @Override public String getColumnName() { return TabsMaterials.get().columnValue(); } @Override public Object getColumnValue(final Material from) { return new ISK(Formatter.iskFormat(from.getValue()), from.getValue()); } }, TYPE_ID(Integer.class) { @Override public String getColumnName() { return TabsMaterials.get().columnTypeID(); } @Override public Object getColumnValue(final Material from) { return from.getTypeID(); } @Override public boolean isShowDefault() { return false; } }; private final Class type; private final Comparator comparator; private MaterialTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/materials/MaterialsData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.materials; import ca.odell.glazedlists.EventList; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.profile.TableData; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.i18n.TabsMaterials; public class MaterialsData extends TableData { public MaterialsData(Program program) { super(program); } public MaterialsData(ProfileManager profileManager, ProfileData profileData) { super(profileManager, profileData); } public EventList getData(String owner, boolean ore, boolean pi, boolean commodity) { Set groups = new HashSet<>(); for (Item item : StaticData.get().getItems().values()) { if (item.getCategory().equals(Item.CATEGORY_MATERIAL)) { groups.add(item.getGroup()); } if (commodity && item.getCategory().equals(Item.CATEGORY_COMMODITY)) { groups.add(item.getGroup()); } if (pi && item.isPiMaterial()) { groups.add(item.getGroup()); } if (ore && item.isMined()) { groups.add(item.getGroup()); } } return getData(owner, groups); } public EventList getData(String owner, Set groups) { EventList eventList = EventListManager.create(); updateData(eventList, owner, groups); return eventList; } protected boolean updateData(EventList eventList, String owner, Set groups) { if (owner == null || owner.isEmpty()) { owner = General.get().all(); } boolean includeAll = owner.equals(General.get().all()); List materials = new ArrayList<>(); Map uniqueMaterials = new HashMap<>(); Map totalMaterials = new HashMap<>(); Map totalAllMaterials = new HashMap<>(); Map summary = new HashMap<>(); Map total = new HashMap<>(); //Summary Total All Material summaryTotalAllMaterial = new Material(Material.MaterialType.SUMMARY_ALL, null, TabsMaterials.get().summary(), TabsMaterials.get().grandTotal(), General.get().all()); for (MyAsset asset : profileData.getAssetsList()) { //Skip if (!groups.contains(asset.getItem().getGroup())) { continue; } //Skip not selected owners if (!owner.equals(asset.getOwnerName()) && !includeAll) { continue; } //Locations Material material = uniqueMaterials.get(asset.getLocation().getLocation() + asset.getName()); if (material == null) { //New material = new Material(Material.MaterialType.LOCATIONS, asset, asset.getLocation().getLocation(), asset.getItem().getGroup(), asset.getName()); uniqueMaterials.put(asset.getLocation().getLocation() + asset.getName(), material); materials.add(material); } //Locations Total Material totalMaterial = totalMaterials.get(asset.getLocation().getLocation() + asset.getItem().getGroup()); if (totalMaterial == null) { //New totalMaterial = new Material(Material.MaterialType.LOCATIONS_TOTAL, asset, asset.getLocation().getLocation(), TabsMaterials.get().total(), asset.getItem().getGroup()); totalMaterials.put(asset.getLocation().getLocation() + asset.getItem().getGroup(), totalMaterial); materials.add(totalMaterial); } //Locations Total All Material totalAllMaterial = totalAllMaterials.get(asset.getLocation().getLocation()); if (totalAllMaterial == null) { //New totalAllMaterial = new Material(Material.MaterialType.LOCATIONS_ALL, asset, asset.getLocation().getLocation(), TabsMaterials.get().total(), General.get().all()); totalAllMaterials.put(asset.getLocation().getLocation(), totalAllMaterial); materials.add(totalAllMaterial); } //Summary Material summaryMaterial = summary.get(asset.getName()); if (summaryMaterial == null) { //New summaryMaterial = new Material(Material.MaterialType.SUMMARY, asset, TabsMaterials.get().summary(), asset.getItem().getGroup(), asset.getName()); summary.put(asset.getName(), summaryMaterial); materials.add(summaryMaterial); } //Summary Total Material summaryTotalMaterial = total.get(asset.getItem().getGroup()); if (summaryTotalMaterial == null) { //New summaryTotalMaterial = new Material(Material.MaterialType.SUMMARY_TOTAL, null, TabsMaterials.get().summary(), TabsMaterials.get().grandTotal(), asset.getItem().getGroup()); total.put(asset.getItem().getGroup(), summaryTotalMaterial); materials.add(summaryTotalMaterial); } //Update values material.updateValue(asset.getCount(), asset.getDynamicPrice()); totalMaterial.updateValue(asset.getCount(), asset.getDynamicPrice()); totalAllMaterial.updateValue(asset.getCount(), asset.getDynamicPrice()); summaryMaterial.updateValue(asset.getCount(), asset.getDynamicPrice()); summaryTotalMaterial.updateValue(asset.getCount(), asset.getDynamicPrice()); summaryTotalAllMaterial.updateValue(asset.getCount(), asset.getDynamicPrice()); } if (!materials.isEmpty()) { materials.add(summaryTotalAllMaterial); } Collections.sort(materials); String location = ""; for (Material material : materials) { if (!location.equals(material.getHeader())) { material.first(); location = material.getHeader(); } } //Update list try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(materials); } finally { eventList.getReadWriteLock().writeLock().unlock(); } return materials.isEmpty(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/materials/MaterialsSeparatorTableCell.java ================================================ /* Glazed Lists (c) 2003-2006 */ /* http://publicobject.com/glazedlists/ publicobject.com,*/ /* O'Dell Engineering Ltd.*/ package net.nikr.eve.jeveasset.gui.tabs.materials; import ca.odell.glazedlists.SeparatorList; import java.awt.Color; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTable; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.table.SeparatorTableCell; /** * * @author Jesse Wilson */ public class MaterialsSeparatorTableCell extends SeparatorTableCell { private final JLabel jLocation; private final JLabel jGroup; private final JButton jExpandLocation; private final JPanel jLocationPanel; public MaterialsSeparatorTableCell(final JTable jTable, final SeparatorList separatorList) { super(jTable, separatorList); jLocationPanel = new JPanel(); jLocationPanel.setBackground(Color.BLACK); GroupLayout locationLayout = new GroupLayout(jLocationPanel); jLocationPanel.setLayout(locationLayout); locationLayout.setAutoCreateGaps(false); locationLayout.setAutoCreateContainerGaps(false); jLocation = new JLabel(); jLocation.setBorder(null); jLocation.setForeground(Color.WHITE); Font font = jLocation.getFont(); jLocation.setFont(new Font(font.getName(), Font.BOLD, font.getSize() + 1)); jLocation.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(final MouseEvent e) { if (e.getClickCount() >= 2) { expandHeader(); } } }); jGroup = new JLabel(); jGroup.setFont(new Font(font.getName(), Font.BOLD, font.getSize() + 1)); jExpandLocation = new JButton(Images.MISC_COLLAPSED_WHITE.getIcon()); jExpandLocation.setOpaque(true); jExpandLocation.setContentAreaFilled(false); jExpandLocation.setBorder(EMPTY_TWO_PIXEL_BORDER); jExpandLocation.setBackground(Color.BLACK); jExpandLocation.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { expandHeader(); } }); locationLayout.setHorizontalGroup( locationLayout.createParallelGroup() .addGroup(locationLayout.createSequentialGroup() .addComponent(jExpandLocation) .addComponent(jLocation, 0, 0, Integer.MAX_VALUE) ) ); locationLayout.setVerticalGroup( locationLayout.createSequentialGroup() .addGroup(locationLayout.createParallelGroup() .addComponent(jExpandLocation, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jLocation, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(jLocationPanel) .addGroup(layout.createSequentialGroup() .addComponent(jExpand) .addGap(1) .addComponent(jGroup, 0, 0, Integer.MAX_VALUE) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jLocationPanel) .addGroup(layout.createParallelGroup() .addComponent(jExpand, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jGroup, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(2) ); } @Override protected void configure(final SeparatorList.Separator separator) { Material material = (Material) separator.first(); if (material == null) { return; } // handle 'late' rendering calls after this separator is invalid jLocationPanel.setVisible(material.isFirst()); jLocation.setText(material.getHeader()); jGroup.setText(material.getGroup()); if (material.isFirst()) { jExpandLocation.setIcon(isHeaderCollapsed() ? Images.MISC_EXPANDED_WHITE.getIcon() : Images.MISC_COLLAPSED_WHITE.getIcon()); } } private void expandHeader() { Material material = (Material) currentSeparator.first(); boolean expand = isHeaderCollapsed(); try { separatorList.getReadWriteLock().readLock().lock(); for (int i = 0; i < separatorList.size(); i++) { Object object = separatorList.get(i); if (object instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) object; Material currentMaterial = (Material) separator.first(); if (currentMaterial.getHeader().equals(material.getHeader())) { try { separatorList.getReadWriteLock().readLock().unlock(); separatorList.getReadWriteLock().writeLock().lock(); separator.setLimit(expand ? Integer.MAX_VALUE : 0); } finally { separatorList.getReadWriteLock().writeLock().unlock(); separatorList.getReadWriteLock().readLock().lock(); } } } } } finally { separatorList.getReadWriteLock().readLock().unlock(); } } private boolean isHeaderCollapsed() { Material material = (Material) currentSeparator.first(); try { separatorList.getReadWriteLock().readLock().lock(); int start; if (material.isFirst()) { start = currentRow; } else { start = 0; } boolean found = false; for (int i = start; i < separatorList.size(); i++) { Object object = separatorList.get(i); if (object instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) object; Material currentMaterial = (Material) separator.first(); if (currentMaterial.getHeader().equals(material.getHeader())) { if (separator.getLimit() != 0) { return false; } found = true; } else if (found) { break; //No longer the same header... } } } } finally { separatorList.getReadWriteLock().readLock().unlock(); } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/materials/MaterialsTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.materials; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.components.ListComboBoxModel; import net.nikr.eve.jeveasset.gui.shared.filter.ExportDialog; import net.nikr.eve.jeveasset.gui.shared.filter.SimpleFilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JSeparatorTable; import net.nikr.eve.jeveasset.gui.shared.table.PaddingTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.i18n.TabsMaterials; public class MaterialsTab extends JMainTabSecondary { private enum MaterialsAction { SELECTED, COLLAPSE, EXPAND, EXPORT } //GUI private final JComboBox jOwners; private final JButton jExport; private final JButton jExpand; private final JButton jCollapse; private final JDropDownButton jMaterial; private final JCheckBoxMenuItem jMaterialAll; private final JDropDownButton jPi; private final JCheckBoxMenuItem jPiAll; private final JDropDownButton jOre; private final JCheckBoxMenuItem jOreAll; private final JDropDownButton jCommodity; private final JCheckBoxMenuItem jCommodityAll; private final List jMaterialGroups = new ArrayList<>(); private final List jPiGroups = new ArrayList<>(); private final List jOreGroups = new ArrayList<>(); private final List jCommodityGroups = new ArrayList<>(); private final JSeparatorTable jTable; private final JScrollPane jTableScroll; //Table private final EventList eventList; private final SeparatorList separatorList; private final DefaultEventSelectionModel selectionModel; private final DefaultEventTableModel tableModel; private final EnumTableFormatAdaptor tableFormat; //Dialog private final ExportDialog exportDialog; //Data private final MaterialsData materialsData; public static final String NAME = "materials"; //Not to be changed! public MaterialsTab(final Program program) { super(program, NAME, TabsMaterials.get().materials(), Images.TOOL_MATERIALS.getIcon(), true); materialsData = new MaterialsData(program); ListenerClass listener = new ListenerClass(); JFixedToolBar jToolBar = new JFixedToolBar(); jOwners = new JComboBox<>(); jOwners.setActionCommand(MaterialsAction.SELECTED.name()); jOwners.addActionListener(listener); jToolBar.addComboBox(jOwners, 200); jToolBar.addSpace(5); jMaterial = new JDropDownButton(TabsMaterials.get().includeMaterials(), Images.MISC_MATERIALS.getIcon()); jToolBar.addButton(jMaterial); jMaterialAll = new JCheckBoxMenuItem(TabsMaterials.get().all()); createAll(jMaterialGroups, jMaterialAll); jPi = new JDropDownButton(TabsMaterials.get().includePI(), Images.MISC_PI.getIcon()); jToolBar.addButton(jPi); jPiAll = new JCheckBoxMenuItem(TabsMaterials.get().all()); createAll(jPiGroups, jPiAll); jOre = new JDropDownButton(TabsMaterials.get().includeOre(), Images.MISC_ORE.getIcon()); jToolBar.addButton(jOre); jOreAll = new JCheckBoxMenuItem(TabsMaterials.get().all()); createAll(jOreGroups, jOreAll); jCommodity = new JDropDownButton(TabsMaterials.get().includeCommodity(), Images.MISC_COMMODITY.getIcon()); jToolBar.addButton(jCommodity); jCommodityAll = new JCheckBoxMenuItem(TabsMaterials.get().all()); createAll(jCommodityGroups, jCommodityAll); jToolBar.addSeparator(); jExport = new JButton(GuiShared.get().export(), Images.DIALOG_CSV_EXPORT.getIcon()); jExport.setActionCommand(MaterialsAction.EXPORT.name()); jExport.addActionListener(listener); jToolBar.addButton(jExport); jToolBar.addGlue(); jCollapse = new JButton(TabsMaterials.get().collapse(), Images.MISC_COLLAPSED.getIcon()); jCollapse.setActionCommand(MaterialsAction.COLLAPSE.name()); jCollapse.addActionListener(listener); jToolBar.addButton(jCollapse); jExpand = new JButton(TabsMaterials.get().expand(), Images.MISC_EXPANDED.getIcon()); jExpand.setActionCommand(MaterialsAction.EXPAND.name()); jExpand.addActionListener(listener); jToolBar.addButton(jExpand); //Table Format tableFormat = TableFormatFactory.materialTableFormat(); //Backend eventList = EventListManager.create(); //Separator eventList.getReadWriteLock().readLock().lock(); separatorList = new SeparatorList<>(eventList, new MaterialSeparatorComparator(), 1, Integer.MAX_VALUE); eventList.getReadWriteLock().readLock().unlock(); //Table Model tableModel = EventModels.createTableModel(separatorList, tableFormat); //Table jTable = new JSeparatorTable(program, tableModel, separatorList); jTable.setSeparatorRenderer(new MaterialsSeparatorTableCell(jTable, separatorList)); jTable.setSeparatorEditor(new MaterialsSeparatorTableCell(jTable, separatorList)); PaddingTableCellRenderer.install(jTable, 3); //Selection Model selectionModel = EventModels.createSelectionModel(separatorList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll jTableScroll = new JScrollPane(jTable); //Menu installTableTool(new MaterialTableMenu(), tableFormat, null, tableModel, jTable, eventList, Material.class); exportDialog = new ExportDialog<>(program.getMainWindow().getFrame(), NAME, null, new MaterialsFilterControl(), tableFormat, eventList); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(jToolBar, jToolBar.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void updateData() { if (!program.getOwnerNames(false).isEmpty()) { Set materialGroups = new TreeSet<>(); Set piGroups = new TreeSet<>(); Set oreGroups = new TreeSet<>(); Set commodityGroups = new TreeSet<>(); for (MyAsset asset : program.getAssetsList()) { Item item = asset.getItem(); if (item.getCategory().equals(Item.CATEGORY_MATERIAL)) { materialGroups.add(item.getGroup()); } if (item.getCategory().equals(Item.CATEGORY_COMMODITY)) { commodityGroups.add(item.getGroup()); } if (item.isPiMaterial()) { piGroups.add(item.getGroup()); } if (item.isMined()) { oreGroups.add(item.getGroup()); } } createGroups(materialGroups, jMaterialGroups, jMaterialAll, jMaterial); createGroups(piGroups, jPiGroups, jPiAll, jPi); createGroups(oreGroups, jOreGroups, jOreAll, jOre); createGroups(commodityGroups, jCommodityGroups, jCommodityAll, jCommodity); jExport.setEnabled(true); jExpand.setEnabled(true); jCollapse.setEnabled(true); jOwners.setEnabled(true); String selectedItem = (String) jOwners.getSelectedItem(); jOwners.setModel(new ListComboBoxModel<>(program.getOwnerNames(true))); if (selectedItem != null && program.getOwnerNames(true).contains(selectedItem)) { jOwners.setSelectedItem(selectedItem); } else { jOwners.setSelectedIndex(0); } } else { jExport.setEnabled(false); jExpand.setEnabled(false); jCollapse.setEnabled(false); jOwners.setEnabled(false); jOwners.setModel(new ListComboBoxModel<>()); jOwners.getModel().setSelectedItem(TabsMaterials.get().no()); } } @Override public void clearData() { try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } @Override public void updateCache() { } @Override public Collection getLocations() { try { eventList.getReadWriteLock().readLock().lock(); return new ArrayList<>(eventList); } finally { eventList.getReadWriteLock().readLock().unlock(); } } private void updateTable() { beforeUpdateData(); String owner = (String) jOwners.getSelectedItem(); Set groups = new HashSet<>(); addGroups(groups, jPiGroups, jPiAll); addGroups(groups, jMaterialGroups, jMaterialAll); addGroups(groups, jOreGroups, jOreAll); addGroups(groups, jCommodityGroups, jCommodityAll); //Save separator expanded/collapsed state jTable.saveExpandedState(); //Update Data boolean isEmpty = materialsData.updateData(eventList, owner, groups); //Restore separator expanded/collapsed state jTable.loadExpandedState(); if (!isEmpty) { jExport.setEnabled(true); jExpand.setEnabled(true); jCollapse.setEnabled(true); } else { jExport.setEnabled(false); jExpand.setEnabled(false); jCollapse.setEnabled(false); } jTableScroll.getViewport().setViewPosition(new Point(0, 0)); afterUpdateData(); } private void addGroups(Set groups, List jGroups, JCheckBoxMenuItem jAll) { boolean all = true; for (JCheckBoxMenuItem jGroup : jGroups) { if (jGroup.isSelected()) { groups.add(jGroup.getText()); } else { all = false; } } jAll.setSelected(all); } private void createGroups(Set groups, List jGroups, JCheckBoxMenuItem jAll, JDropDownButton jButton) { jButton.removeAll(); jGroups.clear(); jAll.setSelected(true); jButton.add(jAll); for (String group : groups) { JCheckBoxMenuItem jGroup = new JCheckBoxMenuItem(group); jGroup.setSelected(true); jGroup.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateTable(); } }); jButton.add(jGroup, true); jGroups.add(jGroup); } } private void createAll(List jGroups, JCheckBoxMenuItem jAll) { jAll.setSelected(true); jAll.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { boolean selected = jAll.isSelected(); for (JCheckBoxMenuItem jGroup : jGroups) { jGroup.setSelected(selected); } updateTable(); } }); } private class MaterialTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return null; } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { JMenuInfo.material(jPopupMenu, selectionModel.getSelected(), eventList); } @Override public void addToolMenu(JComponent jComponent) { } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (MaterialsAction.SELECTED.name().equals(e.getActionCommand())) { updateTable(); } if (MaterialsAction.COLLAPSE.name().equals(e.getActionCommand())) { jTable.expandSeparators(false); } if (MaterialsAction.EXPAND.name().equals(e.getActionCommand())) { jTable.expandSeparators(true); } if (MaterialsAction.EXPORT.name().equals(e.getActionCommand())) { exportDialog.setVisible(true); } } } private class MaterialsFilterControl implements SimpleFilterControl { @Override public void saveSettings(final String msg) { program.saveSettings("Materials Table " + msg); //Save Material Export Settings (Filters not used) } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/mining/ExtractionsTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.mining; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.util.ArrayList; import java.util.Collection; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyExtraction; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabPrimary; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.TabsMining; public class ExtractionsTab extends JMainTabPrimary { //GUI private final JAutoColumnTable jTable; //Table private final ExtractionFilterControl filterControl; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventTableModel tableModel; private final EventList eventList; private final FilterList filterList; private final DefaultEventSelectionModel selectionModel; public static final String NAME = "extractions"; //Not to be changed! public ExtractionsTab(Program program) { super(program, NAME, TabsMining.get().extractions(), Images.TOOL_EXTRACTIONS.getIcon(), true); //Table Format tableFormat = TableFormatFactory.extractionsTableFormat(); //Backend eventList = program.getProfileData().getExtractionsEventList(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedList); eventList.getReadWriteLock().readLock().unlock(); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JExtractionsTable(program, tableModel); jTable.setCellSelectionEnabled(true); jTable.setRowSelectionAllowed(true); jTable.setColumnSelectionAllowed(true); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new ExtractionFilterControl(sortedList); //Menu installTableTool(new ExtractionTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, MyExtraction.class); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void updateCache() { } @Override public void clearData() { } @Override public Collection getLocations() { return new ArrayList<>(); //No Location } private class ExtractionTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { } @Override public void addToolMenu(JComponent jComponent) { } } private class ExtractionFilterControl extends FilterControl { public ExtractionFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("Extractions Table: " + msg); //Save Mining Filters and Export Settings } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/mining/ExtractionsTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.mining; import java.util.Comparator; import java.util.Date; import net.nikr.eve.jeveasset.data.api.my.MyExtraction; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.TabsMining; public enum ExtractionsTableFormat implements EnumTableColumn { LOCATION(String.class) { @Override public String getColumnName() { return TabsMining.get().columnLocation(); } @Override public Object getColumnValue(final MyExtraction from) { return from.getLocation().getLocation(); } }, MOON(String.class) { @Override public String getColumnName() { return TabsMining.get().columnMoon(); } @Override public Object getColumnValue(final MyExtraction from) { return from.getMoon().getLocation(); } }, START(Date.class) { @Override public String getColumnName() { return TabsMining.get().columnExtractionStartTime(); } @Override public Object getColumnValue(final MyExtraction from) { return from.getExtractionStartTime(); } }, ARRIVAL(Date.class) { @Override public String getColumnName() { return TabsMining.get().columnChunkArrivalTime(); } @Override public Object getColumnValue(final MyExtraction from) { return from.getChunkArrivalTime(); } }, DECAY(Date.class) { @Override public String getColumnName() { return TabsMining.get().columnNaturalDecayTime(); } @Override public Object getColumnValue(final MyExtraction from) { return from.getNaturalDecayTime(); } }; private final Class type; private final Comparator comparator; private ExtractionsTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/mining/JExtractionsTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.mining; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyExtraction; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; public class JExtractionsTable extends JAutoColumnTable { private static final Calendar CALENDAR = Calendar.getInstance(TimeZone.getTimeZone("GMT")); private final DefaultEventTableModel tableModel; public JExtractionsTable(final Program program, final DefaultEventTableModel tableModel) { super(program, tableModel); this.tableModel = tableModel; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); boolean isSelected = isCellSelected(row, column); MyExtraction extraction = tableModel.getElementAt(row); String columnName = (String) this.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); if (columnName.equals(ExtractionsTableFormat.ARRIVAL.getColumnName())) { Date start = extraction.getChunkArrivalTime(); if ((nextDays(start, 2) || lastDays(start, 2))) { ColorSettings.configCell(component, ColorEntry.EXTRACTIONS_DAYS, isSelected); } else if (nextDays(start, 7)) { ColorSettings.configCell(component, ColorEntry.EXTRACTIONS_WEEK, isSelected); } else if (!past(start)) { ColorSettings.configCell(component, ColorEntry.EXTRACTIONS_WEEKS, isSelected); } } if (columnName.equals(ExtractionsTableFormat.DECAY.getColumnName())) { Date end = extraction.getNaturalDecayTime(); if (lastDays(end, 2)) { ColorSettings.configCell(component, ColorEntry.EXTRACTIONS_DAYS, isSelected); } } return component; } private boolean lastDays(final Date date, final int days) { CALENDAR.setTime(new Date()); CALENDAR.add(Calendar.DAY_OF_MONTH, -days); return date.before(Settings.getNow()) && date.after(CALENDAR.getTime()); } private boolean past(final Date date) { return date.before(Settings.getNow()); } private boolean nextDays(final Date date, final int days) { CALENDAR.setTime(new Date()); CALENDAR.add(Calendar.DAY_OF_MONTH, days); return date.after(Settings.getNow()) && date.before(CALENDAR.getTime()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/mining/MiningGraphTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.mining; import com.github.lgooddatepicker.optionalusertools.DateChangeListener; import com.github.lgooddatepicker.zinternaltools.DateChangeEvent; import java.awt.Color; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import javax.swing.AbstractListModel; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.ListModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.JStatusLabel; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.ColorIcon; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.JFreeChartUtil; import net.nikr.eve.jeveasset.gui.shared.components.JDateChooser; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.components.JMultiSelectionList; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.AutoNumberFormat; import net.nikr.eve.jeveasset.gui.tabs.tracker.QuickDate; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.i18n.TabsMining; import net.nikr.eve.jeveasset.i18n.TabsTracker; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.LogarithmicAxis; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.labels.XYToolTipGenerator; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.time.SimpleTimePeriod; import org.jfree.data.time.TimePeriodValues; import org.jfree.data.time.TimePeriodValuesCollection; import org.jfree.data.xy.XYDataset; public class MiningGraphTab extends JMainTabSecondary { private enum MiningGraphAction { TYPE_CHANGE, QUICK_DATE, INCLUDE_ZERO, LOGARITHMIC, SHOW_ALL, UPDATE_SHOWN, } private enum Type { ORE(AutoNumberFormat.ISK) { @Override public double toValue(MyMining mining) { return mining.getValue(); } @Override public String getText() { return TabsMining.get().valueOre(); } }, REPROCESSED(AutoNumberFormat.ISK) { @Override public double toValue(MyMining mining) { return mining.getValueReprocessed(); } @Override public String getText() { return TabsMining.get().valueReprocessed(); } }, REPROCESSED_MAX(AutoNumberFormat.ISK) { @Override public double toValue(MyMining mining) { return mining.getValueReprocessedMax(); } @Override public String getText() { return TabsMining.get().valueReprocessedMax(); } }, VOLUME(AutoNumberFormat.DOUBLE) { @Override public double toValue(MyMining mining) { return mining.getVolumeTotal(); } @Override public String getText() { return TabsMining.get().volume(); } }, COUNT(AutoNumberFormat.ITEMS) { @Override public double toValue(MyMining mining) { return mining.getCount(); } @Override public String getText() { return TabsMining.get().count(); } }; private final AutoNumberFormat format; private Type(AutoNumberFormat format) { this.format = format; } public String format(Number value) { return JMenuInfo.format(value, format); } private AutoNumberFormat getAutoNumberFormat() { return format; } public abstract double toValue(MyMining mining); public abstract String getText(); @Override public String toString() { return getText(); } } private final int PANEL_WIDTH_MINIMUM = 215; //GUI private final JComboBox jType; private final JComboBox jQuickDate; private final JDateChooser jFrom; private final JDateChooser jTo; private final JDropDownButton jShow; private final JCheckBoxMenuItem jAll; private final JMultiSelectionList jOwners; private final JCheckBoxMenuItem jIncludeZero; private final JRadioButtonMenuItem jLogarithmic; //Graph private final JFreeChart jFreeChart; private final ChartPanel jChartPanel; private final XYLineAndShapeRenderer renderer; private final DateAxis domainAxis; private final LogarithmicAxis rangeLogarithmicAxis; private final NumberAxis rangeLinearAxis; //Listener private final ListenerClass listener = new ListenerClass(); //Data private final TotalComparator comparator = new TotalComparator(); private final List shownOrder = new ArrayList<>(); private final Map series = new HashMap<>(); private final Map seriesMax = new HashMap<>(); private final Map seriesTotals = new HashMap<>(); private final Map seriesGroup = new HashMap<>(); private final TimePeriodValuesCollection dataset = new TimePeriodValuesCollection(); private final Map items = new TreeMap<>(); //Settings ToDo private Date fromDate = null; private Date toDate = null; public static final String NAME = "mininggraph"; //Not to be changed! public MiningGraphTab(Program program) { super(program, NAME, TabsMining.get().miningGraph(), Images.TOOL_MINING_GRAPH.getIcon(), true); jType = new JComboBox<>(Type.values()); jType.setActionCommand(MiningGraphAction.TYPE_CHANGE.name()); jType.addActionListener(listener); JSeparator jTypeSeparator = new JSeparator(); jQuickDate = new JComboBox<>(QuickDate.values()); jQuickDate.setActionCommand(MiningGraphAction.QUICK_DATE.name()); jQuickDate.addActionListener(listener); JLabel jFromLabel = new JLabel(TabsMining.get().from()); jFrom = new JDateChooser(true); if (fromDate != null) { jFrom.setDate(fromDate); } jFrom.addDateChangeListener(listener); JLabel jToLabel = new JLabel(TabsMining.get().to()); jTo = new JDateChooser(true); if (toDate != null) { jTo.setDate(toDate); } jTo.addDateChangeListener(listener); JSeparator jDateSeparator = new JSeparator(); jShow = new JDropDownButton(TabsMining.get().show(), Images.LOC_INCLUDE.getIcon()); jShow.setHorizontalAlignment(JButton.LEFT); jAll = new JCheckBoxMenuItem(General.get().all()); jAll.setSelected(true); jAll.setActionCommand(MiningGraphAction.SHOW_ALL.name()); jAll.addActionListener(listener); jAll.setFont(new Font(jAll.getFont().getName(), Font.ITALIC, jAll.getFont().getSize())); JSeparator jShowSeparator = new JSeparator(); JDropDownButton jSettings = new JDropDownButton(Images.DIALOG_SETTINGS.getIcon()); jIncludeZero = new JCheckBoxMenuItem(TabsMining.get().includeZero()); jIncludeZero.setSelected(true); jIncludeZero.setActionCommand(MiningGraphAction.INCLUDE_ZERO.name()); jIncludeZero.addActionListener(listener); jSettings.add(jIncludeZero); jSettings.addSeparator(); ButtonGroup buttonGroup = new ButtonGroup(); JRadioButtonMenuItem jLinear = new JRadioButtonMenuItem(TabsMining.get().scaleLinear()); jLinear.setSelected(true); jLinear.setActionCommand(MiningGraphAction.LOGARITHMIC.name()); jLinear.addActionListener(listener); jSettings.add(jLinear); buttonGroup.add(jLinear); jLogarithmic = new JRadioButtonMenuItem(TabsMining.get().scaleLogarithmic()); jLogarithmic.setSelected(false); jLogarithmic.setActionCommand(MiningGraphAction.LOGARITHMIC.name()); jLogarithmic.addActionListener(listener); jSettings.add(jLogarithmic); buttonGroup.add(jLogarithmic); jOwners = new JMultiSelectionList<>(); jOwners.getSelectionModel().addListSelectionListener(listener); JScrollPane jOwnersScroll = new JScrollPane(jOwners); domainAxis = JFreeChartUtil.createDateAxis(); rangeLogarithmicAxis = JFreeChartUtil.createLogarithmicAxis(true); rangeLinearAxis = JFreeChartUtil.createNumberAxis(true); renderer = JFreeChartUtil.createRenderer(); renderer.setDefaultToolTipGenerator(new XYToolTipGenerator() { @Override public String generateToolTip(XYDataset dataset, int series, int item) { Date date = new Date(dataset.getX(series, item).longValue()); Number value = dataset.getY(series, item); Type type = jType.getItemAt(jType.getSelectedIndex()); return TabsMining.get().graphToolTip(dataset.getSeriesKey(series), type.format(value), Formatter.columnDateOnly(date)); } }); XYPlot plot = JFreeChartUtil.createPlot(dataset, domainAxis, rangeLinearAxis, renderer); jFreeChart = JFreeChartUtil.createChart(plot); jChartPanel = JFreeChartUtil.createChartPanel(jFreeChart); int gapWidth = 5; int labelWidth = Math.max(jFromLabel.getPreferredSize().width, jToLabel.getPreferredSize().width); int panelWidth = PANEL_WIDTH_MINIMUM; panelWidth = Math.max(panelWidth, jFrom.getPreferredSize().width + labelWidth + gapWidth); panelWidth = Math.max(panelWidth, jTo.getPreferredSize().width + labelWidth + gapWidth); int dateWidth = panelWidth - labelWidth - gapWidth; layout.setHorizontalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jChartPanel) ) .addGroup(layout.createParallelGroup() .addComponent(jType, panelWidth, panelWidth, panelWidth) .addComponent(jTypeSeparator, panelWidth, panelWidth, panelWidth) .addComponent(jQuickDate, panelWidth, panelWidth, panelWidth) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jFromLabel, labelWidth, labelWidth, labelWidth) .addComponent(jToLabel, labelWidth, labelWidth, labelWidth) ) .addGap(gapWidth) .addGroup(layout.createParallelGroup() .addComponent(jFrom, dateWidth, dateWidth, dateWidth) .addComponent(jTo, dateWidth, dateWidth, dateWidth) ) ) .addComponent(jDateSeparator, panelWidth, panelWidth, panelWidth) .addComponent(jShow, panelWidth, panelWidth, panelWidth) .addComponent(jShowSeparator, panelWidth, panelWidth, panelWidth) .addGroup(layout.createSequentialGroup() .addComponent(jSettings) ) .addComponent(jOwnersScroll, panelWidth, panelWidth, panelWidth) ) ); layout.setVerticalGroup( layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addComponent(jChartPanel) ) .addGroup(layout.createSequentialGroup() .addComponent(jType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jTypeSeparator, 3, 3, 3) .addComponent(jQuickDate, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup() .addComponent(jFromLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFrom, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jToLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jTo, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jDateSeparator, 3, 3, 3) .addComponent(jShow, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jShowSeparator, 3, 3, 3) .addGroup(layout.createParallelGroup() .addComponent(jSettings, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jOwnersScroll, 70, 70, Integer.MAX_VALUE) ) ); } @Override public void updateData() { createData(); updateGUI(); updateShown(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { updateStatusbar(); //Must be done after being shown } }); } @Override public void updateCache() { } @Override public void clearData() { } @Override public Collection getLocations() { return new ArrayList<>(); //No Location } private void updateGUI() { Set ownerSet = new HashSet<>(program.getOwnerNames(false)); try { program.getProfileData().getMiningEventList().getReadWriteLock().readLock().lock(); for (MyMining mining : program.getProfileData().getMiningEventList()) { ownerSet.add(mining.getCharacterName()); if(mining.isForCorporation()) { ownerSet.add(mining.getCorporationName()); } } } finally { program.getProfileData().getMiningEventList().getReadWriteLock().readLock().unlock(); } List owners = new ArrayList<>(ownerSet); Collections.sort(owners); listener.valueIsAdjusting = true; if (owners.isEmpty()) { jOwners.setEnabled(false); jOwners.setModel(new AbstractListModel() { @Override public int getSize() { return 1; } @Override public String getElementAt(int index) { return TabsTracker.get().noDataFound(); } }); } else { List selectedOwners = jOwners.getSelectedValuesList(); jOwners.setEnabled(true); jOwners.setModel(new AbstractListModel() { @Override public int getSize() { return owners.size(); } @Override public String getElementAt(int index) { return owners.get(index); } }); if (items.isEmpty()) { jOwners.selectAll(); } else { ListModel model = jOwners.getModel(); for (int i = 0; i < model.getSize(); i++) { String ownerName = model.getElementAt(i); if (selectedOwners.contains(ownerName)) { jOwners.addSelectionInterval(i, i); } } } } createData(); jShow.removeAll(); if (shownOrder.isEmpty()) { jShow.setEnabled(false); } else { jShow.setEnabled(true); jShow.add(jAll, true); List itemsList = new ArrayList<>(shownOrder); Collections.sort(itemsList, comparator); for (String s : itemsList) { JCheckBoxMenuItem jMenuItem = items.get(s); if (jMenuItem == null) { //Create new item jMenuItem = new JCheckBoxMenuItem(s); jMenuItem.setSelected(true); jMenuItem.setActionCommand(MiningGraphAction.UPDATE_SHOWN.name()); jMenuItem.addActionListener(listener); items.put(s, jMenuItem); } jShow.add(jMenuItem, true); } } listener.valueIsAdjusting = false; updateShown(); } private void createData() { Date from = getFromDate(); Date to = getToDate(); Type type = jType.getItemAt(jType.getSelectedIndex()); //Remove All while (dataset.getSeriesCount() != 0) { dataset.removeSeries(0); } series.clear(); shownOrder.clear(); seriesMax.clear(); seriesTotals.clear(); seriesGroup.clear(); //dataset Map> groupCounts = new HashMap<>(); Map> values = new TreeMap<>(); Set names = new HashSet<>(); final String grandTotal = TabsMining.get().grandTotal(); List selectedOwners = getSelectedOwners(); try { program.getProfileData().getMiningEventList().getReadWriteLock().readLock().lock(); for (MyMining mining : program.getProfileData().getMiningEventList()) { final Date date = mining.getDate(); //Filter if ((from != null && !date.after(from)) || (to != null && !date.before(to))) { continue; } if (!selectedOwners.contains(mining.getCharacterName()) || (mining.isForCorporation() && !selectedOwners.contains(mining.getCorporationName()))) { continue; } //Type final String typeName = getTypeName(mining.getItem()); final double value = type.toValue(mining); Map map = values.get(date); if (map == null) { map = new HashMap<>(); values.put(date, map); } names.add(typeName); Double typeTotal = map.getOrDefault(typeName, 0.0); map.put(typeName, typeTotal + value); //Group Total final String groupName = TabsMining.get().groupTotal(mining.getItem().getGroup()); double groupTotal = map.getOrDefault(groupName, 0.0); names.add(groupName); map.put(groupName, groupTotal + value); Set set = groupCounts.get(groupName); if (set == null) { set = new HashSet<>(); groupCounts.put(groupName, set); } set.add(typeName); seriesGroup.put(typeName, groupName); //GrandTotal double total = map.getOrDefault(grandTotal, 0.0); names.add(grandTotal); map.put(grandTotal, total + value); //Totals double d; d = seriesTotals.getOrDefault(typeName, 0.0); d = d + value; seriesTotals.put(typeName, d); d = seriesTotals.getOrDefault(groupName, 0.0); d = d + value; seriesTotals.put(groupName, d); d = seriesTotals.getOrDefault(grandTotal, 0.0); d = d + value; seriesTotals.put(grandTotal, d); } } finally { program.getProfileData().getMiningEventList().getReadWriteLock().readLock().unlock(); } //Remove group totals for groups with only one entry for (Map.Entry> entry : groupCounts.entrySet()) { if (entry.getValue().size() < 2) { names.remove(entry.getKey()); } } //Remove grand total if only one entry if (names.size() == 1) { names.remove(grandTotal); } for (Map.Entry> entry : values.entrySet()) { final Date date = entry.getKey(); Map map = entry.getValue(); for (String name : names) { final double value = map.getOrDefault(name, 0.0); TimePeriodValues timePeriod = series.get(name); if (timePeriod == null) { timePeriod = new TimePeriodValues(name); series.put(name, timePeriod); } double max = seriesMax.getOrDefault(name, 0.0); max = Math.max(max, value); seriesMax.put(name, max); SimpleTimePeriod simpleTimePeriod = new SimpleTimePeriod(date, date); timePeriod.add(simpleTimePeriod, value); } } shownOrder.addAll(names); Collections.sort(shownOrder, comparator); //Add all for (String typeName : shownOrder) { dataset.addSeries(series.get(typeName)); } } private String getTypeName(Item item) { if (item.getTypeName().equals(item.getGroup())) { return TabsMining.get().groupBasic(item.getTypeName()); } else { String oreType = item.getTypeName().replace(item.getGroup(), "").trim(); return TabsMining.get().groupName(item.getGroup(), oreType); } } private List getSelectedItems() { List selected = new ArrayList<>(); for (Map.Entry entry : items.entrySet()) { if (!entry.getValue().isSelected()) { continue; //Not selected } selected.add(entry.getKey()); } return selected; } private List getSelectedOwners() { return jOwners.getSelectedValuesList(); } private void updateStatusbar() { Type type = jType.getItemAt(jType.getSelectedIndex()); List selected = getSelectedItems(); Set shownGroups = new HashSet<>(); Set shownTypes = new HashSet<>(); for (String typeName : selected) { String groupName = seriesGroup.get(typeName); if (groupName == null) { //Group or Grand total shownGroups.add(typeName); } else { shownTypes.add(typeName); } } clearStatusbarLabels(); for (int i = 0; i < shownOrder.size(); i++) { final String typeName = shownOrder.get(i); final Double value = seriesTotals.get(typeName); String group = seriesGroup.get(typeName); if (value != null && (shownGroups.contains(typeName) //Shown group || (shownTypes.contains(typeName) && !shownGroups.contains(group)))) { //Shown Type final Color color = (Color) renderer.getSeriesPaint(i); JStatusLabel jStatusLabel = StatusPanel.createLabel(typeName, new ColorIcon(color), type.getAutoNumberFormat()); jStatusLabel.setNumber(value); addStatusbarLabel(jStatusLabel); } } program.getStatusPanel().tabChanged(); } private void updateShown() { List selected = getSelectedItems(); double max = 0; int count = 0; for (int i = 0; i < dataset.getSeriesCount(); i++) { String typeName = shownOrder.get(i); boolean fromVisible = renderer.isSeriesVisible(i); boolean toVisible = selected.contains(typeName); if (fromVisible != toVisible) { renderer.setSeriesVisible(i, toVisible); } max = Math.max(max, seriesMax.get(typeName)); count = Math.max(count, dataset.getItemCount(i)); } JFreeChartUtil.updateTickScale(domainAxis, rangeLinearAxis, max); renderer.setDefaultShapesVisible(count < 2); updateStatusbar(); } private Date getFromDate() { LocalDate date = jFrom.getDate(); if (date == null) { return null; } Instant instant = date.atStartOfDay().atZone(ZoneId.of("GMT")).toInstant(); //Start of day - GMT return Date.from(instant); } private Date getToDate() { LocalDate date = jTo.getDate(); if (date == null) { return null; } Instant instant = date.atTime(23, 59, 59).atZone(ZoneId.of("GMT")).toInstant(); //End of day - GMT return Date.from(instant); } private class ListenerClass implements ActionListener, DateChangeListener, ListSelectionListener { boolean valueIsAdjusting = false; @Override public void actionPerformed(ActionEvent e) { if (MiningGraphAction.TYPE_CHANGE.name().equals(e.getActionCommand())) { createData(); updateShown(); } else if (MiningGraphAction.QUICK_DATE.name().equals(e.getActionCommand())) { QuickDate quickDate = (QuickDate) jQuickDate.getSelectedItem(); if (quickDate == QuickDate.RESET) { jTo.clearDate(); jFrom.clearDate(); } else { Date toDate = getToDate(); if (toDate == null) { toDate = new Date(); //now } Date fromDate = quickDate.apply(toDate); if (fromDate != null) { jFrom.setDate(fromDate); } } } else if (MiningGraphAction.INCLUDE_ZERO.name().equals(e.getActionCommand())) { rangeLogarithmicAxis.setAutoRangeIncludesZero(jIncludeZero.isSelected()); rangeLinearAxis.setAutoRangeIncludesZero(jIncludeZero.isSelected()); } else if (MiningGraphAction.LOGARITHMIC.name().equals(e.getActionCommand())) { if (jLogarithmic.isSelected()) { jFreeChart.getXYPlot().setRangeAxis(rangeLogarithmicAxis); } else { jFreeChart.getXYPlot().setRangeAxis(rangeLinearAxis); } } else if (MiningGraphAction.SHOW_ALL.name().equals(e.getActionCommand())) { if (valueIsAdjusting) { return; } valueIsAdjusting = true; for (JCheckBoxMenuItem jMenuItem : items.values()) { jMenuItem.setSelected(jAll.isSelected()); } valueIsAdjusting = false; updateShown(); } else if (MiningGraphAction.UPDATE_SHOWN.name().equals(e.getActionCommand())) { if (valueIsAdjusting) { return; } valueIsAdjusting = true; jAll.setSelected(getSelectedItems().size() == items.size()); valueIsAdjusting = false; updateShown(); } } @Override public void dateChanged(DateChangeEvent event) { Date from = getFromDate(); Date to = getToDate(); QuickDate quickDate = (QuickDate) jQuickDate.getSelectedItem(); if (!quickDate.isValid(from, to)) { QuickDate selected = quickDate.getSelected(from, to); jQuickDate.setSelectedItem(selected); } if (from != null && to != null && from.after(to)) { jTo.setDate(from); } createData(); updateShown(); } @Override public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting() || valueIsAdjusting) { return; } createData(); updateShown(); } } public class TotalComparator implements Comparator { private final String grandTotal = TabsMining.get().grandTotal(); private final String groupTotal = TabsMining.get().groupTotal(""); @Override public int compare(String o1, String o2) { boolean t1 = o1.equals(grandTotal); boolean t2 = o2.equals(grandTotal); if (t1) { return -1; } else if (t2) { return 1; } boolean g1 = o1.contains(groupTotal); boolean g2 = o2.contains(groupTotal); if (g1) { String type = o1.replace(groupTotal, "").trim(); if (o2.contains(type)) { return -1; } } if (g2) { String type = o2.replace(groupTotal, "").trim(); if (o1.contains(type)) { return 1; } } return o1.compareToIgnoreCase(o2); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/mining/MiningTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.mining; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.util.ArrayList; import java.util.Collection; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.JStatusLabel; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabPrimary; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.AutoNumberFormat; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.TabsMining; public class MiningTab extends JMainTabPrimary { //GUI private final JAutoColumnTable jTable; private final JStatusLabel jValue; private final JStatusLabel jReprocessed; private final JStatusLabel jCount; private final JStatusLabel jAverage; private final JStatusLabel jVolume; //Table private final MiningFilterControl filterControl; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventTableModel tableModel; private final EventList eventList; private final FilterList filterList; private final DefaultEventSelectionModel selectionModel; public static final String NAME = "mining"; //Not to be changed! public MiningTab(Program program) { super(program, NAME, TabsMining.get().miningLog(), Images.TOOL_MINING_LOG.getIcon(), true); ListenerClass listener = new ListenerClass(); //StatusPanels must be initialized before the eventlist jVolume = StatusPanel.createLabel(TabsMining.get().totalVolume(), Images.ASSETS_VOLUME.getIcon(), AutoNumberFormat.DOUBLE); this.addStatusbarLabel(jVolume); jCount = StatusPanel.createLabel(TabsMining.get().totalCount(), Images.EDIT_ADD.getIcon(), AutoNumberFormat.ITEMS); this.addStatusbarLabel(jCount); jAverage = StatusPanel.createLabel(TabsMining.get().average(), Images.ASSETS_AVERAGE.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jAverage); jReprocessed = StatusPanel.createLabel(TabsMining.get().totalReprocessed(), Images.SETTINGS_REPROCESSING.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jReprocessed); jValue = StatusPanel.createLabel(TabsMining.get().totalValue(), Images.TOOL_VALUES.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jValue); //Table Format tableFormat = TableFormatFactory.miningTableFormat(); //Backend eventList = program.getProfileData().getMiningEventList(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedList); eventList.getReadWriteLock().readLock().unlock(); //Listener filterList.addListEventListener(listener); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JAutoColumnTable(program, tableModel); jTable.setCellSelectionEnabled(true); jTable.setRowSelectionAllowed(true); jTable.setColumnSelectionAllowed(true); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new MiningFilterControl(sortedList); //Menu installTableTool(new MiningTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, MyMining.class); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void updateCache() { } @Override public void clearData() { } @Override public Collection getLocations() { return new ArrayList<>(); //No Location } private void updateStatusbar() { double averageValue = 0; double totalValue = 0; long totalCount = 0; double totalVolume = 0; double totalReprocessed = 0; try { filterList.getReadWriteLock().readLock().lock(); for (MyMining mining : filterList) { totalValue = totalValue + mining.getValue(); totalCount = totalCount + mining.getCount(); totalVolume = totalVolume + mining.getVolumeTotal(); totalReprocessed = totalReprocessed + mining.getValueReprocessed(); } } finally { filterList.getReadWriteLock().readLock().unlock(); } if (totalCount > 0 && totalValue > 0) { averageValue = totalValue / totalCount; } jVolume.setNumber(totalVolume); jCount.setNumber(totalCount); jAverage.setNumber(averageValue); jReprocessed.setNumber(totalReprocessed); jValue.setNumber(totalValue); } private class MiningTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { JMenuInfo.infoItem(jPopupMenu, selectionModel.getSelected()); } @Override public void addToolMenu(JComponent jComponent) { } } private class MiningFilterControl extends FilterControl { public MiningFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("Mining Table: " + msg); //Save Mining Filters and Export Settings } } private class ListenerClass implements ListEventListener { @Override public void listChanged(final ListEvent listChanges) { updateStatusbar(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/mining/MiningTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.mining; import java.util.Comparator; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.DateOnly; import net.nikr.eve.jeveasset.i18n.TabsMining; public enum MiningTableFormat implements EnumTableColumn { DATE(DateOnly.class) { @Override public String getColumnName() { return TabsMining.get().columnDate(); } @Override public Object getColumnValue(final MyMining from) { return from.getDateOnly(); } }, NAME(String.class) { @Override public String getColumnName() { return TabsMining.get().columnName(); } @Override public Object getColumnValue(final MyMining from) { return from.getItem().getTypeName(); } }, GROUP(String.class) { @Override public String getColumnName() { return TabsMining.get().columnGroup(); } @Override public Object getColumnValue(final MyMining from) { return from.getItem().getGroup(); } }, CATEGORY(String.class) { @Override public String getColumnName() { return TabsMining.get().columnCategory(); } @Override public Object getColumnValue(final MyMining from) { return from.getItem().getCategory(); } }, OWNER(String.class) { @Override public String getColumnName() { return TabsMining.get().columnOwner(); } @Override public Object getColumnValue(final MyMining from) { return from.getCharacterName(); } }, LOCATION(String.class) { @Override public String getColumnName() { return TabsMining.get().columnLocation(); } @Override public Object getColumnValue(final MyMining from) { return from.getLocation().getLocation(); } }, COUNT(Long.class) { @Override public String getColumnName() { return TabsMining.get().columnCount(); } @Override public Object getColumnValue(final MyMining from) { return from.getCount(); } }, PRICE_ORE(Double.class) { @Override public String getColumnName() { return TabsMining.get().columnPriceOre(); } @Override public Object getColumnValue(final MyMining from) { return from.getDynamicPrice(); } }, PRICE_REPROCESSED(Double.class) { @Override public String getColumnName() { return TabsMining.get().columnPriceReprocessed(); } @Override public String getColumnToolTip() { return TabsMining.get().columnPriceReprocessedToolTip(); } @Override public Object getColumnValue(final MyMining from) { return from.getPriceReprocessed(); } }, PRICE_REPROCESSED_MAX(Double.class) { @Override public String getColumnName() { return TabsMining.get().columnPriceReprocessedMax(); } @Override public String getColumnToolTip() { return TabsMining.get().columnPriceReprocessedMaxToolTip(); } @Override public Object getColumnValue(final MyMining from) { return from.getPriceReprocessedMax(); } }, VALUE_ORE(Double.class) { @Override public String getColumnName() { return TabsMining.get().columnValueOre(); } @Override public Object getColumnValue(final MyMining from) { return from.getValue(); } }, VALUE_REPROCESSED(Double.class) { @Override public String getColumnName() { return TabsMining.get().columnValueReprocessed(); } @Override public String getColumnToolTip() { return TabsMining.get().columnValueReprocessedToolTip(); } @Override public Object getColumnValue(final MyMining from) { return from.getValueReprocessed(); } }, VALUE_REPROCESSED_MAX(Double.class) { @Override public String getColumnName() { return TabsMining.get().columnValueReprocessedMax(); } @Override public String getColumnToolTip() { return TabsMining.get().columnValueReprocessedMaxToolTip(); } @Override public Object getColumnValue(final MyMining from) { return from.getValueReprocessedMax(); } }, VOLUME(Double.class) { @Override public String getColumnName() { return TabsMining.get().columnVolume(); } @Override public Object getColumnValue(final MyMining from) { return from.getVolumeTotal(); } }, VALUE_PER_VOLUME_ORE(Double.class) { @Override public String getColumnName() { return TabsMining.get().columnValuePerVolumeOre(); } @Override public Object getColumnValue(final MyMining from) { return from.getValuePerVolumeOre(); } }, VALUE_PER_VOLUME_REPROCESSED(Double.class) { @Override public String getColumnName() { return TabsMining.get().columnValuePerVolumeReprocessed(); } @Override public String getColumnToolTip() { return TabsMining.get().columnValuePerVolumeReprocessedToolTip(); } @Override public Object getColumnValue(final MyMining from) { return from.getValuePerVolumeReprocessed(); } }, VALUE_PER_VOLUME_REPROCESSED_MAX(Double.class) { @Override public String getColumnName() { return TabsMining.get().columnValuePerVolumeReprocessedMax(); } @Override public String getColumnToolTip() { return TabsMining.get().columnValuePerVolumeReprocessedMaxToolTip(); } @Override public Object getColumnValue(final MyMining from) { return from.getValuePerVolumeReprocessedMax(); } }, CORPORATION(String.class) { @Override public String getColumnName() { return TabsMining.get().columnCorporation(); } @Override public Object getColumnValue(final MyMining from) { return from.getCorporationName(); } }, FOR_CORPORATION(String.class) { @Override public String getColumnName() { return TabsMining.get().columnForCorporation(); } @Override public Object getColumnValue(final MyMining from) { return from.isForCorporation() ? TabsMining.get().corporation() : TabsMining.get().character(); } }; private final Class type; private final Comparator comparator; private MiningTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/orders/JMarketOrdersTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.orders; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; public class JMarketOrdersTable extends JAutoColumnTable { private final DefaultEventTableModel tableModel; public JMarketOrdersTable(final Program program, final DefaultEventTableModel tableModel) { super(program, tableModel); this.tableModel = tableModel; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); boolean isSelected = isCellSelected(row, column); MyMarketOrder marketOrder = tableModel.getElementAt(row); String columnName = (String) this.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); if (columnName.equals(MarketTableFormat.EXPIRES.getColumnName())) { if (marketOrder.isExpired()) { ColorSettings.configCell(component, ColorEntry.MARKET_ORDERS_EXPIRED, isSelected); } else if (marketOrder.isNearExpired()) { ColorSettings.configCell(component, ColorEntry.MARKET_ORDERS_NEAR_EXPIRED, isSelected); } } if (columnName.equals(MarketTableFormat.OUTBID_PRICE.getColumnName())) { if (marketOrder.haveOutbid()) { if (marketOrder.isOutbid()) { if (marketOrder.isOutbidOwned()) { ColorSettings.configCell(component, ColorEntry.MARKET_ORDERS_OUTBID_NOT_BEST_OWNED, isSelected); } else { ColorSettings.configCell(component, ColorEntry.MARKET_ORDERS_OUTBID_NOT_BEST, isSelected); } } else { ColorSettings.configCell(component, ColorEntry.MARKET_ORDERS_OUTBID_BEST, isSelected); } } else if (marketOrder.isActive()) { ColorSettings.configCell(component, ColorEntry.MARKET_ORDERS_OUTBID_UNKNOWN, isSelected); } } //Order filled warning if (columnName.equals(MarketTableFormat.QUANTITY.getColumnName())) { if (marketOrder.isNearFilled()) { ColorSettings.configCell(component, ColorEntry.MARKET_ORDERS_NEAR_FILLED, isSelected); } } //User set location if (marketOrder.getLocation().isUserLocation() && columnName.equals(MarketTableFormat.LOCATION.getColumnName())) { ColorSettings.configCell(component, ColorEntry.CUSTOM_USER_LOCATION, isSelected); return component; } //Changed date if (columnName.equals(MarketTableFormat.CHANGED.getColumnName()) && Settings.get().getTableChanged(MarketOrdersTab.NAME).before(marketOrder.getChanged())) { ColorSettings.configCell(component, ColorEntry.MARKET_ORDERS_NEW, isSelected); return component; } return component; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/orders/MarketLog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.orders; import java.util.Date; public class MarketLog { private Double price; private Double volRemaining; private Integer typeID; private Integer range; private Long orderID; private Integer volEntered; private Integer minVolume; private Boolean bid; private Date issueDate; private Integer duration; private Long stationID; private Long regionID; private Long solarSystemID; private Integer jumps; private String empty; public MarketLog() { } public MarketLog(Double price, Double volRemaining, Integer typeID, Integer range, Long orderID, Integer volEntered, Integer minVolume, Boolean bid, Date issueDate, Integer duration, Long stationID, Long regionID, Long solarSystemID, Integer jumps, String empty) { this.price = price; this.volRemaining = volRemaining; this.typeID = typeID; this.range = range; this.orderID = orderID; this.volEntered = volEntered; this.minVolume = minVolume; this.bid = bid; this.issueDate = issueDate; this.duration = duration; this.stationID = stationID; this.regionID = regionID; this.solarSystemID = solarSystemID; this.jumps = jumps; this.empty = empty; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } public Double getVolRemaining() { return volRemaining; } public void setVolRemaining(Double volRemaining) { this.volRemaining = volRemaining; } public Integer getTypeID() { return typeID; } public void setTypeID(Integer typeID) { this.typeID = typeID; } public Integer getRange() { return range; } public void setRange(Integer range) { this.range = range; } public Long getOrderID() { return orderID; } public void setOrderID(Long orderID) { this.orderID = orderID; } public Integer getVolEntered() { return volEntered; } public void setVolEntered(Integer volEntered) { this.volEntered = volEntered; } public Integer getMinVolume() { return minVolume; } public void setMinVolume(Integer minVolume) { this.minVolume = minVolume; } public Boolean getBid() { return bid; } public void setBid(Boolean bid) { this.bid = bid; } public Date getIssueDate() { return issueDate; } public void setIssueDate(Date issueDate) { this.issueDate = issueDate; } public Integer getDuration() { return duration; } public void setDuration(Integer duration) { this.duration = duration; } public Long getStationID() { return stationID; } public void setStationID(Long stationID) { this.stationID = stationID; } public Long getRegionID() { return regionID; } public void setRegionID(Long regionID) { this.regionID = regionID; } public Long getSolarSystemID() { return solarSystemID; } public void setSolarSystemID(Long solarSystemID) { this.solarSystemID = solarSystemID; } public Integer getJumps() { return jumps; } public void setJumps(Integer jumps) { this.jumps = jumps; } public String getEmpty() { return empty; } public void setEmpty(String empty) { this.empty = empty; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/orders/MarketOrdersTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.orders; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.StandardWatchEventKinds; import static java.nio.file.StandardWatchEventKinds.OVERFLOW; import java.nio.file.WatchEvent; import java.nio.file.WatchKey; import java.nio.file.WatchService; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Objects; import javax.swing.GroupLayout; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.Timer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.MarketOrderRange; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.MarketOrderState; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Colors; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.dialogs.settings.SoundsSettingsPanel.SoundOption; import net.nikr.eve.jeveasset.gui.dialogs.update.StructureUpdateDialog; import net.nikr.eve.jeveasset.gui.dialogs.update.TaskDialog; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.JStatusLabel; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.CopyHandler; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.InstantToolTip; import net.nikr.eve.jeveasset.gui.shared.MarketDetailsColumn; import net.nikr.eve.jeveasset.gui.shared.MarketDetailsColumn.MarketDetailsActionListener; import net.nikr.eve.jeveasset.gui.shared.Updatable; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabPrimary; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.AutoNumberFormat; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuUI; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.PaddingTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.gui.tabs.orders.OutbidProcesser.OutbidProcesserInput; import net.nikr.eve.jeveasset.gui.tabs.orders.OutbidProcesser.OutbidProcesserOutput; import net.nikr.eve.jeveasset.i18n.DialoguesUpdate; import net.nikr.eve.jeveasset.i18n.TabsOrders; import net.nikr.eve.jeveasset.io.esi.EsiPublicMarketOrdersGetter; import net.nikr.eve.jeveasset.io.local.MarketLogReader; import net.nikr.eve.jeveasset.gui.sounds.SoundPlayer; import net.nikr.eve.jeveasset.io.local.profile.ProfileDatabase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MarketOrdersTab extends JMainTabPrimary { private static final Logger LOG = LoggerFactory.getLogger(MarketOrdersTab.class); private enum MarketOrdersAction { UPDATE, ORDER_TYPE, ORDER_RANGE } private static final int SIGNIFICANT_FIGURES = 4; private final JAutoColumnTable jTable; private final JButton jUpdate; private final JButton jClearNew; private final JComboBox jOrderRangeNext; private final JComboBox jOrderType; private final JStatusLabel jSellOrdersTotal; private final JStatusLabel jBuyOrdersTotal; private final JStatusLabel jEscrowTotal; private final JStatusLabel jToCoverTotal; private final JStatusLabel jSellOrderRangeLast; private final JStatusLabel jLastEsiUpdate; private final JStatusLabel jLastLogUpdate; private final JStatusLabel jClipboard; private final Timer timer; private final FileListener fileListener; private static Date lastLogUpdate = null; private static String clipboardData = null; private boolean showUnknownLocationsWarning = true; //Table private final MarketOrdersFilterControl filterControl; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventTableModel tableModel; private final EventList eventList; private final FilterList filterList; private final DefaultEventSelectionModel selectionModel; public static final String NAME = "marketorders"; //Not to be changed! public MarketOrdersTab(final Program program) { super(program, NAME, TabsOrders.get().market(), Images.TOOL_MARKET_ORDERS.getIcon(), true); ListenerClass listener = new ListenerClass(); JFixedToolBar jToolBar = new JFixedToolBar(); jClearNew = new JButton(TabsOrders.get().clearNew(), Images.UPDATE_DONE_OK.getIcon()); jClearNew.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Settings.get().getTableChanged().put(NAME, new Date()); jTable.repaint(); jClearNew.setEnabled(false); program.saveSettings("Table Changed (market orders cleared)"); } }); jToolBar.addButton(jClearNew); jToolBar.addSeparator(); jToolBar.addSpace(5); jOrderRangeNext = new JComboBox<>(MarketOrderRange.valuesSorted()); jOrderRangeNext.setSelectedItem(Settings.get().getOutbidOrderRange()); jOrderRangeNext.setActionCommand(MarketOrdersAction.ORDER_RANGE.name()); jOrderRangeNext.addActionListener(listener); jToolBar.add(jOrderRangeNext, 95); jToolBar.addSpace(1); JLabel jOrderRangeNextLabel = new JLabel(Images.MISC_HELP.getIcon()); jOrderRangeNextLabel.setToolTipText(TabsOrders.get().sellOrderRangeToolTip()); InstantToolTip.install(jOrderRangeNextLabel); jToolBar.addLabelIcon(jOrderRangeNextLabel); jToolBar.addSpace(7); String[] orderTypes = {TabsOrders.get().updateOutbidFileBuy(), TabsOrders.get().updateOutbidFileSell()}; jOrderType = new JComboBox<>(orderTypes); jOrderType.setSelectedItem(TabsOrders.get().updateOutbidFileBuy()); jOrderType.setActionCommand(MarketOrdersAction.ORDER_TYPE.name()); jOrderType.addActionListener(listener); jToolBar.add(jOrderType, 95); jToolBar.addSpace(1); JLabel jOrderTypeLabel = new JLabel(Images.MISC_HELP.getIcon()); jOrderTypeLabel.setToolTipText(TabsOrders.get().marketLogTypeToolTip()); InstantToolTip.install(jOrderTypeLabel); jToolBar.addLabelIcon(jOrderTypeLabel); jToolBar.addSpace(7); jToolBar.addSeparator(); jUpdate = new JButton(TabsOrders.get().updateOutbidEsi(), Images.DIALOG_UPDATE.getIcon()); jUpdate.setActionCommand(MarketOrdersAction.UPDATE.name()); jUpdate.addActionListener(listener); jToolBar.addButton(jUpdate); //StatusPanels must be initialized before the eventlist jSellOrdersTotal = StatusPanel.createLabel(TabsOrders.get().totalSellOrders(), Images.ORDERS_SELL.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jSellOrdersTotal); jBuyOrdersTotal = StatusPanel.createLabel(TabsOrders.get().totalBuyOrders(), Images.ORDERS_BUY.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jBuyOrdersTotal); jEscrowTotal = StatusPanel.createLabel(TabsOrders.get().totalEscrow(), Images.ORDERS_ESCROW.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jEscrowTotal); jToCoverTotal = StatusPanel.createLabel(TabsOrders.get().totalToCover(), Images.ORDERS_TO_COVER.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jToCoverTotal); jSellOrderRangeLast = StatusPanel.createLabel(TabsOrders.get().sellOrderRangeLastToolTip(), Images.ORDERS_SELL.getIcon(), null); this.addStatusbarLabel(jSellOrderRangeLast); jSellOrderRangeLast.setText(TabsOrders.get().sellOrderRangeSelcted(Settings.get().getOutbidOrderRange().toString())); jClipboard = StatusPanel.createLabel(TabsOrders.get().lastClipboardToolTip(), Images.EDIT_COPY.getIcon(), null); this.addStatusbarLabel(jClipboard); setClipboardData(TabsOrders.get().none()); jLastLogUpdate = StatusPanel.createLabel(TabsOrders.get().lastLogUpdateToolTip(), null, null); this.addStatusbarLabel(jLastLogUpdate); jLastEsiUpdate = StatusPanel.createLabel(TabsOrders.get().lastEsiUpdateToolTip(), null, null); this.addStatusbarLabel(jLastEsiUpdate); //Table Format tableFormat = TableFormatFactory.marketTableFormat(); //Backend eventList = program.getProfileData().getMarketOrdersEventList(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedList); eventList.getReadWriteLock().readLock().unlock(); filterList.addListEventListener(listener); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JMarketOrdersTable(program, tableModel); jTable.setCellSelectionEnabled(true); //Padding PaddingTableCellRenderer.install(jTable, 1); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Market Details MarketDetailsColumn.install(eventList, new MarketDetailsActionListener() { @Override public void openMarketDetails(MyMarketOrder marketOrder) { openEve(marketOrder); } }); //Listeners installTable(jTable); //Scroll Panels JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new MarketOrdersFilterControl(sortedList); //Menu installTableTool(new OrdersTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, MyMarketOrder.class); updateDates(); timer = new Timer(1000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateDates(); } }); timer.start(); fileListener = new FileListener(program, Settings.get().getOutbidOrderRange()); fileListener.start(); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, jToolBar.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void clearData() { filterControl.clearCache(); } @Override public void updateCache() { Date current = Settings.get().getTableChanged(NAME); boolean newFound = false; try { eventList.getReadWriteLock().readLock().lock(); for (MyMarketOrder marketOrder : eventList) { if (current.before(marketOrder.getChanged())) { newFound = true; break; } } } finally { eventList.getReadWriteLock().readLock().unlock(); } filterControl.createCache(); final boolean found = newFound; Program.ensureEDT(new Runnable() { @Override public void run() { jClearNew.setEnabled(found); } }); } @Override public Collection getLocations() { try { eventList.getReadWriteLock().readLock().lock(); return new ArrayList<>(eventList); } finally { eventList.getReadWriteLock().readLock().unlock(); } } public synchronized static Date getLastLogUpdate() { return lastLogUpdate; } public synchronized static void setLastLogUpdate() { MarketOrdersTab.lastLogUpdate = new Date(); } public synchronized static String getClipboardData() { return clipboardData; } public synchronized static void setClipboardData(String clipboardData) { MarketOrdersTab.clipboardData = clipboardData; } private void openEve(MyMarketOrder marketOrder) { OwnerType owner = null; if (marketOrder.isCorporation()) { //Look for issuing owner if (marketOrder.getIssuedBy() != null) { for (OwnerType ownerType : program.getProfileData().getOwners().values()) { //Copy = thread safe if (marketOrder.getIssuedBy() == ownerType.getOwnerID()) { owner = ownerType; if (owner.isOpenWindows()) { break; //Found valid owner - otherwise keep looking } } } } } else { owner = marketOrder.getOwner(); } //Issuer not found if (owner == null) { int value = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), TabsOrders.get().ownerNotFoundMsg(), TabsOrders.get().ownerNotFoundTitle(), JOptionPane.OK_CANCEL_OPTION); if (value != JOptionPane.OK_OPTION) { return; } owner = JMenuUI.selectOwner(program, JMenuUI.EsiOwnerRequirement.OPEN_WINDOW); if (owner == null) { return; } } //Issuer missing scope if (!owner.isOpenWindows()) { int value = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), TabsOrders.get().ownerInvalidScopeMsg(), TabsOrders.get().ownerInvalidScopeTitle(), JOptionPane.OK_CANCEL_OPTION); if (value != JOptionPane.OK_OPTION) { return; } owner = JMenuUI.selectOwner(program, JMenuUI.EsiOwnerRequirement.OPEN_WINDOW); if (owner == null) { return; } } if (!(owner instanceof EsiOwner)) { return; } EsiOwner esiOwner = (EsiOwner) owner; if (marketOrder.isOutbid()) { copy(marketOrder, marketOrder.getOutbidPrice()); } JMenuUI.openMarketDetails(program, esiOwner, marketOrder.getTypeID(), false); } private static void copy(MyMarketOrder marketOrder, Double price) { if (price != null) { if (marketOrder.isBuyOrder()) { price = significantIncrement(price); } else { //Sell price = significantDecrement(price); } String copy = Formatter.copyFormat(price); CopyHandler.toClipboard(copy); setClipboardData(copy); } else { setClipboardData(TabsOrders.get().none()); } } private void updateDates() { Date nextUpdate = Settings.get().getPublicMarketOrdersNextUpdate(); if (Updatable.isUpdatable(nextUpdate)) { jUpdate.setText(TabsOrders.get().updateOutbidEsi()); jUpdate.setEnabled(true); } else { long diff = nextUpdate.getTime() - System.currentTimeMillis(); if (diff < 1000) { jUpdate.setText(TabsOrders.get().updateOutbidWhen("...")); } else { jUpdate.setText(TabsOrders.get().updateOutbidWhen(Formatter.milliseconds(diff, false, false, true, true, true, true))); } jUpdate.setEnabled(false); } Date lastEsiUpdate = Settings.get().getPublicMarketOrdersLastUpdate(); update(jLastEsiUpdate, lastEsiUpdate, Images.MISC_ESI); Date logUpdate = getLastLogUpdate(); update(jLastLogUpdate, logUpdate, Images.FILTER_LOAD); jClipboard.setText(getClipboardData()); } private void update(JLabel jLastUpdate, Date lastUpdate, Images images) { if (lastUpdate != null) { long diff = Math.abs(System.currentTimeMillis() - lastUpdate.getTime()); long diffMinutes = diff / (60 * 1000) % 60; jLastUpdate.setOpaque(true); if (diffMinutes < 2) { jLastUpdate.setIcon(new IconColorIcon(Colors.STRONG_GREEN.getColor(), images.getImage())); ColorSettings.config(jLastUpdate, ColorEntry.GLOBAL_ENTRY_VALID); } else if (diffMinutes < 5) { jLastUpdate.setIcon(new IconColorIcon(Colors.STRONG_YELLOW.getColor(), images.getImage())); ColorSettings.config(jLastUpdate, ColorEntry.GLOBAL_ENTRY_WARNING); } else { jLastUpdate.setIcon(new IconColorIcon(Colors.STRONG_RED.getColor(), images.getImage())); ColorSettings.config(jLastUpdate, ColorEntry.GLOBAL_ENTRY_INVALID); } jLastUpdate.setText(Formatter.milliseconds(diff, false, false, true, true, true, true)); } else { jLastUpdate.setOpaque(false); jLastUpdate.setIcon(images.getIcon()); jLastUpdate.setText(TabsOrders.get().none()); } } private void updateESI() { timer.stop(); jUpdate.setText(TabsOrders.get().updateOutbidUpdating()); jUpdate.setEnabled(false); OutbidProcesserInput input = new OutbidProcesserInput(program.getProfileData(), Settings.get().getOutbidOrderRange()); if (input.getRegionIDs().isEmpty()) { LOG.info("no active orders found"); updateDates(); JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsOrders.get().updateNoActiveMsg(), TabsOrders.get().updateNoActiveTitle(), JOptionPane.PLAIN_MESSAGE); return; } final Date currentUpdate = Settings.get().getPublicMarketOrdersNextUpdate(); OutbidProcesserOutput output = new OutbidProcesserOutput(); final PublicMarketOrdersUpdateTask updateTask = new PublicMarketOrdersUpdateTask(input, output); TaskDialog taskDialog = new TaskDialog(program, updateTask, false, false, false, StatusPanel.UpdateType.PUBLIC_MARKET_ORDERS, new TaskDialog.TasksCompletedAdvanced() { @Override public void tasksCompleted(TaskDialog taskDialog) { //Set data Settings.lock("Outbid (ESI)"); Settings.get().setMarketOrdersOutbid(output.getOutbids()); Settings.unlock("Outbid (ESI)"); //Ensure we don't update repeatedly on errors if (Settings.get().getPublicMarketOrdersNextUpdate().equals(currentUpdate)) { //if next update did not change, set the next update to be 5 minutes in the future Settings.get().setPublicMarketOrdersNextUpdate(new Date(System.currentTimeMillis() + (1000 * 60 * 5))); } //Update eventlists if (!output.getOutbids().isEmpty() || !output.getUpdates().isEmpty()) { LOG.info("Updating Orders EventList"); program.updateMarketOrders(output); } //Save Settings if (!output.getOutbids().isEmpty()) { LOG.info("Saving Settings"); program.saveSettings("Marketlog"); } //Save Profile if (!output.getUpdates().isEmpty()) { LOG.info("Saving Profile"); program.saveTable(ProfileDatabase.Table.MARKET_ORDERS); } //Update time again timer.start(); Program.ensureEDT(new Runnable() { @Override public void run() { //Sell Order Range jSellOrderRangeLast.setText(TabsOrders.get().sellOrderRangeSelcted(Settings.get().getOutbidOrderRange().toString())); //Last Update updateDates(); } }); //Play sound SoundPlayer.play(SoundOption.OUTBID_UPDATE_COMPLETED); SoundPlayer.playAt(Settings.get().getPublicMarketOrdersNextUpdate(), SoundOption.OUTBID_UPDATE_AVAILABLE); } @Override public void tasksHidden(TaskDialog taskDialog) { if (output.hasUnknownLocations()) { if (showUnknownLocationsWarning) { showUnknownLocationsWarning = false; //Only shown once per run if (StructureUpdateDialog.structuresUpdatable(program)) { //Strctures updatable //Ask to update structures int returnValue = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), TabsOrders.get().unknownLocationsMsg(), TabsOrders.get().unknownLocationsTitle(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if (returnValue == JOptionPane.OK_OPTION) { //Do update structures //Show structures update dialog program.showUpdateStructuresDialog(false); } } else { //Strctures not updatable //Show help text about how to update later JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsOrders.get().unknownLocationsMsgLater(), TabsOrders.get().unknownLocationsTitle(), JOptionPane.PLAIN_MESSAGE); } } } } }); } public static double significantIncrement(double value) { return significantChange(value, +1); } public static double significantDecrement(double value) { return significantChange(value, -1); } private static double significantChange(double value, double change) { int significantFigures; if (value <= 0.0) { return 0.0; } else if (value == 0.01) { if (change > 0) { return 0.02; } else { return 0.01; } } else if (value < 0.1) { significantFigures = SIGNIFICANT_FIGURES - 3; } else if (value < 1.0) { significantFigures = SIGNIFICANT_FIGURES - 2; } else if (value < 10.0) { significantFigures = SIGNIFICANT_FIGURES - 1; } else { significantFigures = SIGNIFICANT_FIGURES; } double log10 = Math.log10(value); if (Math.round(log10) == log10 && value > 10 && change < 0) { //Power of 10 significantFigures++; } double power = Math.pow(10, Math.floor(Math.log10(value)) - significantFigures + 1); //double power = Math.pow(10, Math.floor(Math.log10(value)) - significantFigures); value = value / power; value = value + change; value = value * power; return new BigDecimal(value).setScale(2, RoundingMode.HALF_UP).doubleValue(); } private MyMarketOrder getSelectedMarketOrder() { int index = jTable.getSelectedRow(); if (index < 0 || index >= tableModel.getRowCount()) { return null; } return tableModel.getElementAt(index); } private class OrdersTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { JMenuInfo.marketOrder(jPopupMenu, selectionModel.getSelected()); } @Override public void addToolMenu(JComponent jComponent) { MyMarketOrder marketOrder = getSelectedMarketOrder(); boolean enabled = marketOrder != null && !marketOrder.isESI() && selectionModel.getSelected().size() == 1; JMenu jStatus = new JMenu(TabsOrders.get().status()); jStatus.setIcon(Images.MISC_STATUS.getIcon()); if (!enabled) { jStatus.setIcon(jStatus.getDisabledIcon()); } jComponent.add(jStatus); JRadioButtonMenuItem jMenuItem; for (MarketOrderState state : MarketOrderState.values()) { jMenuItem = new JRadioButtonMenuItem(MyMarketOrder.getStateName(state)); jMenuItem.setEnabled(enabled); jMenuItem.setSelected(enabled && state == marketOrder.getState()); jMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (marketOrder == null || marketOrder.isESI() || marketOrder.getState() == state) { return; } marketOrder.setState(state); tableModel.fireTableDataChanged(); program.saveTable(ProfileDatabase.Table.MARKET_ORDERS); } }); jStatus.add(jMenuItem); } MenuManager.addSeparator(jComponent); } } private class ListenerClass implements ListEventListener, ActionListener { @Override public void listChanged(ListEvent listChanges) { double sellOrdersTotal = 0; double buyOrdersTotal = 0; double toCoverTotal = 0; double escrowTotal = 0; try { filterList.getReadWriteLock().readLock().lock(); for (MyMarketOrder marketOrder : filterList) { if (!marketOrder.isBuyOrder()) { //Sell sellOrdersTotal += marketOrder.getPrice() * marketOrder.getVolumeRemain(); } else { //Buy buyOrdersTotal += marketOrder.getPrice() * marketOrder.getVolumeRemain(); escrowTotal += marketOrder.getEscrow(); toCoverTotal += (marketOrder.getPrice() * marketOrder.getVolumeRemain()) - marketOrder.getEscrow(); } } } finally { filterList.getReadWriteLock().readLock().unlock(); } jSellOrdersTotal.setNumber(sellOrdersTotal); jBuyOrdersTotal.setNumber(buyOrdersTotal); jToCoverTotal.setNumber(toCoverTotal); jEscrowTotal.setNumber(escrowTotal); } @Override public void actionPerformed(ActionEvent e) { if (MarketOrdersAction.UPDATE.name().equals(e.getActionCommand())) { updateDates(); updateESI(); } else if (MarketOrdersAction.ORDER_TYPE.name().equals(e.getActionCommand())) { String value = jOrderType.getItemAt(jOrderType.getSelectedIndex()); fileListener.setBuy(TabsOrders.get().updateOutbidFileBuy().equals(value)); } else if (MarketOrdersAction.ORDER_RANGE.name().equals(e.getActionCommand())) { MarketOrderRange range = jOrderRangeNext.getItemAt(jOrderRangeNext.getSelectedIndex()); Settings.lock("Outbid Range"); Settings.get().setOutbidOrderRange(range); Settings.unlock("Outbid Range"); fileListener.setRange(range); } } } private class MarketOrdersFilterControl extends FilterControl { public MarketOrdersFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("Market Orders Table: " + msg); //Save Market Order Filters and Export Settings } } private static class PublicMarketOrdersUpdateTask extends UpdateTask { private final OutbidProcesserInput input; private final OutbidProcesserOutput output; public PublicMarketOrdersUpdateTask(OutbidProcesserInput input, OutbidProcesserOutput output) { super(DialoguesUpdate.get().publicMarketOrders()); this.input = input; this.output = output; } @Override public void update() { EsiPublicMarketOrdersGetter publicMarketOrdersGetter = new EsiPublicMarketOrdersGetter(this, input, output); publicMarketOrdersGetter.run(); } } public static class IconColorIcon implements Icon { private final Color color; private final Image image; public IconColorIcon(Color color, Image image) { this.color = color; this.image = image; } @Override public void paintIcon(Component c, Graphics g, int x, int y) { Graphics2D g2d = (Graphics2D) g; //Background g2d.setColor(color); g2d.fillRect(x, y, getIconWidth(), getIconHeight()); //Icon g2d.drawImage(image, x+1, y, null); } @Override public int getIconWidth() { return 16; } @Override public int getIconHeight() { return 16; } } private static class FileListener extends Thread { private final Program program; private boolean buy; private MarketOrderRange range; public FileListener(Program program, MarketOrderRange range) { super("FileListener"); this.program = program; this.buy = true; this.range = range; } public synchronized boolean isBuy() { return buy; } public synchronized void setBuy(boolean buy) { this.buy = buy; } public synchronized MarketOrderRange getRange() { return range; } public synchronized void setRange(MarketOrderRange range) { this.range = range; } @Override public void run() { Path dir = MarketLogReader.getMarketlogsDirectory().toPath(); WatchService watcher; while (true) { if (MarketLogReader.getMarketlogsDirectory().exists()) { try { watcher = FileSystems.getDefault().newWatchService(); dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE); break; } catch (IOException ex) { LOG.error(ex.getMessage(), ex); return; } } else { try { Thread.sleep(15000); //Sleep 15 seconds, then tries again } catch (InterruptedException ex1) { //No problem } } } while (true) { WatchKey key; try { LOG.info("waiting for changes..."); key = watcher.take(); LOG.info("change detected"); for (WatchEvent event : key.pollEvents()) { // This key is registered only // for ENTRY_CREATE events, // but an OVERFLOW event can // occur regardless if events // are lost or discarded. WatchEvent.Kind kind = event.kind(); if (kind == OVERFLOW) { LOG.info("Overflow..."); continue; } // The filename is the // context of the event. Object context = event.context(); if (context instanceof Path) { Path path = (Path) context; File file = dir.resolve(path).toFile(); LOG.info("Starting marketlog file processing for " + file.getName()); long start = System.currentTimeMillis(); update(file); LOG.info("Marketlog file processing done in " + Formatter.milliseconds(System.currentTimeMillis() - start) + " for " + file.getName()); } } key.reset(); } catch (InterruptedException ex) { LOG.info("FileListener Interrupted"); } } } private void update(final File file) { OutbidProcesserOutput output = new OutbidProcesserOutput(); boolean updated = update(file, output); if (!updated) { return; } Thread thread = new Thread(new Runnable() { @Override public void run() { LOG.info("Starting marketlog update thread for " + file.getName()); long start = System.currentTimeMillis(); LOG.info("Setting setting"); Settings.lock("Outbids (files)"); Settings.get().setMarketOrdersOutbid(output.getOutbids()); Settings.unlock("Outbids (files)"); //Update eventlists if (!output.getOutbids().isEmpty() || !output.getUpdates().isEmpty()) { LOG.info("Updating Orders EventList"); program.updateMarketOrdersWithProgress(output); } //Save Settings if (!output.getOutbids().isEmpty()) { LOG.info("Saving Settings"); program.saveSettings("Marketlog"); } //Save Profile if (!output.getUpdates().isEmpty()) { LOG.info("Saving Profile"); program.saveTable(ProfileDatabase.Table.MARKET_ORDERS); } LOG.info("Marketlog update thread done in " + Formatter.milliseconds(System.currentTimeMillis() - start) + " for " + file.getName()); } }, file.getName()); thread.start(); } private boolean update(final File file, final OutbidProcesserOutput output) { OutbidProcesserInput input = new OutbidProcesserInput(program.getProfileData(), Settings.get().getOutbidOrderRange()); List marketLogs = MarketLogReader.read(file, input, output); if (marketLogs == null || marketLogs.isEmpty()) { LOG.info("No marketslogs found"); return false; } //Copy to clipart MyMarketOrder marketOrderCopy = null; for (OwnerType ownerType : program.getProfileData().getOwners().values()) { //Copy = thread safe synchronized (ownerType) { for (MyMarketOrder marketOrder : ownerType.getMarketOrders()) { //Synchronized on owner = thread safe if (!Objects.equals(isBuy(), marketOrder.isBuyOrder())) { continue; } Outbid outbid = output.getOutbids().get(marketOrder.getOrderID()); if (outbid != null) { if (marketOrder.isBuyOrder()) { //Outbid and highest buy price if (outbid.getPrice() > marketOrder.getPrice() && (marketOrderCopy == null || marketOrder.getPrice() > marketOrderCopy.getPrice()) ) { marketOrderCopy = marketOrder; } } else { //Outbid and lowest sell price if (outbid.getPrice() < marketOrder.getPrice() && (marketOrderCopy == null || marketOrder.getPrice() < marketOrderCopy.getPrice())) { marketOrderCopy = marketOrder; } } } } } } if (marketOrderCopy != null) { LOG.info("Found matching order"); Outbid outbid = output.getOutbids().get(marketOrderCopy.getOrderID()); if (outbid != null) { //Better safe than sorry copy(marketOrderCopy, outbid.getPrice()); setLastLogUpdate(); return true; } } //Nothing found - going region wide Double price = null; for (MarketLog marketLog : marketLogs) { if (!Objects.equals(isBuy(), marketLog.getBid())) { continue; } if (marketLog.getJumps() > OutbidProcesser.getRange(getRange())) { continue; } if (price == null) { price = marketLog.getPrice(); } else { if (marketLog.getBid()) { price = Math.max(price, marketLog.getPrice()); } else { //Sell price = Math.min(price, marketLog.getPrice()); } } } if (price != null) { LOG.info("Found region price"); if (isBuy()) { price = significantIncrement(price); } else { //Sell price = significantDecrement(price); } String copy = Formatter.copyFormat(price); CopyHandler.toClipboard(copy); setLastLogUpdate(); setClipboardData(copy); return true; } LOG.info("No price found...."); setClipboardData(TabsOrders.get().none()); return false; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/orders/MarketTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.orders; import java.awt.Component; import java.util.Comparator; import java.util.Date; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.LongInt; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.gui.shared.table.containers.YesNo; import net.nikr.eve.jeveasset.i18n.TabsOrders; public enum MarketTableFormat implements EnumTableColumn { ORDER_TYPE(String.class) { @Override public String getColumnName() { return TabsOrders.get().columnOrderType(); } @Override public Object getColumnValue(final MyMarketOrder from) { if (!from.isBuyOrder()) { return TabsOrders.get().sell(); } else { return TabsOrders.get().buy(); } } }, NAME(String.class) { @Override public String getColumnName() { return TabsOrders.get().columnName(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getItem().getTypeName(); } }, GROUP(String.class) { @Override public String getColumnName() { return TabsOrders.get().columnGroup(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getItem().getGroup(); } }, CATEGORY(String.class) { @Override public String getColumnName() { return TabsOrders.get().columnCategory(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getItem().getCategory(); } }, QUANTITY(Integer.class) { @Override public String getColumnName() { return TabsOrders.get().columnVolumeRemain(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getVolumeRemain(); } }, QUANTITY_ENTERED(Integer.class) { @Override public String getColumnName() { return TabsOrders.get().columnVolumeTotal(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getVolumeTotal(); } }, PRICE(Double.class) { @Override public String getColumnName() { return TabsOrders.get().columnPrice(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getPrice(); } }, OUTBID_PRICE(Double.class) { @Override public String getColumnName() { return TabsOrders.get().columnOutbidPrice(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnOutbidPriceToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getOutbidPrice(); } }, OUTBID_COUNT(Long.class) { @Override public String getColumnName() { return TabsOrders.get().columnOutbidCount(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnOutbidCountToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getOutbidCount(); } }, OUTBID_DELTA(Double.class) { @Override public String getColumnName() { return TabsOrders.get().columnOutbidDelta(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnOutbidDeltaToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getOutbidDelta(); } }, EVE_UI(Component.class) { @Override public String getColumnName() { return TabsOrders.get().columnEveUi(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnEveUiToolTip(); } @Override public boolean isColumnEditable(Object baseObject) { return true; } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getButton(); } }, BROKERS_FEE(Double.class) { @Override public String getColumnName() { return TabsOrders.get().columnBrokersFee(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnBrokersFeeToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getBrokersFee(); } }, EDITS(Integer.class) { @Override public String getColumnName() { return TabsOrders.get().columnEdits(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnEditsToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getEdits(); } }, PRICE_REPROCESSED(Double.class) { @Override public String getColumnName() { return TabsOrders.get().columnPriceReprocessed(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getPriceReprocessed(); } }, PRICE_MANUFACTURING(Double.class) { @Override public String getColumnName() { return TabsOrders.get().columnPriceManufacturing(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnPriceManufacturingToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getItem().getPriceManufacturing(); } }, ISSUED(Date.class) { @Override public String getColumnName() { return TabsOrders.get().columnIssued(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnIssuedToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getIssued(); } }, ISSUED_FIRST(Date.class) { @Override public String getColumnName() { return TabsOrders.get().columnIssuedFirst(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnIssuedFirstToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getCreatedOrIssued(); } }, EXPIRES(Date.class) { @Override public String getColumnName() { return TabsOrders.get().columnExpires(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getExpires(); } }, CHANGED(Date.class) { @Override public String getColumnName() { return TabsOrders.get().columnChanged(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnChangedToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getChanged(); } }, RANGE(String.class) { @Override public String getColumnName() { return TabsOrders.get().columnRange(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getRange().toString(); } }, STATUS(String.class) { @Override public String getColumnName() { return TabsOrders.get().columnStatus(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getStateFormatted(); } }, MIN_VOLUME(Integer.class) { @Override public String getColumnName() { return TabsOrders.get().columnMinimumQuantity(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getMinVolume(); } }, OWNER(String.class) { @Override public String getColumnName() { return TabsOrders.get().columnOwner(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getOwnerName(); } }, ISSUED_BY(String.class) { @Override public String getColumnName() { return TabsOrders.get().columnIssuedBy(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getIssuedByName(); } }, OWNED(YesNo.class) { @Override public String getColumnName() { return TabsOrders.get().columnOwned(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnOwnedToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return YesNo.get(from.isOwned()); } }, WalletDivision(Integer.class) { @Override public String getColumnName() { return TabsOrders.get().columnWalletDivision(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getWalletDivision(); } }, LOCATION(String.class) { @Override public String getColumnName() { return TabsOrders.get().columnLocation(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getLocation().getLocation(); } }, SYSTEM(String.class) { @Override public String getColumnName() { return TabsOrders.get().columnSystem(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getLocation().getSystem(); } }, CONSTELLATION(String.class) { @Override public String getColumnName() { return TabsOrders.get().columnConstellation(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getLocation().getConstellation(); } }, REGION(String.class) { @Override public String getColumnName() { return TabsOrders.get().columnRegion(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getLocation().getRegion(); } }, VALUE(Double.class) { @Override public String getColumnName() { return TabsOrders.get().columnRemainingValue(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getVolumeRemain() * from.getPrice(); } }, TRANSACTION_PRICE(Double.class) { @Override public String getColumnName() { return TabsOrders.get().columnTransactionPrice(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnTransactionPriceToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getTransactionPrice(); } }, TRANSACTION_MARGIN(Double.class) { @Override public String getColumnName() { return TabsOrders.get().columnTransactionMargin(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnTransactionMarginToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getTransactionMargin(); } }, TRANSACTION_PROFIT(Double.class) { @Override public String getColumnName() { return TabsOrders.get().columnTransactionProfitDifference(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnTransactionProfitDifferenceToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getTransactionProfitDifference(); } }, TRANSACTION_PROFIT_PERCENT(Percent.class) { @Override public String getColumnName() { return TabsOrders.get().columnTransactionProfitPercent(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnTransactionProfitPercentToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getTransactionProfitPercent(); } }, MARKET_PRICE(Double.class) { @Override public String getColumnName() { return TabsOrders.get().columnMarketPrice(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnMarketPriceToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getDynamicPrice(); } }, MARKET_PRICE_SELL_MIN(Double.class) { @Override public String getColumnName() { return TabsOrders.get().columnMarketPriceSellMin(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnMarketPriceSellMinToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getPriceSellMin(); } }, MARKET_PRICE_BUY_MAX(Double.class) { @Override public String getColumnName() { return TabsOrders.get().columnMarketPriceBuyMax(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnMarketPriceBuyMaxToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getPriceBuyMax(); } }, MARKET_MARGIN(Percent.class) { @Override public String getColumnName() { return TabsOrders.get().columnMarketMargin(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnMarketMarginToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return Percent.create(from.getMarketMargin()); } }, MARKET_PROFIT(Double.class) { @Override public String getColumnName() { return TabsOrders.get().columnMarketProfit(); } @Override public String getColumnToolTip() { return TabsOrders.get().columnMarketProfitToolTip(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getMarketProfit(); } }, VOLUME(Float.class) { @Override public String getColumnName() { return TabsOrders.get().columnVolume(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getItem().getVolumePackaged(); } }, TYPE_ID(Integer.class) { @Override public String getColumnName() { return TabsOrders.get().columnTypeID(); } @Override public Object getColumnValue(final MyMarketOrder from) { return from.getTypeID(); } }, ORDER_ID(LongInt.class) { @Override public String getColumnName() { return TabsOrders.get().columnOrderID(); } @Override public Object getColumnValue(final MyMarketOrder from) { return new LongInt(from.getOrderID()); } @Override public boolean isShowDefault() { return false; } }; private final Class type; private final Comparator comparator; private MarketTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/orders/Outbid.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.orders; import net.nikr.eve.jeveasset.data.api.raw.RawPublicMarketOrder; public class Outbid { private Double price; private long count; public Outbid(Double price, long count) { this.price = price; this.count = count; } public Outbid(RawPublicMarketOrder ordersResponse) { this.price = ordersResponse.getPrice(); this.count = 0; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } public long getCount() { return count; } public void addCount(long count) { this.count = this.count + count; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/orders/OutbidProcesser.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.orders; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.MarketOrderRange; import net.nikr.eve.jeveasset.data.api.raw.RawPublicMarketOrder; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.RouteFinder; import net.nikr.eve.jeveasset.data.sde.RouteFinder.RouteFinderFilter; import net.nikr.eve.jeveasset.data.settings.Citadel; import net.nikr.eve.jeveasset.io.online.CitadelGetter; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.troja.eve.esi.api.MarketApi; import net.troja.eve.esi.api.UniverseApi; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class OutbidProcesser { private static final Logger LOG = LoggerFactory.getLogger(OutbidProcesser.class); private final OutbidProcesserInput input; private final OutbidProcesserOutput output; private OutbidProcesser(OutbidProcesserInput input, OutbidProcesserOutput output) { this.input = input; this.output = output; } public static void process(OutbidProcesserInput input, OutbidProcesserOutput output) { OutbidProcesser processer = new OutbidProcesser(input, output); processer.process(); } private void process() { //Process order updates for (RawPublicMarketOrder ordersResponse : input.getMarketOrders()) { Set orders = input.getTypeIDs().get(ordersResponse.getTypeID()); if (orders != null) { for (MyMarketOrder marketOrder : orders) { if (isSameOrder(marketOrder, ordersResponse)) { //Orders to be updated output.getUpdates().put(ordersResponse.getOrderID(), ordersResponse); } } } } //Process outbid for (RawPublicMarketOrder ordersResponse : input.getMarketOrders()) { //Regions with data MyLocation orderLocation = ApiIdConverter.getLocation(ordersResponse.getSystemID()); if (!orderLocation.isEmpty()) { output.getRegionIDs().add(orderLocation.getRegionID()); } Set orders = input.getTypeIDs().get(ordersResponse.getTypeID()); if (orders != null) { //Orders to match for (MyMarketOrder marketOrder : orders) { if (isSameOrder(marketOrder, ordersResponse)) { //Orders to be updated continue; } if (!isSameType(marketOrder, ordersResponse)) { //Both buy or both sell continue; } if (!isInRange(marketOrder, ordersResponse)) { //Order range overlap continue; } Outbid outbid = output.getOutbids().get(marketOrder.getOrderID()); if (outbid == null) { outbid = new Outbid(ordersResponse); output.getOutbids().put(marketOrder.getOrderID(), outbid); } RawPublicMarketOrder rawPublicMarketOrder = output.getUpdates().get(marketOrder.getOrderID()); final double price; final Date issued; if (rawPublicMarketOrder != null) { //Updated price/issued price = rawPublicMarketOrder.getPrice(); issued = rawPublicMarketOrder.getIssued(); } else { //Old price/issued (better than nothing) price = marketOrder.getPrice(); issued = marketOrder.getIssued(); } if (marketOrder.isBuyOrder()) { //Buy (outbid is higher) outbid.setPrice(Math.max(outbid.getPrice(), ordersResponse.getPrice())); if (ordersResponse.getPrice() > price || (ordersResponse.getPrice() == price && ordersResponse.getIssued().before(issued))) { outbid.addCount(ordersResponse.getVolumeRemain()); } } else { //Sell (outbid is lower) outbid.setPrice(Math.min(outbid.getPrice(), ordersResponse.getPrice())); if (ordersResponse.getPrice() < price || (ordersResponse.getPrice() == price && ordersResponse.getIssued().before(issued))) { outbid.addCount(ordersResponse.getVolumeRemain()); } else if (ordersResponse.getPrice() == price) { //TODO matching price, compare date? } } } } } CitadelGetter.set(input.getCitadels().values()); } private boolean isInRange(MyMarketOrder fromMarketOrder, RawPublicMarketOrder toMarketOrder) { Long fromSystemID = getSystemID(fromMarketOrder.getLocationID()); Long toSystemID = RawConverter.toLong(toMarketOrder.getSystemID()); MyLocation fromSystemLocation = ApiIdConverter.getLocation(fromSystemID); MyLocation toSystemLocation = ApiIdConverter.getLocation(toSystemID); if (fromSystemLocation.isEmpty() || toSystemLocation.isEmpty()) { LOG.warn("Unknown market location ignored"); output.setUnknownLocations(); return false; //We can't work with unknown locations } if (!Objects.equals(fromSystemLocation.getRegionID(), toSystemLocation.getRegionID())) { return false; //Must be in same region } MarketOrderRange fromRange; MarketOrderRange toRange; if (fromMarketOrder.isBuyOrder()) { fromRange = fromMarketOrder.getRange(); toRange = toMarketOrder.getRange(); } else { fromRange = input.getSellOrderRange(); toRange = input.getSellOrderRange(); } if (fromRange == MarketOrderRange.REGION || toRange == MarketOrderRange.REGION) { return true; //Match everything } else if (fromRange == MarketOrderRange.STATION && toRange == MarketOrderRange.STATION) { return Objects.equals(fromMarketOrder.getLocationID(), toMarketOrder.getLocationID()); //Only match if in the same station } else { int range = getRange(fromRange) + getRange(toRange); //Find overlapping area //int range = Math.max(getRange(response), getRange(marketOrder)); //Use the order with the max range Integer distance = RouteFinder.get().distanceBetween(RouteFinderFilter.MARKET_ORDERS, fromSystemID, toSystemID); if (distance == null) { return false; } return distance <= range; } } public static int getRange(MarketOrderRange range) { switch (range) { case REGION: return 32767; case SOLARSYSTEM: return 0; case STATION: return 0; case _1: return 1; case _2: return 2; case _3: return 3; case _4: return 4; case _5: return 5; case _10: return 10; case _20: return 20; case _30: return 30; case _40: return 40; } return Integer.MAX_VALUE; } private boolean isSameType(MyMarketOrder marketOrder, RawPublicMarketOrder response) { return Objects.equals(marketOrder.isBuyOrder(), response.isBuyOrder()); } private boolean isSameOrder(MyMarketOrder marketOrder, RawPublicMarketOrder response) { return Objects.equals(marketOrder.getOrderID(), response.getOrderID()); } private Long getSystemID(long locationID) { Long systemID = input.getLocationToSystem().get(locationID); if (systemID != null) { return systemID; } MyLocation location = ApiIdConverter.getLocation(locationID); if (!location.isEmpty()) { return location.getSystemID(); } Citadel citadel = input.getCitadels().get(locationID); if (citadel != null) { return citadel.getSystemID(); } LOG.warn("Unknown market location"); return null; } public static class OutbidProcesserInput { private static final Map MARKET_ORDERS = Collections.synchronizedMap(new HashMap<>()); private final Map locationToSystem = new HashMap<>(); private final Map citadels = new HashMap<>(); private final Map> typeIDs = new HashMap<>(); private final Set structureIDs = new HashSet<>(); private final Set regionIDs = new HashSet<>(); private final MarketOrderRange sellOrderRange; private UniverseApi structuresApi = null; private MarketApi marketApi = null; public OutbidProcesserInput(ProfileData profileData, MarketOrderRange sellOrderRange) { this.sellOrderRange = sellOrderRange; for (OwnerType ownerType : profileData.getOwners().values()) { //Copy = thread safe synchronized (ownerType) { for (MyMarketOrder marketOrder : ownerType.getMarketOrders()) { //Synchronized on owner = thread safe if (marketOrder.isActive()) { //StructuresIDs if (marketOrder.getLocationID() > 100000000) { structureIDs.add(marketOrder.getLocationID()); } //TypeIDs Set set = typeIDs.get(marketOrder.getTypeID()); if (set == null) { set = new HashSet<>(); typeIDs.put(marketOrder.getTypeID(), set); } set.add(marketOrder); //RegionIDs Integer regionID = marketOrder.getRegionID(); if (regionID != null && ((regionID >= 10000000 && regionID <= 13000000) || regionID == 19000001)) { regionIDs.add(regionID); } } } } } for (OwnerType ownerType : profileData.getOwners().values()) { //Copy = thread safe if (ownerType instanceof EsiOwner) { EsiOwner esiOwner = (EsiOwner) ownerType; if (!esiOwner.isShowOwner() || esiOwner.isInvalid()) { continue; //Ignore hidden and invalid owners } if (esiOwner.isStructures()) { structuresApi = esiOwner.getUniverseApiAuth(); } if (esiOwner.isMarketStructures()) { marketApi = esiOwner.getMarketApiAuth(); } } } } public void addOrders(Map> orders, Date date) { if (date == null) { return; } synchronized (MARKET_ORDERS) { for (Map.Entry> entry : orders.entrySet()) { DatedMarketOrders datedMarketOrders = MARKET_ORDERS.get(entry.getKey()); if (datedMarketOrders != null && datedMarketOrders.getDate().after(date)) { return; //Current is newer } datedMarketOrders = new DatedMarketOrders(date, entry.getValue()); MARKET_ORDERS.put(entry.getKey(), datedMarketOrders); } } } public List getMarketOrders() { List marketOrders = new ArrayList<>(); synchronized (MARKET_ORDERS) { for (DatedMarketOrders datedMarketOrders : MARKET_ORDERS.values()) { marketOrders.addAll(datedMarketOrders.getMarketOrders()); } } return marketOrders; } public Map getLocationToSystem() { return locationToSystem; } public Map getCitadels() { return citadels; } public Map> getTypeIDs() { return typeIDs; } public Set getStructureIDs() { return structureIDs; } public Set getRegionIDs() { return regionIDs; } public MarketOrderRange getSellOrderRange() { return sellOrderRange; } public UniverseApi getStructuresApi() { return structuresApi; } public MarketApi getMarketApi() { return marketApi; } } public static class OutbidProcesserOutput { private final Map outbids = new HashMap<>(); private final Map updates = new HashMap<>(); private final Set regionIDs = new HashSet<>(); private boolean unknownLocations = false; public Map getOutbids() { return outbids; } public Map getUpdates() { return updates; } public Set getRegionIDs() { return regionIDs; } public boolean hasUnknownLocations() { return unknownLocations; } public void setUnknownLocations() { this.unknownLocations = true; } } private static class DatedMarketOrders { private final Date date; private final Set marketOrders; public DatedMarketOrders(Date date, Set marketOrders) { this.date = date; this.marketOrders = marketOrders; } public Date getDate() { return date; } public Set getMarketOrders() { return marketOrders; } @Override public int hashCode() { int hash = 7; hash = 47 * hash + Objects.hashCode(this.date); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final DatedMarketOrders other = (DatedMarketOrders) obj; if (!Objects.equals(this.date, other.date)) { return false; } return true; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/overview/JOverviewMenu.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.overview; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; import java.util.Map; import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.JOptionInput; import net.nikr.eve.jeveasset.i18n.TabsOverview; public class JOverviewMenu extends JMenu { private enum OverviewMenu { RENAME, DELETE, NEW } private final Program program; private final OverviewTab overviewTab; private final AddToGroup addToGroup = new AddToGroup(); private final RemoveFromGroup removeFromGroup = new RemoveFromGroup(); public JOverviewMenu(Program program, OverviewTab overviewTab, List selected) { super(TabsOverview.get().groups()); this.program = program; this.overviewTab = overviewTab; this.setIcon(Images.LOC_GROUPS.getIcon()); ListenerClass listener = new ListenerClass(); JMenuItem jMenuItem; JCheckBoxMenuItem jCheckBoxMenuItem; //Station, System, Region views if (overviewTab.getSelectedView() != OverviewTab.View.GROUPS) { jMenuItem = new JMenuItem(TabsOverview.get().add()); jMenuItem.setIcon(Images.EDIT_ADD.getIcon()); jMenuItem.setEnabled(!selected.isEmpty()); jMenuItem.setActionCommand(OverviewMenu.NEW.name()); jMenuItem.addActionListener(listener); this.add(jMenuItem); if (!Settings.get().getOverviewGroups().isEmpty()) { this.addSeparator(); } for (Map.Entry entry : Settings.get().getOverviewGroups().entrySet()) { OverviewGroup overviewGroup = entry.getValue(); boolean found = overviewGroup.getLocations().containsAll(overviewTab.getSelectedLocations()); jCheckBoxMenuItem = new JCheckBoxMenuItem(overviewGroup.getName()); if (overviewTab.getSelectedView() == OverviewTab.View.PLANETS) { jCheckBoxMenuItem.setIcon(Images.LOC_PLANET.getIcon()); } else if (overviewTab.getSelectedView() == OverviewTab.View.STATIONS) { jCheckBoxMenuItem.setIcon(Images.LOC_STATION.getIcon()); } else if (overviewTab.getSelectedView() == OverviewTab.View.SYSTEMS) { jCheckBoxMenuItem.setIcon(Images.LOC_SYSTEM.getIcon()); } else if (overviewTab.getSelectedView() == OverviewTab.View.CONSTELLATIONS) { jCheckBoxMenuItem.setIcon(Images.LOC_CONSTELLATION.getIcon()); } else if (overviewTab.getSelectedView() == OverviewTab.View.REGIONS) { jCheckBoxMenuItem.setIcon(Images.LOC_REGION.getIcon()); } jCheckBoxMenuItem.setEnabled(!selected.isEmpty()); jCheckBoxMenuItem.setActionCommand(overviewGroup.getName()); jCheckBoxMenuItem.addActionListener(addToGroup); jCheckBoxMenuItem.setSelected(found); this.add(jCheckBoxMenuItem); } } //Groups view if (overviewTab.getSelectedView() == OverviewTab.View.GROUPS) { jMenuItem = new JMenuItem(TabsOverview.get().renameGroup()); jMenuItem.setIcon(Images.EDIT_RENAME.getIcon()); jMenuItem.setEnabled(selected.size() == 1); jMenuItem.setActionCommand(OverviewMenu.RENAME.name()); jMenuItem.addActionListener(listener); this.add(jMenuItem); jMenuItem = new JMenuItem(TabsOverview.get().deleteGroup()); jMenuItem.setIcon(Images.EDIT_DELETE.getIcon()); jMenuItem.setEnabled(selected.size() == 1); jMenuItem.setActionCommand(OverviewMenu.DELETE.name()); jMenuItem.addActionListener(listener); this.add(jMenuItem); if (selected.size() == 1) { //Add the group locations Overview overview = selected.get(0); OverviewGroup overviewGroup = Settings.get().getOverviewGroups().get(overview.getName()); if (overviewGroup != null) { if (!overviewGroup.getLocations().isEmpty()) { this.addSeparator(); } for (OverviewLocation location : overviewGroup.getLocations()) { jCheckBoxMenuItem = new JCheckBoxMenuItem(location.getName()); if (location.isPlanet()) { jCheckBoxMenuItem.setIcon(Images.LOC_PLANET.getIcon()); } if (location.isStation()) { jCheckBoxMenuItem.setIcon(Images.LOC_STATION.getIcon()); } if (location.isSystem()) { jCheckBoxMenuItem.setIcon(Images.LOC_SYSTEM.getIcon()); } if (location.isConstellation()) { jCheckBoxMenuItem.setIcon(Images.LOC_CONSTELLATION.getIcon()); } if (location.isRegion()) { jCheckBoxMenuItem.setIcon(Images.LOC_REGION.getIcon()); } jCheckBoxMenuItem.setActionCommand(location.getName()); jCheckBoxMenuItem.addActionListener(removeFromGroup); jCheckBoxMenuItem.setSelected(true); this.add(jCheckBoxMenuItem); } } } } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(ActionEvent e) { //Group if (OverviewMenu.NEW.name().equals(e.getActionCommand())) { String value = JOptionInput.showInputDialog(program.getMainWindow().getFrame(), TabsOverview.get().groupName(), TabsOverview.get().addGroup(), JOptionPane.PLAIN_MESSAGE); if (value != null) { Settings.lock("Overview Groups (New)"); //Lock for Overview Groups (New) OverviewGroup overviewGroup = new OverviewGroup(value); Settings.get().getOverviewGroups().put(overviewGroup.getName(), overviewGroup); overviewGroup.addAll(overviewTab.getSelectedLocations()); overviewTab.updateTable(); Settings.unlock("Overview Groups (New)"); //Unlock for Overview Groups (New) program.saveSettings("Overview Groups (New)"); //Save Overview Groups (New) } } if (OverviewMenu.DELETE.name().equals(e.getActionCommand())) { OverviewGroup overviewGroup = overviewTab.getSelectGroup(); int value = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), TabsOverview.get().deleteTheGroup(overviewGroup.getName()), TabsOverview.get().deleteGroup(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (value == JOptionPane.OK_OPTION) { Settings.lock("Overview Groups (Delete)"); //Lock for Overview Groups (Delete) Settings.get().getOverviewGroups().remove(overviewGroup.getName()); overviewTab.updateTable(); Settings.unlock("Overview Groups (Delete)"); //Unlock for Overview Groups (Delete) program.saveSettings("Overview Groups (Delete)"); //Save Overview Groups (Delete) } } if (OverviewMenu.RENAME.name().equals(e.getActionCommand())) { OverviewGroup overviewGroup = overviewTab.getSelectGroup(); String value = (String) JOptionInput.showInputDialog(program.getMainWindow().getFrame(), TabsOverview.get().groupName(), TabsOverview.get().renameGroup(), JOptionPane.PLAIN_MESSAGE, null, null, overviewGroup.getName()); if (value != null) { Settings.lock("Overview Groups (Rename)"); //Lock for Overview Groups (Rename) Settings.get().getOverviewGroups().remove(overviewGroup.getName()); overviewGroup.setName(value); Settings.get().getOverviewGroups().put(overviewGroup.getName(), overviewGroup); overviewTab.updateTable(); Settings.unlock("Overview Groups (Rename)"); //Unlock for Overview Groups (Rename) program.saveSettings("Overview Groups (Rename)"); //Save Overview Groups (Rename) } } } } class AddToGroup implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { OverviewGroup overviewGroup = Settings.get().getOverviewGroups().get(e.getActionCommand()); if (overviewGroup != null) { List locations = overviewTab.getSelectedLocations(); if (overviewGroup.getLocations().containsAll(locations)) { overviewGroup.removeAll(locations); } else { //Remove overviewGroup.addAll(locations); } overviewTab.updateTable(); } } } class RemoveFromGroup implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { OverviewGroup overviewGroup = overviewTab.getSelectGroup(); String location = e.getActionCommand(); overviewGroup.remove(new OverviewLocation(location)); overviewTab.updateTable(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/overview/JOverviewTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.overview; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import java.util.ArrayList; import java.util.List; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; class JOverviewTable extends JAutoColumnTable { private List groupedLocations = new ArrayList<>(); private final DefaultEventTableModel tableModel; public JOverviewTable(final Program program, final DefaultEventTableModel tableModel) { super(program, tableModel); this.tableModel = tableModel; } public void setGroupedLocations(final List groupedLocations) { this.groupedLocations = groupedLocations; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); boolean isSelected = isCellSelected(row, column); Overview overview = tableModel.getElementAt(row); String columnName = (String) this.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); //User set location if (columnName.equals(OverviewTableFormat.NAME.getColumnName())) { if (groupedLocations.contains(overview.getName())) { //In group ColorSettings.configCell(component, ColorEntry.OVERVIEW_GROUPED_LOCATIONS, isSelected); return component; } else if (overview.getLocation().isUserLocation()) { ColorSettings.configCell(component, ColorEntry.CUSTOM_USER_LOCATION, isSelected); return component; } } if (groupedLocations.contains(overview.getLocation().getSystem()) && columnName.equals(OverviewTableFormat.SYSTEM.getColumnName())) { //In group ColorSettings.configCell(component, ColorEntry.OVERVIEW_GROUPED_LOCATIONS, isSelected); return component; } if (groupedLocations.contains(overview.getLocation().getRegion()) && columnName.equals(OverviewTableFormat.REGION.getColumnName())) { //In group ColorSettings.configCell(component, ColorEntry.OVERVIEW_GROUPED_LOCATIONS, isSelected); return component; } return component; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/overview/Overview.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.overview; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; public class Overview implements Comparable, JMenuInfo.InfoItem, LocationType { private final String name; private final MyLocation location; //New objects are created by updateData() - no need to update private double valueReprocessed; private double volume; private long count; private double value; public Overview(final String name, final MyLocation location, final double valueReprocessed, final double volume, final long count, final double value) { this.name = name; this.location = location; this.valueReprocessed = valueReprocessed; this.volume = volume; this.count = count; this.value = value; } public double getAverageValue() { if (value > 0 && count > 0) { return value / count; } else { return 0; } } @Override public long getCount() { return count; } @Override public MyLocation getLocation() { return location; } public String getName() { return name; } @Override public double getValueReprocessed() { return valueReprocessed; } @Override public double getValue() { return value; } @Override public double getVolumeTotal() { return volume; } public double getValuePerVolume() { if (getVolumeTotal() > 0 && getValue() > 0) { return getValue() / getVolumeTotal(); } else { return 0; } } public void addCount(final long addCount) { this.count = this.count + addCount; } public void addValue(final double addValue) { this.value = this.value + addValue; } public void addVolume(final double addVolume) { this.volume = this.volume + addVolume; } public void addReprocessedValue(final double addReprocessedValue) { this.valueReprocessed = this.valueReprocessed + addReprocessedValue; } @Override public int compareTo(final Overview o) { return this.name.compareToIgnoreCase(o.getName()); } @Override public boolean equals(final Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Overview other = (Overview) obj; if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { return false; } return true; } @Override public int hashCode() { int hash = 7; hash = 43 * hash + (this.name != null ? this.name.hashCode() : 0); return hash; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/overview/OverviewData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.overview; import ca.odell.glazedlists.EventList; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.profile.TableData; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab.View; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class OverviewData extends TableData { private final List groupedLocations = new ArrayList<>(); private int rowCount; public OverviewData(Program program) { super(program); } public OverviewData(ProfileManager profileManager, ProfileData profileData) { super(profileManager, profileData); } public EventList getData(final Collection assets, final String owner, final View view) { EventList eventList = EventListManager.create(); updateData(eventList, assets, owner, view); return eventList; } public void updateData(EventList eventList, final Collection assets, String owner, final View view) { if (owner == null || owner.isEmpty()) { owner = General.get().all(); } groupedLocations.clear(); List locations = new ArrayList<>(); Map locationsMap = new HashMap<>(); rowCount = 0; if (view == OverviewTab.View.GROUPS) { //Add all groups for (Map.Entry entry : Settings.get().getOverviewGroups().entrySet()) { OverviewGroup overviewGroup = entry.getValue(); if (!locationsMap.containsKey(overviewGroup.getName())) { //Create new overview Overview overview = new Overview(overviewGroup.getName(), MyLocation.create(0), 0, 0, 0, 0); locationsMap.put(overviewGroup.getName(), overview); locations.add(overview); } } } else { //Add all grouped locations for (Map.Entry entry : Settings.get().getOverviewGroups().entrySet()) { OverviewGroup overviewGroup = entry.getValue(); for (OverviewLocation overviewLocation : overviewGroup.getLocations()) { if (!groupedLocations.contains(overviewLocation.getName())) { groupedLocations.add(overviewLocation.getName()); } } } } final boolean all = owner.equals(General.get().all()); for (MyAsset asset : assets) { if (asset.getItem().isContainer() && Settings.get().isIgnoreSecureContainers()) { continue; } if (asset.getItem().getGroup().equals(Item.GROUP_STATION_SERVICES)) { continue; } //Filters if (!owner.equals(asset.getOwnerName()) && !all) { continue; } rowCount++; double reprocessedValue = asset.getValueReprocessed(); double value = asset.getValue(); long count = asset.getCount(); double volume = asset.getVolumeTotal(); if (view != View.GROUPS) { //Locations String locationName = ""; MyLocation location = asset.getLocation(); if (view == View.STATIONS && location.isPlanet()) { continue; } if (view == View.PLANETS && !location.isPlanet()) { continue; } if (!location.isEmpty()) { //Always use the default location for empty locations if (view == View.REGIONS) { locationName = asset.getLocation().getRegion(); location = ApiIdConverter.getLocation(asset.getLocation().getRegionID()); } else if (view == View.CONSTELLATIONS) { locationName = asset.getLocation().getConstellation(); location = ApiIdConverter.getLocation(asset.getLocation().getConstellationID()); } else if (view == View.SYSTEMS) { locationName = asset.getLocation().getSystem(); location = ApiIdConverter.getLocation(asset.getLocation().getSystemID()); } else if (view == View.PLANETS) { locationName = asset.getLocation().getLocation(); location = ApiIdConverter.getLocation(asset.getLocation().getLocationID()); } else if (view == View.STATIONS) { locationName = asset.getLocation().getLocation(); location = ApiIdConverter.getLocation(asset.getLocation().getLocationID()); } } else { locationName = location.getLocation(); } if (locationsMap.containsKey(locationName)) { //Update existing overview Overview overview = locationsMap.get(locationName); overview.addCount(count); overview.addValue(value); overview.addVolume(volume); overview.addReprocessedValue(reprocessedValue); } else { //Create new overview Overview overview = new Overview(locationName, location, reprocessedValue, volume, count, value); locationsMap.put(locationName, overview); locations.add(overview); } } else { //Groups for (Map.Entry entry : Settings.get().getOverviewGroups().entrySet()) { OverviewGroup overviewGroup = entry.getValue(); for (OverviewLocation overviewLocation : overviewGroup.getLocations()) { if (overviewLocation.equalsLocation(asset)) { //Update existing overview (group) Overview overview = locationsMap.get(overviewGroup.getName()); overview.addCount(count); overview.addValue(value); overview.addVolume(volume); overview.addReprocessedValue(reprocessedValue); break; //Only add once.... } } } } } try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(locations); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } public List getGroupedLocations() { return groupedLocations; } public int getRowCount() { return rowCount; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/overview/OverviewGroup.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.overview; import java.util.ArrayList; import java.util.List; public class OverviewGroup { private final List locations = new ArrayList(); private String name; public OverviewGroup(final String name) { this.name = name; } public void add(final OverviewLocation location) { if (locations.contains(location)) { locations.remove(location); } locations.add(location); } public void addAll(final List list) { for (OverviewLocation location : list) { add(location); } } public void remove(final OverviewLocation location) { locations.remove(location); } public void removeAll(final List list) { locations.removeAll(list); } public List getLocations() { return locations; } public String getName() { return name; } public void setName(final String name) { this.name = name; } @Override public String toString() { return name; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/overview/OverviewLocation.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.overview; import net.nikr.eve.jeveasset.data.api.my.MyAsset; public class OverviewLocation { public enum LocationType { TYPE_PLANET, TYPE_STATION, TYPE_SYSTEM, TYPE_CONSTELLATION, TYPE_REGION; } private String name; private LocationType type; public OverviewLocation(final String name) { this(name, null); } public OverviewLocation(final String name, final LocationType type) { this.name = name; this.type = type; } public String getName() { return name; } public LocationType getType() { return type; } public boolean isPlanet() { return type.equals(LocationType.TYPE_PLANET); } public boolean isStation() { return type.equals(LocationType.TYPE_STATION); } public boolean isSystem() { return type.equals(LocationType.TYPE_SYSTEM); } public boolean isConstellation() { return type.equals(LocationType.TYPE_CONSTELLATION); } public boolean isRegion() { return type.equals(LocationType.TYPE_REGION); } public boolean equalsLocation(final MyAsset asset) { return (name.equals(asset.getLocation().getLocation()) || name.equals(asset.getLocation().getSystem()) || name.equals(asset.getLocation().getConstellation()) || name.equals(asset.getLocation().getRegion())); } public boolean equalsLocation(final Overview overview) { return (name.equals(overview.getName()) || name.equals(overview.getLocation().getSystem()) || name.equals(overview.getLocation().getConstellation()) || name.equals(overview.getLocation().getRegion())); } @Override public boolean equals(final Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final OverviewLocation other = (OverviewLocation) obj; if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { return false; } return true; } @Override public int hashCode() { int hash = 3; hash = 23 * hash + (this.name != null ? this.name.hashCode() : 0); return hash; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/overview/OverviewTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.overview; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.awt.CardLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JToggleButton; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.JStatusLabel; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.components.JTreemap; import net.nikr.eve.jeveasset.gui.shared.components.ListComboBoxModel; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.AutoNumberFormat; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.InfoItem; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetsTab; import net.nikr.eve.jeveasset.i18n.TabsOverview; public class OverviewTab extends JMainTabSecondary { public static enum OverviewAction { UPDATE_LIST, LOAD_FILTER, TREEMAP_VIEW } public static enum View { STATIONS, PLANETS, SYSTEMS, CONSTELLATIONS, REGIONS, GROUPS, } private final JOverviewTable jTable; private final JToggleButton jStations; private final JToggleButton jPlanets; private final JToggleButton jSystems; private final JToggleButton jConstellations; private final JToggleButton jRegions; private final JToggleButton jGroups; private final JToggleButton jTreemap; private final JDropDownButton jLoadFilter; private final JComboBox jOwner; private final JStatusLabel jValue; private final JStatusLabel jReprocessed; private final JStatusLabel jCount; private final JStatusLabel jAverage; private final JStatusLabel jVolume; private final JLabel jShowing; private final ListenerClass listener = new ListenerClass(); //Table private final EventList eventList; private final FilterList filterList; private final DefaultEventTableModel tableModel; private final EnumTableFormatAdaptor tableFormat; private final OverviewTabFilterControl filterControl; private final DefaultEventSelectionModel selectionModel; //Data private final OverviewData overviewData; public static final String NAME = "overview"; //Not to be changed! private static final String VIEW_TABLE = "table"; private static final String VIEW_TREEMAP = "treemap"; private final JTreemap jTreemapView; private final JPanel jViewPanel; private final CardLayout viewLayout; public OverviewTab(final Program program) { super(program, NAME, TabsOverview.get().overview(), Images.TOOL_OVERVIEW.getIcon(), true); overviewData = new OverviewData(program); JFixedToolBar jToolBar = new JFixedToolBar(); JLabel jViewsLabel = new JLabel(TabsOverview.get().view()); jToolBar.add(jViewsLabel); jToolBar.addSpace(10); jStations = new JToggleButton(Images.LOC_STATION.getIcon()); jStations.setSelected(true); jStations.setToolTipText(TabsOverview.get().stations()); jStations.setActionCommand(OverviewAction.UPDATE_LIST.name()); jStations.addActionListener(listener); jToolBar.addButtonIcon(jStations); jPlanets = new JToggleButton(Images.LOC_PLANET.getIcon()); jPlanets.setToolTipText(TabsOverview.get().planets()); jPlanets.setActionCommand(OverviewAction.UPDATE_LIST.name()); jPlanets.addActionListener(listener); jToolBar.addButtonIcon(jPlanets); jSystems = new JToggleButton(Images.LOC_SYSTEM.getIcon()); jSystems.setToolTipText(TabsOverview.get().systems()); jSystems.setActionCommand(OverviewAction.UPDATE_LIST.name()); jSystems.addActionListener(listener); jToolBar.addButtonIcon(jSystems); jConstellations = new JToggleButton(Images.LOC_CONSTELLATION.getIcon()); jConstellations.setToolTipText(TabsOverview.get().constellations()); jConstellations.setActionCommand(OverviewAction.UPDATE_LIST.name()); jConstellations.addActionListener(listener); jToolBar.addButtonIcon(jConstellations); jRegions = new JToggleButton(Images.LOC_REGION.getIcon()); jRegions.setToolTipText(TabsOverview.get().regions()); jRegions.setActionCommand(OverviewAction.UPDATE_LIST.name()); jRegions.addActionListener(listener); jToolBar.addButtonIcon(jRegions); jGroups = new JToggleButton(Images.LOC_GROUPS.getIcon()); jGroups.setToolTipText(TabsOverview.get().groups()); jGroups.setActionCommand(OverviewAction.UPDATE_LIST.name()); jGroups.addActionListener(listener); jToolBar.addButtonIcon(jGroups); jTreemap = new JToggleButton(TabsOverview.get().treemap(), Images.TOOL_TREE.getIcon()); jTreemap.setToolTipText(TabsOverview.get().treemapToolTip()); jTreemap.setActionCommand(OverviewAction.TREEMAP_VIEW.name()); jTreemap.addActionListener(listener); jToolBar.addButton(jTreemap); ButtonGroup group = new ButtonGroup(); group.add(jStations); group.add(jPlanets); group.add(jSystems); group.add(jConstellations); group.add(jRegions); group.add(jGroups); jToolBar.addSeparator(); jLoadFilter = new JDropDownButton(TabsOverview.get().loadFilter()); jLoadFilter.setIcon(Images.FILTER_LOAD.getIcon()); jToolBar.addButton(jLoadFilter); jToolBar.addSeparator(); jToolBar.addSpace(5); JLabel jOwnerLabel = new JLabel(TabsOverview.get().owner()); jToolBar.add(jOwnerLabel); jToolBar.addSpace(5); jOwner = new JComboBox<>(); jOwner.setActionCommand(OverviewAction.UPDATE_LIST.name()); jOwner.addActionListener(listener); jToolBar.addComboBox(jOwner, 150); jToolBar.addGlue(10); jShowing = new JLabel(); jShowing.setHorizontalAlignment(JLabel.RIGHT); jToolBar.add(jShowing); updateFilters(); //Table Format tableFormat = TableFormatFactory.overviewTableFormat(); //Backend eventList = EventListManager.create(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedList); eventList.getReadWriteLock().readLock().unlock(); filterList.addListEventListener(new ListEventListener() { @Override public void listChanged(ListEvent listChanges) { if (jTreemap.isSelected()) { updateTreemapData(); } } }); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JOverviewTable(program, tableModel); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); jTreemapView = new JTreemap(new JTreemap.SelectionListener() { @Override public void itemSelected(String name) { applyNameFilter(name); } }); viewLayout = new CardLayout(); jViewPanel = new JPanel(viewLayout); jViewPanel.add(jTableScroll, VIEW_TABLE); jViewPanel.add(jTreemapView, VIEW_TREEMAP); viewLayout.show(jViewPanel, VIEW_TABLE); //Table Filter filterControl = new OverviewTabFilterControl(sortedList); //Menu installTableTool(new OverviewTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, Overview.class); jVolume = StatusPanel.createLabel(TabsOverview.get().totalVolume(), Images.ASSETS_VOLUME.getIcon(), AutoNumberFormat.DOUBLE); this.addStatusbarLabel(jVolume); jCount = StatusPanel.createLabel(TabsOverview.get().totalCount(), Images.EDIT_ADD.getIcon(), AutoNumberFormat.ITEMS); this.addStatusbarLabel(jCount); jAverage = StatusPanel.createLabel(TabsOverview.get().average(), Images.ASSETS_AVERAGE.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jAverage); jReprocessed = StatusPanel.createLabel(TabsOverview.get().totalReprocessed(), Images.SETTINGS_REPROCESSING.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jReprocessed); jValue = StatusPanel.createLabel(TabsOverview.get().totalValue(), Images.TOOL_VALUES.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jValue); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, jToolBar.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jViewPanel, 400, 400, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jViewPanel, 100, 400, Short.MAX_VALUE) ); } @Override public void updateData() { Object object = jOwner.getSelectedItem(); jOwner.setModel(new ListComboBoxModel<>(program.getOwnerNames(true))); if (object != null) { jOwner.setSelectedItem(object); } updateTableInner(); } @Override public void clearData() { try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } @Override public void updateCache() { } @Override public Collection getLocations() { try { eventList.getReadWriteLock().readLock().lock(); return new ArrayList<>(eventList); } finally { eventList.getReadWriteLock().readLock().unlock(); } } public ActionListener getListenerClass() { return listener; } public boolean isGroup() { return getSelectedView() == View.GROUPS; } public boolean isGroupAndNotEmpty() { OverviewGroup overviewGroup = getSelectGroup(); return isGroup() && overviewGroup != null && !overviewGroup.getLocations().isEmpty(); } private void updateStatusbar() { double averageValue = 0; double totalValue = 0; long totalCount = 0; double totalVolume = 0; double totalReprocessed = 0; try { eventList.getReadWriteLock().readLock().lock(); for (InfoItem infoItem : eventList) { totalValue = totalValue + infoItem.getValue(); totalCount = totalCount + infoItem.getCount(); totalVolume = totalVolume + infoItem.getVolumeTotal(); totalReprocessed = totalReprocessed + infoItem.getValueReprocessed(); } } finally { eventList.getReadWriteLock().readLock().unlock(); } if (totalCount > 0 && totalValue > 0) { averageValue = totalValue / totalCount; } jVolume.setNumber(totalVolume); jCount.setNumber(totalCount); jAverage.setNumber(averageValue); jReprocessed.setNumber(totalReprocessed); jValue.setNumber(totalValue); } @Override public void tableDataChanged() { super.tableDataChanged(); if (jTreemap.isSelected()) { updateTreemapData(); } } private void updateTreemapData() { Map nameValues = new HashMap<>(); try { filterList.getReadWriteLock().readLock().lock(); for (Overview overview : filterList) { String name = overview.getName(); if (name == null || name.isEmpty()) { name = "Unknown"; } double value = overview.getValue(); if (value <= 0) { continue; } nameValues.put(name, nameValues.getOrDefault(name, 0.0) + value); } } finally { filterList.getReadWriteLock().readLock().unlock(); } jTreemapView.setItems(nameValues); } private void showTreemap(boolean show) { if (show) { updateTreemapData(); viewLayout.show(jViewPanel, VIEW_TREEMAP); } else { viewLayout.show(jViewPanel, VIEW_TABLE); } } private void applyNameFilter(String name) { if (name == null || name.isEmpty()) { return; } if (jTreemap.isSelected()) { jTreemap.setSelected(false); showTreemap(false); } List filters = new ArrayList<>(); for (Filter filter : filterControl.getCurrentFilters()) { if (filter == null || filter.isEmpty()) { continue; } if (filter.getColumn() instanceof OverviewTableFormat) { OverviewTableFormat column = (OverviewTableFormat) filter.getColumn(); if (column == OverviewTableFormat.NAME) { continue; } } filters.add(filter); } filters.add(new Filter(Filter.LogicType.AND, OverviewTableFormat.NAME, Filter.CompareType.EQUALS, name)); filterControl.clearCurrentFilters(); filterControl.addFilters(filters); } protected View getSelectedView() { if (jStations.isSelected()) { return View.STATIONS; } if (jPlanets.isSelected()) { return View.PLANETS; } if (jSystems.isSelected()) { return View.SYSTEMS; } if (jConstellations.isSelected()) { return View.CONSTELLATIONS; } if (jRegions.isSelected()) { return View.REGIONS; } if (jGroups.isSelected()) { return View.GROUPS; } return View.STATIONS; } public final void updateFilters() { JMenuItem jMenuItem; jLoadFilter.removeAll(); jMenuItem = new FilterMenuItem(TabsOverview.get().clear(), new ArrayList<>()); jMenuItem.setIcon(Images.FILTER_CLEAR.getIcon()); jMenuItem.setActionCommand(OverviewAction.LOAD_FILTER.name()); jMenuItem.addActionListener(listener); jLoadFilter.add(jMenuItem); List filterNames = new ArrayList<>(Settings.get().getTableFilters(AssetsTab.NAME).keySet()); Collections.sort(filterNames, StringComparators.CASE_INSENSITIVE); if (!filterNames.isEmpty()) { jLoadFilter.addSeparator(); } for (String filterName : filterNames) { List filters = Settings.get().getTableFilters(AssetsTab.NAME).get(filterName); jMenuItem = new FilterMenuItem(filterName, filters); jMenuItem.setActionCommand(OverviewAction.LOAD_FILTER.name()); jMenuItem.addActionListener(listener); jLoadFilter.add(jMenuItem); } } public void updateTable() { //Only need to updateFormula when added to the main window if (!program.getMainWindow().getTabs().contains(this)) { return; } updateTableInner(); } public static void updateShownColumns(EnumTableFormatAdaptor tableFormat, View view) { switch (view) { case STATIONS: tableFormat.showColumn(OverviewTableFormat.SYSTEM); tableFormat.showColumn(OverviewTableFormat.CONSTELLATION); tableFormat.showColumn(OverviewTableFormat.REGION); tableFormat.showColumn(OverviewTableFormat.SECURITY); break; case PLANETS: tableFormat.showColumn(OverviewTableFormat.SYSTEM); tableFormat.showColumn(OverviewTableFormat.CONSTELLATION); tableFormat.showColumn(OverviewTableFormat.REGION); tableFormat.showColumn(OverviewTableFormat.SECURITY); break; case SYSTEMS: tableFormat.hideColumn(OverviewTableFormat.SYSTEM); tableFormat.showColumn(OverviewTableFormat.CONSTELLATION); tableFormat.showColumn(OverviewTableFormat.REGION); tableFormat.showColumn(OverviewTableFormat.SECURITY); break; case CONSTELLATIONS: tableFormat.hideColumn(OverviewTableFormat.SYSTEM); tableFormat.hideColumn(OverviewTableFormat.CONSTELLATION); tableFormat.showColumn(OverviewTableFormat.REGION); tableFormat.hideColumn(OverviewTableFormat.SECURITY); break; case REGIONS: tableFormat.hideColumn(OverviewTableFormat.SYSTEM); tableFormat.hideColumn(OverviewTableFormat.REGION); tableFormat.hideColumn(OverviewTableFormat.CONSTELLATION); tableFormat.hideColumn(OverviewTableFormat.SECURITY); break; case GROUPS: tableFormat.hideColumn(OverviewTableFormat.SYSTEM); tableFormat.hideColumn(OverviewTableFormat.CONSTELLATION); tableFormat.hideColumn(OverviewTableFormat.REGION); tableFormat.hideColumn(OverviewTableFormat.SECURITY); break; } } private void updateTableInner() { beforeUpdateData(); String owner = (String) jOwner.getSelectedItem(); View view = getSelectedView(); updateShownColumns(tableFormat, view); tableModel.fireTableStructureChanged(); overviewData.updateData(eventList, program.getAssetsTab().getFilteredAssets(), owner, view); jTable.setGroupedLocations(overviewData.getGroupedLocations()); updateStatusbar(); program.overviewGroupsChanged(); if (jTreemap.isSelected()) { updateTreemapData(); } jShowing.setText(TabsOverview.get().filterShowing(overviewData.getRowCount(), EventListManager.size(program.getProfileData().getAssetsEventList()), program.getAssetsTab().getCurrentFilterName())); afterUpdateData(); } protected List getSelectedLocations() { List locations = new ArrayList<>(); for (int row : jTable.getSelectedRows()) { Overview overview = tableModel.getElementAt(row); OverviewLocation overviewLocation = null; if (getSelectedView() == View.STATIONS) { overviewLocation = new OverviewLocation(overview.getName(), OverviewLocation.LocationType.TYPE_STATION); } else if (getSelectedView() == View.PLANETS) { overviewLocation = new OverviewLocation(overview.getName(), OverviewLocation.LocationType.TYPE_PLANET); } else if (getSelectedView() == View.SYSTEMS) { overviewLocation = new OverviewLocation(overview.getName(), OverviewLocation.LocationType.TYPE_SYSTEM); } else if (getSelectedView() == View.CONSTELLATIONS) { overviewLocation = new OverviewLocation(overview.getName(), OverviewLocation.LocationType.TYPE_CONSTELLATION); } else if (getSelectedView() == View.REGIONS) { overviewLocation = new OverviewLocation(overview.getName(), OverviewLocation.LocationType.TYPE_REGION); } if (overviewLocation != null) { locations.add(overviewLocation); } } return locations; } public OverviewGroup getSelectGroup() { int index = jTable.getSelectedRow(); if (index < 0) { return null; } Overview overview = tableModel.getElementAt(index); if (overview == null) { return null; } return Settings.get().getOverviewGroups().get(overview.getName()); } public class OverviewTableMenu implements TableMenu { public OverviewTab getOverviewTab() { return OverviewTab.this; } @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME, false); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { JMenuInfo.infoItem(jPopupMenu, selectionModel.getSelected()); } @Override public void addToolMenu(JComponent jComponent) { jComponent.add(new JOverviewMenu(program, OverviewTab.this, selectionModel.getSelected())); MenuManager.addSeparator(jComponent); } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (OverviewAction.UPDATE_LIST.name().equals(e.getActionCommand())) { updateTable(); } else if (OverviewAction.LOAD_FILTER.name().equals(e.getActionCommand())) { Object source = e.getSource(); if (source instanceof FilterMenuItem) { FilterMenuItem menuItem = (FilterMenuItem) source; program.getAssetsTab().clearFilters(); if (!menuItem.getFilters().isEmpty()) { program.getAssetsTab().addFilters(menuItem.getFilters()); } } } else if (OverviewAction.TREEMAP_VIEW.name().equals(e.getActionCommand())) { showTreemap(jTreemap.isSelected()); } } } private class FilterMenuItem extends JMenuItem { private final List filters; public FilterMenuItem(final String name, final List filters) { super(name, Images.FILTER_LOAD.getIcon()); this.filters = filters; } public List getFilters() { return filters; } } public class OverviewTabFilterControl extends FilterControl { public OverviewTabFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("Overview Table: " + msg); //Save Overview Filters and Export Settings } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/overview/OverviewTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.overview; import java.util.Comparator; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.Security; import net.nikr.eve.jeveasset.i18n.TabsOverview; public enum OverviewTableFormat implements EnumTableColumn { NAME(String.class) { @Override public String getColumnName() { return TabsOverview.get().columnName(); } @Override public Object getColumnValue(final Overview from) { return from.getName(); } }, SYSTEM(String.class) { @Override public String getColumnName() { return TabsOverview.get().columnSystem(); } @Override public Object getColumnValue(final Overview from) { return from.getLocation().getSystem(); } }, CONSTELLATION(String.class) { @Override public String getColumnName() { return TabsOverview.get().columnConstellation(); } @Override public Object getColumnValue(final Overview from) { return from.getLocation().getConstellation(); } }, REGION(String.class) { @Override public String getColumnName() { return TabsOverview.get().columnRegion(); } @Override public Object getColumnValue(final Overview from) { return from.getLocation().getRegion(); } }, SECURITY(Security.class) { @Override public String getColumnName() { return TabsOverview.get().columnSecurity(); } @Override public Object getColumnValue(final Overview from) { return from.getLocation().getSecurityObject(); } }, VOLUME(Double.class) { @Override public String getColumnName() { return TabsOverview.get().columnVolume(); } @Override public Object getColumnValue(final Overview from) { return from.getVolumeTotal(); } }, VALUE(Double.class) { @Override public String getColumnName() { return TabsOverview.get().columnValue(); } @Override public Object getColumnValue(final Overview from) { return from.getValue(); } }, VALUE_PER_VOLUME(Double.class) { @Override public String getColumnName() { return TabsOverview.get().columnValuePerVolume(); } @Override public Object getColumnValue(final Overview from) { return from.getValuePerVolume(); } }, COUNT(Long.class) { @Override public String getColumnName() { return TabsOverview.get().columnCount(); } @Override public Object getColumnValue(final Overview from) { return from.getCount(); } }, AVERAGE_VALUE(Double.class) { @Override public String getColumnName() { return TabsOverview.get().columnAverageValue(); } @Override public Object getColumnValue(final Overview from) { return from.getAverageValue(); } }, REPROCESSED_VALUE(Double.class) { @Override public String getColumnName() { return TabsOverview.get().columnReprocessedValue(); } @Override public Object getColumnValue(final Overview from) { return from.getValueReprocessed(); } }; private final Class type; private final Comparator comparator; private OverviewTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/prices/JItemsManagerDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.prices; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.components.JManagerDialog; import net.nikr.eve.jeveasset.i18n.TabsPriceHistory; public class JItemsManagerDialog extends JManagerDialog { private final PriceHistoryTab priceHistoryTab; public JItemsManagerDialog(Program program, PriceHistoryTab priceHistoryTab) { super(program, program.getMainWindow().getFrame(), TabsPriceHistory.get().manageTitle(), true, false, false, true, false); this.priceHistoryTab = priceHistoryTab; } @Override protected void load(String name) { priceHistoryTab.setItems(Settings.get().getPriceHistorySets().get(name)); setVisible(false); } @Override protected void edit(String name) { //Edit is not supported } @Override protected void merge(String name, List list) { Set typeIDs = new HashSet<>(); for (String s : list) { typeIDs.addAll(Settings.get().getPriceHistorySets().get(s)); if (typeIDs.size() > priceHistoryTab.MAXIMUM_SHOWN) { JOptionPane.showMessageDialog(parent, TabsPriceHistory.get().mergeMax(priceHistoryTab.MAXIMUM_SHOWN), TabsPriceHistory.get().merge(), JOptionPane.PLAIN_MESSAGE); return; } } Settings.lock("Price History (Merge Sets)"); Settings.get().getPriceHistorySets().put(name, typeIDs); Settings.unlock("Price History (Merge Sets)"); program.saveSettings("Price History (Merge Set)"); updateData(); priceHistoryTab.updateSaved(); } @Override protected void copy(String fromName, String toName) { //Copy is not supported } @Override protected void rename(String name, String oldName) { Settings.lock("Price History (Rename Set)"); Set typeIDs = Settings.get().getPriceHistorySets().remove(oldName); Settings.get().getPriceHistorySets().put(name, typeIDs); Settings.unlock("Price History (Rename Set)"); program.saveSettings("Price History (Rename Set)"); updateData(); priceHistoryTab.updateSaved(); } @Override protected void delete(List list) { Settings.lock("Price History (Delete Sets)"); Settings.get().getPriceHistorySets().keySet().removeAll(list); Settings.unlock("Price History (Delete Sets)"); program.saveSettings("Price History (Delete Sets)"); updateData(); priceHistoryTab.updateSaved(); } @Override protected void export(List list) { //Export is not supported } @Override protected void importData() { //Import is not supported } @Override public void setVisible(boolean b) { if (b) { updateData(); } super.setVisible(b); } private void updateData() { update(Settings.get().getPriceHistorySets().keySet()); } @Override protected String textDeleteMultipleMsg(int size) { return TabsPriceHistory.get().deleteHistorySets(size); } @Override protected String textDelete() { return TabsPriceHistory.get().deleteHistorySet(); } @Override protected String textEnterName() { return TabsPriceHistory.get().enterName(); } @Override protected String textMerge() { return TabsPriceHistory.get().merge(); } @Override protected String textRename() { return TabsPriceHistory.get().rename(); } @Override protected String textOverwrite() { return TabsPriceHistory.get().overwrite(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/prices/PriceChangesTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.prices; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import com.github.lgooddatepicker.optionalusertools.DateChangeListener; import com.github.lgooddatepicker.optionalusertools.DateVetoPolicy; import com.github.lgooddatepicker.zinternaltools.DateChangeEvent; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.ParseException; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.NavigableSet; import java.util.Objects; import java.util.TreeSet; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings.PriceMode; import net.nikr.eve.jeveasset.data.settings.PriceHistoryDatabase; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.types.EditablePriceType; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JDateChooser; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.i18n.TabsPriceChanges; public class PriceChangesTab extends JMainTabSecondary { private enum PriceChangesAction { PRICE_MODE, OWNED, RESET_DATES } //GUI private final JComboBox jPriceMode; private final JDateChooser jFrom; private final JDateChooser jTo; private final JCheckBox jOwned; private final JAutoColumnTable jTable; //Table private final PriceChangeFilterControl filterControl; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventTableModel tableModel; private final EventList eventList; private final FilterList filterList; private final DefaultEventSelectionModel selectionModel; //Date private Map ownedTypeIDs; private NavigableSet priceChangesDate = new TreeSet<>(); public static final String NAME = "pricechange"; //Not to be changed! public PriceChangesTab(final Program program) { super(program, NAME, TabsPriceChanges.get().title(), Images.TOOL_PRICE_CHANGE.getIcon(), true); layout.setAutoCreateGaps(true); ListenerClass listener = new ListenerClass(); JFixedToolBar jToolBar = new JFixedToolBar(); jPriceMode = new JComboBox<>(PriceMode.values()); jPriceMode.setSelectedItem(Settings.get().getPriceDataSettings().getPriceType()); jPriceMode.setActionCommand(PriceChangesAction.PRICE_MODE.name()); jPriceMode.addActionListener(listener); jPriceMode.setPrototypeDisplayValue(PriceMode.PRICE_BUY_PERCENTILE); jToolBar.addPreferedSize(jPriceMode); jToolBar.addSpace(5); jToolBar.addSeparator(); jToolBar.addSpace(5); JLabel jFromLabel = new JLabel(TabsPriceChanges.get().from()); jToolBar.add(jFromLabel); jToolBar.addSpace(5); jFrom = new JDateChooser(false); jFrom.getSettings().setVetoPolicy(new FromVetoPolicy()); jFrom.addDateChangeListener(listener); jToolBar.addPreferedSize(jFrom); jToolBar.addSpace(5); jToolBar.addSeparator(); jToolBar.addSpace(5); JLabel jToLabel = new JLabel(TabsPriceChanges.get().to()); jToolBar.add(jToLabel); jToolBar.addSpace(5); jTo = new JDateChooser(false); jTo.getSettings().setVetoPolicy(new ToVetoPolicy()); jTo.addDateChangeListener(listener); jToolBar.addPreferedSize(jTo); jToolBar.addSpace(5); jToolBar.addSeparator(); jToolBar.addSpace(5); JButton jResetDates = new JButton(TabsPriceChanges.get().resetDates(), Images.FILTER_CLEAR.getIcon()); jResetDates.setActionCommand(PriceChangesAction.RESET_DATES.name()); jResetDates.addActionListener(listener); jToolBar.addButton(jResetDates); jToolBar.addSpace(5); jToolBar.addSeparator(); jToolBar.addSpace(5); jOwned = new JCheckBox(TabsPriceChanges.get().owned(), true); jOwned.setActionCommand(PriceChangesAction.OWNED.name()); jOwned.addActionListener(listener); jToolBar.addPreferedSize(jOwned); //Table Format tableFormat = TableFormatFactory.priceChangesTableFormat(); //Backend eventList = EventListManager.create(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedList); eventList.getReadWriteLock().readLock().unlock(); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JAutoColumnTable(program, tableModel); jTable.setCellSelectionEnabled(true); jTable.setRowSelectionAllowed(true); jTable.setColumnSelectionAllowed(true); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new PriceChangeFilterControl(sortedList); //Menu installTableTool(new PriceChangeTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, PriceChange.class); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void updateData() { boolean setDefaults = ownedTypeIDs == null; //First run //Owned ownedTypeIDs = new HashMap<>(); for (MyAsset asset : program.getProfileData().getAssetsList()) { add(ownedTypeIDs, asset.getTypeID(), asset.getItemCount()); } for (MyIndustryJob industryJob : program.getProfileData().getIndustryJobsList()) { if (industryJob.getItem().isMarketGroup() && industryJob.isNotDeliveredToAssets()) { add(ownedTypeIDs, industryJob.getTypeID(), 1L); } } //Price changes priceChangesDate = PriceHistoryDatabase.getPriceChangesDate(ownedTypeIDs.keySet()); //Defaults if (setDefaults) { try { jFrom.setDate(getDate(priceChangesDate.first())); } catch (ParseException ex) { } try { jTo.setDate(getDate(priceChangesDate.last())); } catch (ParseException ex) { } } //Update table data updateTable(); } private void updateTable() { PriceMode priceMode = jPriceMode.getItemAt(jPriceMode.getSelectedIndex()); boolean ownedOnly = jOwned.isSelected(); try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(PriceHistoryDatabase.getPriceChanges(ownedTypeIDs, ownedOnly, priceMode, getFromDate(), getToDate())); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } @Override public void clearData() { try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } @Override public void updateCache() { } @Override public Collection getLocations() { return new ArrayList<>(); //No Location } private void add(Map priceTypeIDs, Integer typeID, Long count) { Long previous = priceTypeIDs.getOrDefault(typeID, 0L); priceTypeIDs.put(typeID, previous + count); } private Date getFromDate() { return getDate(jFrom.getDate()); } private Date getToDate() { return getDate(jTo.getDate()); } private String getDateString(Date date) { return PriceHistoryDatabase.DATE.format(date); } private static Date getDate(String date) throws ParseException { return PriceHistoryDatabase.DATE.parse(date); } private Date getDate(LocalDate date) { if (date == null) { return null; } Instant instant = date.atTime(12, 0, 0, 0).atZone(ZoneId.of("GMT")).toInstant(); //End of day - GMT return Date.from(instant); } private class PriceChangeTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { //JMenuInfo.infoItem(jPopupMenu, selectionModel.getSelected()); } @Override public void addToolMenu(JComponent jComponent) { } } private class ListenerClass implements ActionListener, DateChangeListener { @Override public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals(PriceChangesAction.PRICE_MODE.name())) { updateTable(); } else if (e.getActionCommand().equals(PriceChangesAction.OWNED.name())) { updateTable(); } else if (e.getActionCommand().equals(PriceChangesAction.RESET_DATES.name())) { try { jFrom.setDate(PriceHistoryDatabase.DATE.parse(priceChangesDate.first())); } catch (ParseException ex) { } try { jTo.setDate(PriceHistoryDatabase.DATE.parse(priceChangesDate.last())); } catch (ParseException ex) { } } } @Override public void dateChanged(DateChangeEvent event) { updateTable(); } } private class PriceChangeFilterControl extends FilterControl { public PriceChangeFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("Price Change Table: " + msg); //Save Asset Filters and Export Settings } } public class FromVetoPolicy implements DateVetoPolicy { @Override public boolean isDateAllowed(LocalDate localDate) { Date date = getDate(localDate); return priceChangesDate.contains(getDateString(date)) && getToDate().after(date); } } public class ToVetoPolicy implements DateVetoPolicy { @Override public boolean isDateAllowed(LocalDate localDate) { Date date = getDate(localDate); return priceChangesDate.contains(getDateString(date)) && date.after(getFromDate()); } } public static class PriceChange implements ItemType, EditablePriceType, Comparable { private final int typeID; private final Item item; private final Long count; private double priceFrom; private double priceTo; public PriceChange(int typeID, Item item, Long count) { this.typeID = typeID; this.item = item; this.count = count; } public int getTypeID() { return typeID; } public Long getCount() { return count; } public double getPriceFrom() { return priceFrom; } public void setPriceFrom(double priceFrom) { this.priceFrom = priceFrom; } public double getPriceTo() { return priceTo; } public void setPriceTo(double priceTo) { this.priceTo = priceTo; } public double getChange() { return getPriceTo() - getPriceFrom(); } public Percent getChangePercent() { if (getPriceFrom() > 0 && getPriceTo() > 0) { return Percent.create(getPriceTo() / getPriceFrom()); } else if (getPriceFrom() == 0 && getPriceTo() == 0) { return Percent.create(0); } else if (getPriceFrom() == 0 && getPriceTo() > 0) { return Percent.create(1); } else { return null; } } public double getTotal() { return getPriceTo() * getItemCount() - getPriceFrom() * getItemCount(); } @Override public Item getItem() { return item; } @Override public long getItemCount() { return count; } @Override public void setDynamicPrice(double price) { } @Override public boolean isBPC() { return false; } @Override public Double getDynamicPrice() { return getPriceFrom(); } @Override public int compareTo(PriceChange o) { return item.getTypeName().compareTo(o.item.getTypeName()); } @Override public int hashCode() { int hash = 7; hash = 53 * hash + Objects.hashCode(this.item.getTypeName()); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final PriceChange other = (PriceChange) obj; return Objects.equals(this.item.getTypeName(), other.item.getTypeName()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/prices/PriceChangesTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.prices; import java.util.Comparator; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceChangesTab.PriceChange; import net.nikr.eve.jeveasset.i18n.TabsPriceChanges; public enum PriceChangesTableFormat implements EnumTableColumn { NAME(String.class) { @Override public String getColumnName() { return TabsPriceChanges.get().columnName(); } @Override public Object getColumnValue(final PriceChange from) { return from.getItem().getTypeName(); } }, GROUP(String.class) { @Override public String getColumnName() { return TabsPriceChanges.get().columnGroup(); } @Override public Object getColumnValue(final PriceChange from) { return from.getItem().getGroup(); } }, CATEGORY(String.class) { @Override public String getColumnName() { return TabsPriceChanges.get().columnCategory(); } @Override public Object getColumnValue(final PriceChange from) { return from.getItem().getCategory(); } }, COUNT(Long.class) { @Override public String getColumnName() { return TabsPriceChanges.get().columnCount(); } @Override public String getColumnToolTip() { return TabsPriceChanges.get().columnCountToolTip(); } @Override public Object getColumnValue(final PriceChange from) { return from.getItemCount(); } }, PRICE_FROM(Double.class) { @Override public String getColumnName() { return TabsPriceChanges.get().columnPriceFrom(); } @Override public Object getColumnValue(final PriceChange from) { return from.getPriceFrom(); } }, PRICE_TO(Double.class) { @Override public String getColumnName() { return TabsPriceChanges.get().columnPriceTo(); } @Override public Object getColumnValue(final PriceChange from) { return from.getPriceTo(); } }, PRICE_CHANGE_PERCENT(Percent.class) { @Override public String getColumnName() { return TabsPriceChanges.get().columnChangePercent(); } @Override public String getColumnToolTip() { return TabsPriceChanges.get().columnChangePercentToolTip(); } @Override public Object getColumnValue(final PriceChange from) { return from.getChangePercent(); } }, PRICE_CHANGE(Double.class) { @Override public String getColumnName() { return TabsPriceChanges.get().columnChange(); } @Override public String getColumnToolTip() { return TabsPriceChanges.get().columnChangeToolTip(); } @Override public Object getColumnValue(final PriceChange from) { return from.getChange(); } }, PRICE_TOTAL(Double.class) { @Override public String getColumnName() { return TabsPriceChanges.get().columnTotal(); } @Override public String getColumnToolTip() { return TabsPriceChanges.get().columnTotalToolTip(); } @Override public Object getColumnValue(final PriceChange from) { return from.getTotal(); } }, ; private final Class type; private final Comparator comparator; private PriceChangesTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/prices/PriceHistoryTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.prices; import com.github.lgooddatepicker.optionalusertools.DateChangeListener; import com.github.lgooddatepicker.zinternaltools.DateChangeEvent; import java.awt.Color; import java.awt.Paint; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.text.ParseException; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.concurrent.ExecutionException; import javax.swing.ButtonGroup; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings.PriceMode; import net.nikr.eve.jeveasset.data.settings.PriceHistoryDatabase; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.Progress; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.UpdateType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.ColorUtil; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.JFreeChartUtil; import net.nikr.eve.jeveasset.gui.shared.components.JAutoCompleteDialog; import net.nikr.eve.jeveasset.gui.shared.components.JDateChooser; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.components.JMultiSelectionList; import net.nikr.eve.jeveasset.gui.tabs.tracker.QuickDate; import net.nikr.eve.jeveasset.i18n.TabsPriceHistory; import net.nikr.eve.jeveasset.io.online.ZkillboardPricesHistoryGetter; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.LogarithmicAxis; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.labels.XYToolTipGenerator; import org.jfree.chart.plot.DefaultDrawingSupplier; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.time.SimpleTimePeriod; import org.jfree.data.time.TimePeriodValues; import org.jfree.data.time.TimePeriodValuesCollection; import org.jfree.data.xy.XYDataset; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class PriceHistoryTab extends JMainTabSecondary { private static final Logger LOG = LoggerFactory.getLogger(PriceHistoryTab.class); private enum PriceHistoryAction { QUICK_DATE, SOURCE, ADD_ITEM, CLEAR_ITEMS, REMOVE_ITEMS, SAVE, MANAGE, INCLUDE_ZERO, LOGARITHMIC } private enum PriceHistorySource { ZKILLBOARD() { @Override String getText() { return TabsPriceHistory.get().sourcezKillboard(); } }, JEVEASSETS() { @Override String getText() { return TabsPriceHistory.get().sourcejEveAssets(); } }; abstract String getText(); @Override public String toString() { return getText(); } } private final int PANEL_WIDTH_MINIMUM = 215; public final int MAXIMUM_SHOWN = 50; //GUI private final JComboBox jSource; private final JComboBox jPriceType; private final JComboBox jQuickDate; private final JDateChooser jFrom; private final JDateChooser jTo; private final JDropDownButton jEdit; private final JMenuItem jRemove; private final JMenuItem jClear; private final JButton jSave; private final JDropDownButton jLoad; private final JMenuItem jManage; private final JMultiSelectionList jItems; private final JCheckBoxMenuItem jIncludeZero; private final JRadioButtonMenuItem jLogarithmic; //Graph private final JFreeChart jFreeChart; private final ChartPanel jChartPanel; private final XYLineAndShapeRenderer renderer; private final LogarithmicAxis rangeLogarithmicAxis; private final DateAxis domainAxis; private final NumberAxis rangeLinearAxis; //Dialog private final JAutoCompleteDialog jAddItemDialog; private final JAutoCompleteDialog jSaveItemsDialog; private final JItemsManagerDialog jItemsManagerDialog; private final JLockWindow jLockWindow; //Listener private final ListenerClass listener = new ListenerClass(); //Data private final DefaultListModel itemsModel; private final List shownOrder = new ArrayList<>(); private final Set shownTypeIDs = new HashSet<>(); private final Map> shownData = new TreeMap<>(); private final Map series = new HashMap<>(); private final Map seriesMax = new HashMap<>(); private final TimePeriodValuesCollection dataset = new TimePeriodValuesCollection(); //Settings ToDo private Date fromDate = null; private Date toDate = null; public static final String NAME = "pricehistory"; //Not to be changed! public PriceHistoryTab(Program program) { super(program, NAME, TabsPriceHistory.get().title(), Images.TOOL_PRICE_HISTORY.getIcon(), true); jLockWindow = new JLockWindow(program.getMainWindow().getFrame()); jSource = new JComboBox<>(PriceHistorySource.values()); jSource.setActionCommand(PriceHistoryAction.SOURCE.name()); jSource.addActionListener(listener); jPriceType = new JComboBox<>(PriceMode.values()); jPriceType.setSelectedItem(Settings.get().getPriceDataSettings().getPriceType()); jPriceType.setActionCommand(PriceHistoryAction.SOURCE.name()); jPriceType.addActionListener(listener); jPriceType.setEnabled(false); JSeparator jDateSeparator = new JSeparator(); jQuickDate = new JComboBox<>(QuickDate.values()); jQuickDate.setActionCommand(PriceHistoryAction.QUICK_DATE.name()); jQuickDate.addActionListener(listener); JLabel jFromLabel = new JLabel(TabsPriceHistory.get().from()); jFrom = new JDateChooser(true); if (fromDate != null) { jFrom.setDate(fromDate); } jFrom.addDateChangeListener(listener); JLabel jToLabel = new JLabel(TabsPriceHistory.get().to()); jTo = new JDateChooser(true); if (toDate != null) { jTo.setDate(toDate); } jTo.addDateChangeListener(listener); jAddItemDialog = new JAutoCompleteDialog<>(program, TabsPriceHistory.get().addTitle(), Images.TOOL_PRICE_HISTORY.getImage(), null, true, JAutoCompleteDialog.ITEM_OPTIONS); jAddItemDialog.updateData(StaticData.get().getItems().values()); jSaveItemsDialog = new JAutoCompleteDialog<>(program, TabsPriceHistory.get().saveTitle(), Images.TOOL_PRICE_HISTORY.getImage(), null, false, JAutoCompleteDialog.STRING_OPTIONS); jItemsManagerDialog = new JItemsManagerDialog(program, this); jEdit = new JDropDownButton(Images.EDIT_EDIT.getIcon()); jEdit.setToolTipText(TabsPriceHistory.get().edit()); JMenuItem jAdd = new JMenuItem(TabsPriceHistory.get().add(), Images.EDIT_ADD.getIcon()); jAdd.setActionCommand(PriceHistoryAction.ADD_ITEM.name()); jAdd.addActionListener(listener); jEdit.add(jAdd); jRemove = new JMenuItem(TabsPriceHistory.get().remove(), Images.EDIT_DELETE.getIcon()); jRemove.setActionCommand(PriceHistoryAction.REMOVE_ITEMS.name()); jRemove.addActionListener(listener); jRemove.setEnabled(false); jEdit.add(jRemove); jClear = new JMenuItem(TabsPriceHistory.get().clear(), Images.MISC_EXIT.getIcon()); jClear.setActionCommand(PriceHistoryAction.CLEAR_ITEMS.name()); jClear.addActionListener(listener); jClear.setEnabled(false); jEdit.add(jClear); jSave = new JButton(Images.FILTER_SAVE.getIcon()); jSave.setToolTipText(TabsPriceHistory.get().save()); jSave.setActionCommand(PriceHistoryAction.SAVE.name()); jSave.setEnabled(false); jSave.addActionListener(listener); jLoad = new JDropDownButton(Images.FILTER_LOAD.getIcon()); jManage = new JMenuItem(TabsPriceHistory.get().manage(), Images.DIALOG_SETTINGS.getIcon()); jManage.setActionCommand(PriceHistoryAction.MANAGE.name()); jManage.addActionListener(listener); itemsModel = new DefaultListModel<>(); jItems = new JMultiSelectionList<>(itemsModel); jItems.getSelectionModel().addListSelectionListener(listener); jItems.addMouseListener(listener); JScrollPane jOwnersScroll = new JScrollPane(jItems); JDropDownButton jSettings = new JDropDownButton(Images.DIALOG_SETTINGS.getIcon()); jIncludeZero = new JCheckBoxMenuItem(TabsPriceHistory.get().includeZero()); jIncludeZero.setSelected(true); jIncludeZero.setActionCommand(PriceHistoryAction.INCLUDE_ZERO.name()); jIncludeZero.addActionListener(listener); jSettings.add(jIncludeZero); jSettings.addSeparator(); ButtonGroup buttonGroup = new ButtonGroup(); JRadioButtonMenuItem jLinear = new JRadioButtonMenuItem(TabsPriceHistory.get().scaleLinear()); jLinear.setSelected(true); jLinear.setActionCommand(PriceHistoryAction.LOGARITHMIC.name()); jLinear.addActionListener(listener); jSettings.add(jLinear); buttonGroup.add(jLinear); jLogarithmic = new JRadioButtonMenuItem(TabsPriceHistory.get().scaleLogarithmic()); jLogarithmic.setSelected(false); jLogarithmic.setActionCommand(PriceHistoryAction.LOGARITHMIC.name()); jLogarithmic.addActionListener(listener); jSettings.add(jLogarithmic); buttonGroup.add(jLogarithmic); domainAxis = JFreeChartUtil.createDateAxis(); rangeLogarithmicAxis = JFreeChartUtil.createLogarithmicAxis(true); rangeLinearAxis = JFreeChartUtil.createNumberAxis(true); renderer = JFreeChartUtil.createRenderer(); renderer.setDefaultToolTipGenerator(new XYToolTipGenerator() { @Override public String generateToolTip(XYDataset dataset, int series, int item) { Date date = new Date(dataset.getX(series, item).longValue()); Number isk = dataset.getY(series, item); return TabsPriceHistory.get().graphToolTip(dataset.getSeriesKey(series), Formatter.iskFormat(isk), Formatter.columnDateOnly(date)); } }); XYPlot plot = JFreeChartUtil.createPlot(dataset, domainAxis, rangeLinearAxis, renderer); jFreeChart = JFreeChartUtil.createChart(plot); jChartPanel = JFreeChartUtil.createChartPanel(jFreeChart); int gapWidth = 5; int labelWidth = Math.max(jFromLabel.getPreferredSize().width, jToLabel.getPreferredSize().width); int panelWidth = PANEL_WIDTH_MINIMUM; panelWidth = Math.max(panelWidth, jFrom.getPreferredSize().width + labelWidth + gapWidth); panelWidth = Math.max(panelWidth, jTo.getPreferredSize().width + labelWidth + gapWidth); int dateWidth = panelWidth - labelWidth - gapWidth; layout.setHorizontalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jChartPanel) ) .addGroup(layout.createParallelGroup() .addComponent(jSource, panelWidth, panelWidth, panelWidth) .addComponent(jPriceType, panelWidth, panelWidth, panelWidth) .addComponent(jDateSeparator, panelWidth, panelWidth, panelWidth) .addComponent(jQuickDate, panelWidth, panelWidth, panelWidth) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jFromLabel, labelWidth, labelWidth, labelWidth) .addComponent(jToLabel, labelWidth, labelWidth, labelWidth) ) .addGap(gapWidth) .addGroup(layout.createParallelGroup() .addComponent(jFrom, dateWidth, dateWidth, dateWidth) .addComponent(jTo, dateWidth, dateWidth, dateWidth) ) ) .addGroup(layout.createSequentialGroup() .addComponent(jEdit) .addComponent(jSave) .addComponent(jLoad) .addComponent(jSettings) ) .addComponent(jOwnersScroll, panelWidth, panelWidth, panelWidth) ) ); layout.setVerticalGroup( layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addComponent(jChartPanel) ) .addGroup(layout.createSequentialGroup() .addComponent(jSource, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jPriceType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDateSeparator, 3, 3, 3) .addComponent(jQuickDate, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup() .addComponent(jFromLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFrom, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jToLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jTo, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jEdit, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSave, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jLoad, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSettings, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jOwnersScroll, 70, 70, Integer.MAX_VALUE) ) ); } @Override public void updateData() { setItems(new HashSet<>(shownTypeIDs)); //Copy updateSaved(); } @Override public void repaintTable() { updateSeries(); } @Override public void updateCache() { } @Override public void clearData() { } @Override public Collection getLocations() { return new ArrayList<>(); //No Location } public void addItems(Set typeIDs) { Set total = new HashSet<>(); total.addAll(typeIDs); total.addAll(shownTypeIDs); if (invalid(total)) { return; } showItems(typeIDs); } public void setItems(Set typeIDs) { if (invalid(typeIDs)) { return; } jItems.getSelectionModel().removeListSelectionListener(listener); clearItems(); jItems.getSelectionModel().addListSelectionListener(listener); showItems(typeIDs); } private boolean invalid(Collection typeIDs) { if (typeIDs.size() > MAXIMUM_SHOWN) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsPriceHistory.get().maxItemsMsg(MAXIMUM_SHOWN), TabsPriceHistory.get().title(), JOptionPane.PLAIN_MESSAGE); return true; } if (program.getStatusPanel().updateing(UpdateType.PRICE_HISTORY)) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsPriceHistory.get().updatingMsg(), TabsPriceHistory.get().updatingTitle(), JOptionPane.PLAIN_MESSAGE, Images.LINK_ZKILLBOARD_32.getIcon()); return true; } return false; } private void addItem() { Set total = new HashSet<>(); total.add(Integer.MAX_VALUE); // + 1 total.addAll(shownTypeIDs); if (invalid(total)) { return; } Item item = jAddItemDialog.show(); if (item == null) { return; //Cancelled } showItems(Collections.singleton(item.getTypeID())); } private void showItems(Set typeIDs) { if (program.getStatusPanel().updateing(UpdateType.PRICE_HISTORY)) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsPriceHistory.get().updatingMsg(), TabsPriceHistory.get().updatingTitle(), JOptionPane.PLAIN_MESSAGE, Images.LINK_ZKILLBOARD_32.getIcon()); return; } switch(getPriceHistorySource()) { case ZKILLBOARD: jPriceType.setEnabled(false); showZKillboard(typeIDs); break; case JEVEASSETS: jPriceType.setEnabled(true); showPriceData(typeIDs); break; } } private void showPriceData(Set typeIDs) { addNewItemsLocked(PriceHistoryDatabase.getPriceData(typeIDs, jPriceType.getItemAt(jPriceType.getSelectedIndex()))); } private void showZKillboard(Set typeIDs) { if (typeIDs == null || typeIDs.isEmpty()) { return; } //Items to update Set update = new HashSet<>(typeIDs); //Items to load Set show = new HashSet<>(typeIDs); //Up-to-date items in the database Set blacklist = PriceHistoryDatabase.getZBlacklist(); Set current = PriceHistoryDatabase.getZKillboardUpdated(); current.addAll(blacklist); //Do not update blacklisted items, but, do add them to the GUI update.removeAll(current); //Remove up-to-date items update.removeAll(shownTypeIDs); //Remove already in the GUI if (!update.isEmpty()) { //Update from zKillboard API setUpdating(true); GetItems addItem = new GetItems(update); addItem.execute(); } show.retainAll(current); //Keep up-to-date items show.removeAll(shownTypeIDs);//Remove already in the GUI if (!show.isEmpty()) { //Load from Database Map> load = PriceHistoryDatabase.getZKillboard(show); if (!load.isEmpty()) { addNewItemsLocked(load); } } } private void addNewItemsLocked(Map> map) { jLockWindow.show(NAME, new JLockWindow.LockWorker() { @Override public void task() { createSeries(map); } @Override public void gui() { updateGUI(map); updateSeries(); } @Override public void hidden() { } }); } private void createSeries(Map> map) { if (map == null || map.isEmpty()) { return; } shownData.putAll(map); Date from = getFromDate(); Date to = getToDate(); for (Map.Entry> entry : map.entrySet()) { Item item = entry.getKey(); //dataset shownOrder.add(item); shownTypeIDs.add(item.getTypeID()); createSeries(from, to, item, entry.getValue()); } Collections.sort(shownOrder); } private void updateGUI(Map> map) { if (map == null || map.isEmpty()) { return; } jItems.getSelectionModel().removeListSelectionListener(listener); //List items = new ArrayList<>(map.keySet()); for (int index = 0; index < shownOrder.size(); index++) { Item item = shownOrder.get(index); if (!map.containsKey(item)) { continue; } //GUI itemsModel.add(index, item); jItems.addSelection(index, true); } jItems.getSelectionModel().addListSelectionListener(listener); } private void clearItems() { shownData.clear(); shownOrder.clear(); shownTypeIDs.clear(); seriesMax.clear(); series.clear(); //Remove All while (dataset.getSeriesCount() != 0) { dataset.removeSeries(0); } itemsModel.clear(); //Must be done after clearing the dataset } private void removeItem(Item item) { removeItems(Collections.singletonList(item)); } private void removeItems(Collection items) { if (items == null || items.isEmpty()) { return; } shownData.keySet().removeAll(items); shownOrder.removeAll(items); seriesMax.keySet().removeAll(items); series.keySet().removeAll(items); jItems.getSelectionModel().removeListSelectionListener(listener); for (Item item : items) { shownTypeIDs.remove(item.getTypeID()); itemsModel.removeElement(item); } jItems.getSelectionModel().addListSelectionListener(listener); updateSeries(); } private PriceHistorySource getPriceHistorySource() { return jSource.getItemAt(jSource.getSelectedIndex()); } private void createData() { //dataset Date from = getFromDate(); Date to = getToDate(); for (Map.Entry> entry : shownData.entrySet()) { createSeries(from, to, entry.getKey(), entry.getValue()); } updateSeries(); } private void createSeries(Date from, Date to, Item item, Set set) { TimePeriodValues values = new TimePeriodValues(item.getTypeName()); double max = 0; for (PriceHistoryData priceHistoryData : set) { Date date = priceHistoryData.getDate(); if ((from != null && !date.after(from)) || (to != null && !date.before(to))) { continue; } double price = priceHistoryData.getPrice(); max = Math.max(max, price); values.add(priceHistoryData.getTimePeriod(), price); } seriesMax.put(item, max); series.put(item, values); } private void updateSeries() { //Remove All while (dataset.getSeriesCount() != 0) { dataset.removeSeries(0); } //Add all boolean bright = ColorUtil.isBrightColor(jPanel.getBackground()); DefaultDrawingSupplier drawingSupplier = new DefaultDrawingSupplier(); for (Item item : shownOrder) { dataset.addSeries(series.get(item)); Paint paint = getColor(bright, drawingSupplier); if (paint != null) { renderer.setSeriesPaint(dataset.getSeriesCount() - 1, paint); } } updateShown(); } private Paint getColor(boolean bright, DefaultDrawingSupplier drawingSupplier) { Paint paint = drawingSupplier.getNextPaint(); if (Settings.get().isEasyChartColors() && paint instanceof Color) { Color color = (Color) paint; if (bright) { if (ColorUtil.luminance(color) > 0.8) { //Skip color > get next color return getColor(bright, drawingSupplier); } else { //OK: return color return color; } } else { if (ColorUtil.luminance(color) < 0.2) { //Skip color > get next color return getColor(bright, drawingSupplier); } else { //OK: return color return color; } } } return paint; } private void updateShown() { List selected = jItems.getSelectedValuesList(); double max = 0; int count = 0; for (int i = 0; i < dataset.getSeriesCount(); i++) { Item item = shownOrder.get(i); boolean fromVisible = renderer.isSeriesVisible(i); boolean toVisible = selected.contains(item); if (fromVisible != toVisible) { renderer.setSeriesVisible(i, toVisible); } if (toVisible) { max = Math.max(max, seriesMax.get(item)); count = Math.max(count, dataset.getItemCount(i)); } } JFreeChartUtil.updateTickScale(domainAxis, rangeLinearAxis, max); renderer.setDefaultShapesVisible(count < 2); jRemove.setEnabled(!selected.isEmpty()); jClear.setEnabled(!itemsModel.isEmpty()); jSave.setEnabled(!itemsModel.isEmpty()); } public void updateSaved() { List sets = new ArrayList<>(Settings.get().getPriceHistorySets().keySet()); jLoad.removeAll(); if (sets.isEmpty()) { jLoad.setEnabled(false); return; } jLoad.setEnabled(true); jLoad.add(jManage); jLoad.addSeparator(); Collections.sort(sets, StringComparators.CASE_INSENSITIVE); for (String name : sets) { JMenuItem jMenuItem = new JMenuItem(name, Images.FILTER_LOAD.getIcon()); jMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if ((e.getModifiers() & ActionEvent.CTRL_MASK) != 0) { addItems(Settings.get().getPriceHistorySets().get(name)); } else { setItems(Settings.get().getPriceHistorySets().get(name)); } } }); jLoad.add(jMenuItem); } } private void setUpdating(boolean updating) { jSource.setEnabled(!updating); jEdit.setEnabled(!updating); if (updating) { jSave.setEnabled(false); jLoad.setEnabled(false); } else { jSave.setEnabled(!itemsModel.isEmpty()); jLoad.setEnabled(!Settings.get().getPriceHistorySets().isEmpty()); } } private Date getFromDate() { LocalDate date = jFrom.getDate(); if (date == null) { return null; } Instant instant = date.atStartOfDay().atZone(ZoneId.of("GMT")).toInstant(); //Start of day - GMT return Date.from(instant); } private Date getToDate() { LocalDate date = jTo.getDate(); if (date == null) { return null; } Instant instant = date.atTime(23, 59, 59).atZone(ZoneId.of("GMT")).toInstant(); //End of day - GMT return Date.from(instant); } private class ListenerClass implements ActionListener, MouseListener, DateChangeListener, ListSelectionListener { @Override public void actionPerformed(ActionEvent e) { if (PriceHistoryAction.QUICK_DATE.name().equals(e.getActionCommand())) { QuickDate quickDate = (QuickDate) jQuickDate.getSelectedItem(); if (quickDate == QuickDate.RESET) { jTo.clearDate(); jFrom.clearDate(); } else { Date toDate = getToDate(); if (toDate == null) { toDate = new Date(); //now } Date fromDate = quickDate.apply(toDate); if (fromDate != null) { jFrom.setDate(fromDate); } } } else if (PriceHistoryAction.SOURCE.name().equals(e.getActionCommand())) { updateData(); } else if (PriceHistoryAction.ADD_ITEM.name().equals(e.getActionCommand())) { addItem(); } else if (PriceHistoryAction.CLEAR_ITEMS.name().equals(e.getActionCommand())) { clearItems(); updateShown(); } else if (PriceHistoryAction.REMOVE_ITEMS.name().equals(e.getActionCommand())) { removeItems(jItems.getSelectedValuesList()); } else if (PriceHistoryAction.SAVE.name().equals(e.getActionCommand())) { jSaveItemsDialog.updateData(Settings.get().getPriceHistorySets().keySet()); String name = jSaveItemsDialog.show(); if (name == null) { return; } Settings.lock("Price History (Save Set)"); Settings.get().getPriceHistorySets().put(name, new HashSet<>(shownTypeIDs)); //Copy Settings.unlock("Price History (Save Set)"); program.saveSettings("Price History (Save Set)"); updateSaved(); } else if (PriceHistoryAction.MANAGE.name().equals(e.getActionCommand())) { jItemsManagerDialog.setVisible(true); } else if (PriceHistoryAction.INCLUDE_ZERO.name().equals(e.getActionCommand())) { rangeLogarithmicAxis.setAutoRangeIncludesZero(jIncludeZero.isSelected()); rangeLinearAxis.setAutoRangeIncludesZero(jIncludeZero.isSelected()); } else if (PriceHistoryAction.LOGARITHMIC.name().equals(e.getActionCommand())) { if (jLogarithmic.isSelected()) { jFreeChart.getXYPlot().setRangeAxis(rangeLogarithmicAxis); } else { jFreeChart.getXYPlot().setRangeAxis(rangeLinearAxis); } } } @Override public void mouseClicked(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { if (e.getButton() != MouseEvent.BUTTON2) { //Middle mouse button return; } int index = jItems.locationToIndex(e.getPoint()); if (index < 0 || index > itemsModel.size()) { return; } removeItem(itemsModel.get(index)); } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void dateChanged(DateChangeEvent event) { Date from = getFromDate(); Date to = getToDate(); QuickDate quickDate = (QuickDate) jQuickDate.getSelectedItem(); if (!quickDate.isValid(from, to)) { QuickDate selected = quickDate.getSelected(from, to); jQuickDate.setSelectedItem(selected); } if (from != null && to != null && from.after(to)) { jTo.setDate(from); } createData(); } @Override public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } updateShown(); } } private class GetItems extends SwingWorker>, Void> { private final Map> data = new TreeMap<>(); private final Set blacklist = new HashSet<>(); private final Progress progress; private final Set typeIDs; public GetItems(Set typeIDs) { this.typeIDs = typeIDs; if (typeIDs.size() > 1) { progress = program.getStatusPanel().addProgress(UpdateType.PRICE_HISTORY, new StatusPanel.ProgressControl() { @Override public boolean isAuto() { return true; } @Override public void show() { } @Override public void cancel() { } @Override public void setPause(boolean pause) { } }); progress.setVisible(true); } else { progress = null; } } @Override protected Map> doInBackground() throws Exception { int done = 0; int total = typeIDs.size(); for (Integer typeID : typeIDs) { if (typeID == null) { done++; updateProgress(done, total); continue; } Item item = ApiIdConverter.getItem(typeID); //Always Add Item Set output = new TreeSet<>(); data.put(item, output); //Update Item Map input = ZkillboardPricesHistoryGetter.getPriceHistory(typeID); //Verify Data if (input == null || input.isEmpty() || !input.containsKey(PriceHistoryDatabase.getZKillboardDate())) { blacklist.add(typeID); if (input == null || input.isEmpty()) { done++; updateProgress(done, total); continue; } } //Add Data for (Map.Entry entry : input.entrySet()) { try { PriceHistoryData priceHistoryData = new PriceHistoryData(typeID, item, entry.getKey(), entry.getValue()); output.add(priceHistoryData); } catch (ParseException ex) { //Ignore data } } done++; updateProgress(done, total); } return data; } private void updateProgress(double done, double total) { if (progress == null) { return; } int progressDone = (int)(done / total * 100.0); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { progress.setValue(progressDone); } }); } @Override protected void done() { if (progress != null) { program.getStatusPanel().removeProgress(progress); } PriceHistoryDatabase.setZBlacklist(blacklist); PriceHistoryDatabase.setZKillboard(data); //Save to Database addNewItemsLocked(data); setUpdating(false); try { get(); } catch (InterruptedException ex) { LOG.error(ex.getMessage(), ex); } catch (ExecutionException ex) { LOG.error(ex.getMessage(), ex); } } } public static class PriceHistoryData implements Comparable { private final int typeID; private final Item item; private final String dateString; private final double price; private final Date date; private final SimpleTimePeriod simpleTimePeriod; public PriceHistoryData(int typeID, Item item, String dateString, double price) throws ParseException { this.typeID = typeID; this.item = item; this.dateString = dateString; this.price = price; this.date = PriceHistoryDatabase.DATE.parse(dateString); this.simpleTimePeriod = new SimpleTimePeriod(date, date); } public int getTypeID() { return typeID; } public Item getItem() { return item; } public String getDateString() { return dateString; } public double getPrice() { return price; } public Date getDate() { return date; } public SimpleTimePeriod getTimePeriod() { return simpleTimePeriod; } @Override public int compareTo(PriceHistoryData o) { int compare = item.getTypeName().compareTo(o.item.getTypeName()); if (compare != 0) { return compare; } return dateString.compareTo(o.dateString); } @Override public int hashCode() { int hash = 3; hash = 89 * hash + this.typeID; hash = 89 * hash + Objects.hashCode(this.dateString); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final PriceHistoryData other = (PriceHistoryData) obj; if (this.typeID != other.typeID) { return false; } if (!Objects.equals(this.dateString, other.dateString)) { return false; } return true; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/reprocessed/JReprocessedTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.reprocessed; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.gui.shared.table.JSeparatorTable; public class JReprocessedTable extends JSeparatorTable { private final DefaultEventTableModel tableModel; public JReprocessedTable(final Program program, final DefaultEventTableModel tableModel, SeparatorList separatorList) { super(program, tableModel, separatorList); this.tableModel = tableModel; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); boolean isSelected = isCellSelected(row, column); Object object = tableModel.getElementAt(row); //String columnName = (String) this.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); if (object instanceof ReprocessedInterface) { ReprocessedInterface reprocessed = (ReprocessedInterface) object; //Background if (reprocessed.isTotal()) { //Total ColorSettings.configCell(component, ColorEntry.GLOBAL_GRAND_TOTAL, isSelected); } } return component; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/reprocessed/ReprocessedData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.reprocessed; import ca.odell.glazedlists.EventList; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.profile.TableData; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.ReprocessedMaterial; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class ReprocessedData extends TableData { private final Map grandItems = new HashMap<>(); private ReprocessedGrandTotal grandTotal; public ReprocessedData(Program program) { super(program); } public ReprocessedData(ProfileManager profileManager, ProfileData profileData) { super(profileManager, profileData); } public EventList getData(Map items) { EventList eventList = EventListManager.create(); updateData(eventList, items); return eventList; } public void updateData(EventList eventList, Map items) { List list = new ArrayList<>(); grandItems.clear(); long grandTotalCount = 1; if (grandTotal != null) { //Save grand total count grandTotalCount = grandTotal.getCount(); } grandTotal = new ReprocessedGrandTotal(grandTotalCount); for (Map.Entry entry : items.entrySet()) { updateItem(list, entry.getKey(), entry.getValue()); } if (items.size() > 1) { grandTotal.reCalc(); list.add(grandTotal); list.addAll(grandItems.values()); } //Update list try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(list); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } public void addItem(EventList eventList, Item item, Long count) { List list = new ArrayList<>(); updateItem(list, item, count); if (!EventListManager.isEmpty(eventList)) { grandTotal.reCalc(); if (!EventListManager.contains(eventList, grandTotal)) { //Add grand totals if needed list.add(grandTotal); list.addAll(grandItems.values()); } } //Add new items try { eventList.getReadWriteLock().writeLock().lock(); eventList.addAll(list); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } public void removeItem(EventList eventList, ReprocessedTotal total) { List list = new ArrayList<>(); list.add(total); list.addAll(total.getItems()); int totals = 0; try { eventList.getReadWriteLock().readLock().lock(); for (ReprocessedInterface reprocessed : eventList) { if (reprocessed.isTotal() && !reprocessed.isGrandTotal()) { totals++; } if (totals >= 3) { break; } } } finally { eventList.getReadWriteLock().readLock().unlock(); } if (totals < 3) { //Remove grand totals if needed list.add(grandTotal); list.addAll(grandItems.values()); } //Add new items try { eventList.getReadWriteLock().writeLock().lock(); eventList.removeAll(list); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } private void updateItem(List list, Item item, Long count) { if (item.isEmpty() || item.getReprocessedMaterial().isEmpty()) { return; //Ignore types without materials } double sellPrice = ApiIdConverter.getPrice(item.getTypeID(), false); ReprocessedTotal itemTotal = new ReprocessedTotal(grandTotal, item, sellPrice, count); list.add(itemTotal); for (ReprocessedMaterial material : item.getReprocessedMaterial()) { Item materialItem = ApiIdConverter.getItem(material.getTypeID()); if (!materialItem.isEmpty()) { double price = ApiIdConverter.getPrice(materialItem.getTypeID(), false); ReprocessedItem reprocessedItem = new ReprocessedItem(itemTotal, materialItem, material, item.isOre(), price); list.add(reprocessedItem); //Total itemTotal.add(reprocessedItem); //Grand Item ReprocessedGrandItem grandItem = grandItems.get(materialItem); if (grandItem == null) { grandItem = new ReprocessedGrandItem(grandTotal, materialItem, price); grandItems.put(materialItem, grandItem); //Grand Total grandTotal.add(grandItem); } grandItem.add(reprocessedItem); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/reprocessed/ReprocessedExtendedTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.reprocessed; import java.util.Comparator; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.TabsReprocessed; public enum ReprocessedExtendedTableFormat implements EnumTableColumn { TOTAL_NAME(String.class) { @Override public String getColumnName() { return TabsReprocessed.get().columnTotalName(); } @Override public Object getColumnValue(final ReprocessedInterface from) { return from.getTotal().getTypeName(); } }, TOTAL_PRICE(Double.class) { @Override public String getColumnName() { return TabsReprocessed.get().columnTotalPrice(); } @Override public Object getColumnValue(final ReprocessedInterface from) { return from.getTotal().getSellPrice(); } }, TOTAL_VALUE(Double.class) { @Override public String getColumnName() { return TabsReprocessed.get().columnTotalValue(); } @Override public Object getColumnValue(final ReprocessedInterface from) { return from.getTotal().getValue(); } }, TOTAL_BATCH(Long.class) { @Override public String getColumnName() { return TabsReprocessed.get().columnTotalBatch(); } @Override public Object getColumnValue(final ReprocessedInterface from) { return from.getTotal().getPortionSize(); } }; private final Class type; private final Comparator comparator; private ReprocessedExtendedTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/reprocessed/ReprocessedGrandItem.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.reprocessed; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.i18n.TabsReprocessed; public class ReprocessedGrandItem extends ReprocessedTotal { private final ReprocessedGrandTotal grandTotal; private final double price; public ReprocessedGrandItem(final ReprocessedGrandTotal grandTotal, final Item item, final double price) { super(grandTotal, item, 0, 1); this.grandTotal = grandTotal; this.price = price; } @Override public boolean isTotal() { return false; } @Override public String getTypeName() { return TabsReprocessed.get().grandTotal(); } @Override public String getName() { return getItem().getTypeName(); } @Override public boolean isGrandTotal() { return true; } @Override public ReprocessedTotal getTotal() { return grandTotal; } @Override public long getPortionSize() { return 0; } @Override public Double getDynamicPrice() { return price; } @Override public long getQuantity100() { return super.getQuantity100() * grandTotal.getCount(); } @Override public long getQuantityMax() { return super.getQuantityMax() * grandTotal.getCount(); } @Override public long getQuantitySkill() { return super.getQuantitySkill() * grandTotal.getCount(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/reprocessed/ReprocessedGrandTotal.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.reprocessed; import java.util.ArrayList; import java.util.List; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.i18n.TabsReprocessed; public class ReprocessedGrandTotal extends ReprocessedTotal { private final List items = new ArrayList<>(); public ReprocessedGrandTotal(long count) { super(null, new Item(0), 0, count); } @Override public boolean isGrandTotal() { return true; } @Override public ReprocessedGrandTotal getGrandTotal() { return this; } @Override protected void reCalc() { super.reCalc(); for (ReprocessedGrandItem reprocessed : items) { reprocessed.reCalc(); } } public void add(ReprocessedGrandItem item) { super.add(item); items.add(item); } @Override public String getTypeName() { return TabsReprocessed.get().grandTotal(); } @Override public long getPortionSize() { return 0; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/reprocessed/ReprocessedInterface.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.reprocessed; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.data.settings.types.PriceType; import net.nikr.eve.jeveasset.gui.shared.CopyHandler.CopySeparator; public interface ReprocessedInterface extends Comparable, ItemType, PriceType, CopySeparator { public String getName(); public long getPortionSize(); public long getQuantity100(); public long getQuantityMax(); public long getQuantitySkill(); public double getValueMax(); public double getValueSkill(); public double getValueDifference(); public boolean isTotal(); public boolean isGrandTotal(); public ReprocessedTotal getTotal(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/reprocessed/ReprocessedItem.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.reprocessed; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.ReprocessedMaterial; import net.nikr.eve.jeveasset.data.settings.ReprocessSettings; import net.nikr.eve.jeveasset.data.settings.Settings; public class ReprocessedItem implements ReprocessedInterface { private final ReprocessedTotal total; private final Item item; private final ReprocessedMaterial material; private final boolean ore; private final double price; private final String name; public ReprocessedItem(final ReprocessedTotal parent, final Item item, final ReprocessedMaterial material, final boolean ore, final double price) { this.total = parent; this.item = item; this.material = material; this.ore = ore; this.price = price; this.name = item.getTypeName(); } @Override public ReprocessedTotal getTotal() { return total; } @Override public long getPortionSize() { return material.getPortionSize(); } private long getQuantityRaw() { return material.getQuantity() * total.getCount() / material.getPortionSize(); } @Override public long getQuantity100() { return getQuantityRaw(); } @Override public long getQuantityMax() { return ReprocessSettings.getMax(getQuantityRaw(), ore); } @Override public long getQuantitySkill() { return Settings.get().getReprocessSettings().getLeft(getQuantityRaw(), ore); } @Override public Double getDynamicPrice() { return price; } @Override public String getName() { return name; } @Override public double getValueMax() { return getDynamicPrice() * getQuantityMax(); } @Override public double getValueSkill() { return getDynamicPrice() * getQuantitySkill(); } @Override public double getValueDifference() { return getValueMax() - getValueSkill(); } @Override public String getCopyString() { StringBuilder builder = new StringBuilder(); builder.append(getTotal().getTypeName()); builder.append("\t"); builder.append(getTotal().getSellPrice()); builder.append("\t"); builder.append(getTotal().getValue()); return builder.toString(); } @Override public int compareTo(ReprocessedInterface o) { return 0; } @Override public boolean isTotal() { return false; } @Override public boolean isGrandTotal() { return false; } @Override public Item getItem() { return item; } @Override public long getItemCount() { return getQuantitySkill(); } @Override public int hashCode() { int hash = 5; hash = 29 * hash + (this.total != null ? this.total.hashCode() : 0); hash = 29 * hash + getItem().getTypeID(); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ReprocessedItem other = (ReprocessedItem) obj; if (this.total != other.total && (this.total == null || !this.total.equals(other.total))) { return false; } if (this.getItem().getTypeID() != other.getItem().getTypeID()) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/reprocessed/ReprocessedSeparatorComparator.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.reprocessed; import java.util.Comparator; public class ReprocessedSeparatorComparator implements Comparator { @Override public int compare(final ReprocessedInterface o1, final ReprocessedInterface o2) { String a = o1.getTotal().getTypeName(); String b = o2.getTotal().getTypeName(); if (o1.getTotal().isGrandTotal() && o2.getTotal().isGrandTotal()) { return a.compareToIgnoreCase(b); //Both is grand total: compare name } else if (o1.getTotal().isGrandTotal()) { return -1; //First is grand total } else if (o2.getTotal().isGrandTotal()) { return 1;//Second is grand total } else { return a.compareToIgnoreCase(b); //Not grand total: compare name } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/reprocessed/ReprocessedSeparatorTableCell.java ================================================ /* Glazed Lists (c) 2003-2006 */ /* http://publicobject.com/glazedlists/ publicobject.com,*/ /* O'Dell Engineering Ltd.*/ package net.nikr.eve.jeveasset.gui.tabs.reprocessed; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.SeparatorList.Separator; import java.awt.Color; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import javax.swing.BorderFactory; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.gui.shared.DocumentFactory; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.components.JIntegerField; import net.nikr.eve.jeveasset.gui.shared.table.SeparatorTableCell; import net.nikr.eve.jeveasset.i18n.TabsReprocessed; /** * * @author Jesse Wilson */ public class ReprocessedSeparatorTableCell extends SeparatorTableCell { public enum ReprocessedCellAction { REMOVE, UPDATE_COUNT } private final JLabel jColor; private final JButton jRemove; private final JButton jRemoveTotal; private final JIntegerField jCount; private final JLabel jName; private final JLabel jSellPriceLabel; private final JLabel jSellPrice; private final JLabel jBatchSizeLabel; private final JLabel jBatchSize; private final JLabel jValueLabel; private final JLabel jValue; private final ReprocessedTab reprocessedTab; public ReprocessedSeparatorTableCell(final ReprocessedTab reprocessedTab, final JTable jTable, final SeparatorList separatorList, final ActionListener actionListener) { super(jTable, separatorList); this.reprocessedTab = reprocessedTab; ListenerClass listener = new ListenerClass(); addCellEditorListener(listener); jColor = new JLabel(); jColor.setOpaque(true); jColor.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); jRemove = new JButton(TabsReprocessed.get().remove()); jRemove.setOpaque(false); jRemove.setActionCommand(ReprocessedCellAction.REMOVE.name()); jRemove.addActionListener(actionListener); jRemoveTotal = new JButton(TabsReprocessed.get().remove()); jRemoveTotal.setOpaque(false); jRemoveTotal.setEnabled(false); jRemoveTotal.setVisible(false); jCount = new JIntegerField("1", DocumentFactory.ValueFlag.POSITIVE_AND_NOT_ZERO); jCount.setAutoSelectAll(true); jCount.setHorizontalAlignment(JTextField.RIGHT); jCount.setActionCommand(ReprocessedCellAction.UPDATE_COUNT.name()); jCount.addActionListener(listener); jCount.addKeyListener(listener); JLabel jCountLabel = new JLabel(TabsReprocessed.get().multiplierSign()); jName = new JLabel(); Font font = jName.getFont(); jName.setFont(new Font(font.getName(), Font.BOLD, font.getSize() + 1)); jSellPriceLabel = new JLabel(TabsReprocessed.get().price()); jSellPriceLabel.setFont(new Font(font.getName(), Font.BOLD, font.getSize())); jSellPrice = new JLabel(); jBatchSizeLabel = new JLabel(TabsReprocessed.get().batch()); jBatchSizeLabel.setFont(new Font(font.getName(), Font.BOLD, font.getSize())); jBatchSize = new JLabel(); jValueLabel = new JLabel(TabsReprocessed.get().value()); jValueLabel.setFont(new Font(font.getName(), Font.BOLD, font.getSize())); jValue = new JLabel(); layout.setHorizontalGroup( layout.createSequentialGroup() .addComponent(jExpand) .addGap(5) .addComponent(jColor, Program.getButtonsHeight() - 6, Program.getButtonsHeight() - 6, Program.getButtonsHeight() - 6) .addGap(10) .addComponent(jRemove, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jRemoveTotal, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addGap(10) .addComponent(jCount, 50, 50, 50) .addComponent(jCountLabel) .addGap(10) .addComponent(jName, 220, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addGap(10) .addComponent(jSellPriceLabel) .addGap(5) .addComponent(jSellPrice) .addGap(10) .addComponent(jValueLabel) .addGap(5) .addComponent(jValue) .addGap(10) .addComponent(jBatchSizeLabel) .addGap(5) .addComponent(jBatchSize) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGap(2) .addGroup(layout.createParallelGroup() .addComponent(jExpand, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createSequentialGroup() .addGap(3) .addComponent(jColor, Program.getButtonsHeight() - 6, Program.getButtonsHeight() - 6, Program.getButtonsHeight() - 6) ) .addComponent(jRemove, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRemoveTotal, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jName, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCount, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCountLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSellPriceLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSellPrice, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jValueLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jValue, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jBatchSizeLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jBatchSize, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(2) ); } @Override protected void configure(Separator separator) { ReprocessedInterface material = (ReprocessedInterface) separator.first(); if (material == null) { // handle 'late' rendering calls after this separator is invalid return; } jRemove.setVisible(!material.getTotal().isGrandTotal()); jRemoveTotal.setVisible(material.getTotal().isGrandTotal()); jName.setText(material.getTotal().getTypeName()); //Count jCount.setText(String.valueOf(material.getTotal().getCount())); //Sell Price jSellPriceLabel.setVisible(!material.isGrandTotal()); jSellPrice.setVisible(!material.isGrandTotal()); jSellPrice.setText(Formatter.iskFormat(material.getTotal().getSellPrice())); //Value if (material.getTotal().getValue() != material.getTotal().getSellPrice()) { jValue.setText(Formatter.iskFormat(material.getTotal().getValue())); jValueLabel.setVisible(true); jValue.setVisible(true); } else { jValueLabel.setVisible(false); jValue.setVisible(false); } //Portion Size if (material.getPortionSize() > 1) { jBatchSize.setText(Formatter.longFormat(material.getPortionSize())); jBatchSizeLabel.setVisible(true); jBatchSize.setVisible(true); } else { jBatchSizeLabel.setVisible(false); jBatchSize.setVisible(false); } //Color if (material.isGrandTotal()) { ColorSettings.config(jColor, ColorEntry.REPROCESSED_EQUAL); } else if (material.getTotal().isSell()) { ColorSettings.config(jColor, ColorEntry.REPROCESSED_SELL); } else if (material.getTotal().isReprocess()) { ColorSettings.config(jColor, ColorEntry.REPROCESSED_REPROCESS); } else { ColorSettings.config(jColor, ColorEntry.REPROCESSED_EQUAL); } } private class ListenerClass implements ActionListener, CellEditorListener, KeyListener { private boolean update = true; @Override public void actionPerformed(ActionEvent e) { if (ReprocessedCellAction.UPDATE_COUNT.name().equals(e.getActionCommand())) { stopCellEditing(); } } @Override public void editingStopped(ChangeEvent e) { saveMultiplier(); } @Override public void editingCanceled(ChangeEvent e) { saveMultiplier(); } @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { update = false; stopCellEditing(); } } @Override public void keyReleased(KeyEvent e) { } private void saveMultiplier() { if (!update) { update = true; return; } ReprocessedInterface reprocessed = (ReprocessedInterface) currentSeparator.first(); if (reprocessed == null) { // handle 'late' rendering calls after this separator is invalid return; } reprocessedTab.setCount(reprocessed, jCount); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/reprocessed/ReprocessedTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.reprocessed; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.GlazedLists; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTextField; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.TextImport; import net.nikr.eve.jeveasset.gui.shared.TextImport.TextImportHandler; import net.nikr.eve.jeveasset.gui.shared.components.JAutoCompleteDialog; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JSeparatorTable; import net.nikr.eve.jeveasset.gui.shared.table.PaddingTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedSeparatorTableCell.ReprocessedCellAction; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.i18n.TabsReprocessed; import net.nikr.eve.jeveasset.io.local.text.TextImportType; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class ReprocessedTab extends JMainTabSecondary { private enum ReprocessedAction { COLLAPSE, EXPAND, CLEAR, ADD_ITEM, IMPORT_TEXT_FORMATS, } //GUI private final JSeparatorTable jTable; //Dialogs private final JAutoCompleteDialog jAddItemDialog; private final TextImport textImport; //Table private final ReprocessedFilterControl filterControl; private final EventList eventList; private final FilterList filterList; private final SeparatorList separatorList; private final DefaultEventSelectionModel selectionModel; private final DefaultEventTableModel tableModel; private final EnumTableFormatAdaptor tableFormat; //Listener private final ListenerClass listener = new ListenerClass(); //Data private final Map items = new HashMap<>(); private final ReprocessedData reprocessedData; public static final String NAME = "reprocessed"; //Not to be changed! public ReprocessedTab(final Program program) { super(program, NAME, TabsReprocessed.get().title(), Images.TOOL_REPROCESSED.getIcon(), true); reprocessedData = new ReprocessedData(program); //Add item dialog ArrayList reprocessableItems = new ArrayList<>(); for(Item item : StaticData.get().getItems().values()) { if(!item.getReprocessedMaterial().isEmpty()) { reprocessableItems.add(item); } } jAddItemDialog = new JAutoCompleteDialog<>(program, TabsReprocessed.get().addItem(), Images.TOOL_REPROCESSED.getImage(), TabsReprocessed.get().selectItem(), true, JAutoCompleteDialog.ITEM_OPTIONS); jAddItemDialog.updateData(reprocessableItems); textImport = new TextImport<>(program, NAME); JFixedToolBar jToolBar = new JFixedToolBar(); JButton jAddItem = new JButton(TabsReprocessed.get().addItem(), Images.EDIT_ADD.getIcon()); jAddItem.setActionCommand(ReprocessedAction.ADD_ITEM.name()); jAddItem.addActionListener(listener); jToolBar.addButton(jAddItem); JButton jClear = new JButton(TabsReprocessed.get().removeAll(), Images.EDIT_DELETE.getIcon()); jClear.setActionCommand(ReprocessedAction.CLEAR.name()); jClear.addActionListener(listener); jToolBar.addButton(jClear); JButton jImport = new JButton(TabsReprocessed.get().importButton(), Images.EDIT_IMPORT.getIcon()); jImport.setActionCommand(ReprocessedAction.IMPORT_TEXT_FORMATS.name()); jImport.addActionListener(listener); jToolBar.addButton(jImport); jToolBar.addGlue(); JButton jCollapse = new JButton(TabsReprocessed.get().collapse(), Images.MISC_COLLAPSED.getIcon()); jCollapse.setActionCommand(ReprocessedAction.COLLAPSE.name()); jCollapse.addActionListener(listener); jToolBar.addButton(jCollapse); JButton jExpand = new JButton(TabsReprocessed.get().expand(), Images.MISC_EXPANDED.getIcon()); jExpand.setActionCommand(ReprocessedAction.EXPAND.name()); jExpand.addActionListener(listener); jToolBar.addButton(jExpand); //Table Format tableFormat = TableFormatFactory.reprocessedTableFormat(); //Backend eventList = EventListManager.create(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedListColumn = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Sorting Total (Ensure that total is always last) eventList.getReadWriteLock().readLock().lock(); SortedList sortedListTotal = new SortedList<>(sortedListColumn, new TotalComparator()); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedListTotal); eventList.getReadWriteLock().readLock().unlock(); //Separator separatorList = new SeparatorList<>(filterList, new ReprocessedSeparatorComparator(), 1, Integer.MAX_VALUE); //Table Model tableModel = EventModels.createTableModel(separatorList, tableFormat); //Table jTable = new JReprocessedTable(program, tableModel, separatorList); jTable.setSeparatorRenderer(new ReprocessedSeparatorTableCell(this, jTable, separatorList, listener)); jTable.setSeparatorEditor(new ReprocessedSeparatorTableCell(this, jTable, separatorList, listener)); jTable.setCellSelectionEnabled(true); PaddingTableCellRenderer.install(jTable, 3); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedListColumn, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(separatorList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new ReprocessedFilterControl(sortedListTotal); //Menu installTableTool(new ReprocessedTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, ReprocessedInterface.class); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(filterControl.getPanel()) .addComponent(jToolBar, jToolBar.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void updateData() { //Save separator expanded/collapsed state jTable.saveExpandedState(); //Update Data reprocessedData.updateData(eventList, items); //Restore separator expanded/collapsed state jTable.loadExpandedState(); } @Override public void clearData() { filterControl.clearCache(); } @Override public void updateCache() { filterControl.createCache(); } @Override public Collection getLocations() { return new ArrayList<>(); //No Location } public void set(final Map newItems) { items.clear(); add(newItems); } public void add(final Map newItems) { for (Map.Entry entry : newItems.entrySet()) { Long value = entry.getValue(); if (value == null || value < 1) { value = 1L; } Long previous = items.put(entry.getKey(), value); if (previous != null) { items.put(entry.getKey(), value + previous); } } } protected void setCount(ReprocessedInterface reprocessed, JTextField jCount) { if (reprocessed == null) { return; } ReprocessedTotal total = reprocessed.getTotal(); long count; try { count = Long.parseLong(jCount.getText()); } catch (NumberFormatException ex) { count = 1; } if (count != total.getCount()) { Item item = total.getItem(); if (!total.isGrandTotal()) { items.put(item, count); } total.setCount(count); tableModel.fireTableDataChanged(); } } private ReprocessedInterface getSelectedReprocessed() { int index = jTable.getSelectedRow(); if (index < 0 || index >= tableModel.getRowCount()) { return null; } Object o = tableModel.getElementAt(index); if (o instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) o; return (ReprocessedInterface) separator.first(); } return null; } public void show() { jTable.clearExpandedState(); if (program.getMainWindow().isOpen(this)) { updateData(); //Also update data when already open } program.getMainWindow().addTab(this); } private void importText() { TextImportType systemType = TextImportType.EVE_MULTIBUY; try { systemType = TextImportType.valueOf(Settings.get().getImportSettings(NAME, systemType)); } catch (IllegalArgumentException ex) { //No problem, use default } importText("", systemType); } private void importText(String text, TextImportType selected) { textImport.importText(text, TextImportType.values(), selected, new TextImportHandler() { @Override public void addItems(JTextDialog.TextReturn textReturn) { TextImportType importType = textReturn.getType(); String importText = textReturn.getText(); Map data = importType.importText(importText); //Validate Output if (data == null || data.isEmpty()) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), GuiShared.get().textInvalid(), GuiShared.get().textImport(), JOptionPane.PLAIN_MESSAGE); importText(importText, importType); //Again! return; } //Add items Map newItems = new HashMap<>(); for (Map.Entry entry : data.entrySet()) { Item item = ApiIdConverter.getItemUpdate(entry.getKey()); newItems.put(item, entry.getValue().longValue()); } add(newItems); updateData(); } }); } private class ReprocessedTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { } @Override public void addToolMenu(JComponent jComponent) { } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (ReprocessedAction.COLLAPSE.name().equals(e.getActionCommand())) { jTable.expandSeparators(false); } else if (ReprocessedAction.EXPAND.name().equals(e.getActionCommand())) { jTable.expandSeparators(true); } else if (ReprocessedAction.CLEAR.name().equals(e.getActionCommand())) { items.clear(); updateData(); } else if (ReprocessedCellAction.REMOVE.name().equals(e.getActionCommand())) { ReprocessedInterface reprocessed = getSelectedReprocessed(); if (reprocessed != null) { ReprocessedTotal total = reprocessed.getTotal(); items.remove(total.getItem()); reprocessedData.removeItem(eventList, total); } } else if (ReprocessedAction.ADD_ITEM.name().equals(e.getActionCommand())) { Item selectedItem = jAddItemDialog.show(); if (selectedItem != null) { items.put(selectedItem, 1L); reprocessedData.addItem(eventList, selectedItem, 1L); } } else if (ReprocessedAction.IMPORT_TEXT_FORMATS.name().equals(e.getActionCommand())) { //Add stockpile (EFT Import) importText(); } } } public static class TotalComparator implements Comparator { private final Comparator comparator; public TotalComparator() { List> comparators = new ArrayList<>(); comparators.add(new ReprocessedSeparatorComparator()); comparators.add(new InnerTotalComparator()); comparator = GlazedLists.chainComparators(comparators); } @Override public int compare(final ReprocessedInterface o1, final ReprocessedInterface o2) { return comparator.compare(o1, o2); } private static class InnerTotalComparator implements Comparator { @Override public int compare(final ReprocessedInterface o1, final ReprocessedInterface o2) { if (o1.isTotal() && o2.isTotal()) { return 0; //Equal (both StockpileTotal) } else if (o1.isTotal()) { return 1; //After } else if (o2.isTotal()) { return -1; //Before } else { return 0; //Equal (not StockpileTotal) } } } } private class ReprocessedFilterControl extends FilterControl { public ReprocessedFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override protected void afterFilter() { jTable.loadExpandedState(); } @Override protected void beforeFilter() { jTable.saveExpandedState(); } @Override public void saveSettings(final String msg) { program.saveSettings("Reprocessed Table: " + msg); //Save Reprocessed Filters and Export Settings } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/reprocessed/ReprocessedTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.reprocessed; import java.util.Comparator; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.TabsReprocessed; public enum ReprocessedTableFormat implements EnumTableColumn { NAME(String.class) { @Override public String getColumnName() { return TabsReprocessed.get().columnName(); } @Override public Object getColumnValue(final ReprocessedInterface from) { return from.getName(); } }, QUANTITY_100(Long.class) { @Override public String getColumnName() { return TabsReprocessed.get().columnQuantity100(); } @Override public String getColumnToolTip() { return TabsReprocessed.get().columnQuantity100ToolTip(); } @Override public Object getColumnValue(final ReprocessedInterface from) { return from.getQuantity100(); } }, QUANTITY_MAX(Long.class) { @Override public String getColumnName() { return TabsReprocessed.get().columnQuantityMax(); } @Override public String getColumnToolTip() { return TabsReprocessed.get().columnQuantityMaxToolTip(); } @Override public Object getColumnValue(final ReprocessedInterface from) { return from.getQuantityMax(); } }, QUANTITY_SKILL(Long.class) { @Override public String getColumnName() { return TabsReprocessed.get().columnQuantitySkill(); } @Override public String getColumnToolTip() { return TabsReprocessed.get().columnQuantitySkillToolTip(); } @Override public Object getColumnValue(final ReprocessedInterface from) { return from.getQuantitySkill(); } }, PRICE(Double.class) { @Override public String getColumnName() { return TabsReprocessed.get().columnPrice(); } @Override public Object getColumnValue(final ReprocessedInterface from) { return from.getDynamicPrice(); } }, VALUE_MAX(Double.class) { @Override public String getColumnName() { return TabsReprocessed.get().columnValueMax(); } @Override public Object getColumnValue(final ReprocessedInterface from) { return from.getValueMax(); } }, VALUE_SKILL(Double.class) { @Override public String getColumnName() { return TabsReprocessed.get().columnValueSkill(); } @Override public Object getColumnValue(final ReprocessedInterface from) { return from.getValueSkill(); } }, VALUE_DIFFERENCE(Double.class) { @Override public String getColumnName() { return TabsReprocessed.get().columnValueDifference(); } @Override public Object getColumnValue(final ReprocessedInterface from) { return from.getValueDifference(); } }, TYPE_ID(Integer.class) { @Override public String getColumnName() { return TabsReprocessed.get().columnTypeID(); } @Override public Object getColumnValue(final ReprocessedInterface from) { return from.getItem().getTypeID(); } }; private final Class type; private final Comparator comparator; private ReprocessedTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/reprocessed/ReprocessedTotal.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.reprocessed; import java.util.ArrayList; import java.util.List; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.i18n.TabsReprocessed; public class ReprocessedTotal implements ReprocessedInterface { private final Item item; private final double sellPrice; private final ReprocessedGrandTotal grandTotal; //Calculated values private long count; private long portionSize; private long quantity100 = 0; private long quantityMax = 0; private long quantitySkill = 0; private double valueMax = 0; private double valueSkill = 0; private final List items = new ArrayList<>(); private final List prices = new ArrayList<>(); public ReprocessedTotal(ReprocessedGrandTotal grandTotal, Item item, double sellPrice, long count) { this.item = item; this.sellPrice = sellPrice; this.grandTotal = grandTotal; this.count = count; } public void add(final ReprocessedInterface reprocessed) { items.add(reprocessed); portionSize = reprocessed.getPortionSize(); quantity100 = quantity100 + reprocessed.getQuantity100(); quantityMax = quantityMax + reprocessed.getQuantityMax(); quantitySkill = quantitySkill + reprocessed.getQuantitySkill(); valueMax = valueMax + reprocessed.getValueMax(); valueSkill = valueSkill + reprocessed.getValueSkill(); prices.add(reprocessed.getDynamicPrice()); } public List getItems() { return items; } public long getCount() { return count; } protected void reCalc() { quantity100 = 0; quantityMax = 0; quantitySkill = 0; valueMax = 0; valueSkill = 0; for (ReprocessedInterface reprocessed : items) { quantity100 = quantity100 + reprocessed.getQuantity100(); quantityMax = quantityMax + reprocessed.getQuantityMax(); quantitySkill = quantitySkill + reprocessed.getQuantitySkill(); valueMax = valueMax + reprocessed.getValueMax(); valueSkill = valueSkill + reprocessed.getValueSkill(); } } public void setCount(long count) { boolean update = this.count != count; this.count = count; if (update) { reCalc(); if (grandTotal != null) { grandTotal.reCalc(); } } } public double getSellPrice() { return sellPrice; } public String getTypeName() { return item.getTypeName(); } public double getValue() { return getSellPrice() * count; } public boolean isSell() { return getValue() > getValueSkill(); } public boolean isReprocess() { return getValue() < getValueSkill(); } @Override public boolean isGrandTotal() { return false; } public ReprocessedGrandTotal getGrandTotal() { return grandTotal; } @Override public Item getItem() { return item; } @Override public long getItemCount() { return getQuantitySkill(); } @Override public String getName() { return TabsReprocessed.get().total(); } @Override public long getPortionSize() { return portionSize; } @Override public long getQuantity100() { return quantity100; } @Override public long getQuantityMax() { return quantityMax; } @Override public long getQuantitySkill() { return quantitySkill; } @Override public Double getDynamicPrice() { double total = 0; for (double price : prices) { total = total + price; } return total / prices.size(); } @Override public double getValueMax() { return valueMax; } @Override public double getValueSkill() { return valueSkill; } @Override public double getValueDifference() { return getValueMax() - getValueSkill(); } @Override public boolean isTotal() { return true; } @Override public ReprocessedTotal getTotal() { return this; } @Override public String getCopyString() { StringBuilder builder = new StringBuilder(); builder.append(getTypeName()); builder.append("\t"); builder.append(getSellPrice()); builder.append("\t"); builder.append(getValue()); return builder.toString(); } @Override public int compareTo(final ReprocessedInterface o) { return 0; } @Override public int hashCode() { int hash = 7; hash = 97 * hash + (this.item != null ? this.item.hashCode() : 0); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ReprocessedTotal other = (ReprocessedTotal) obj; if (this.item != other.item && (this.item == null || !this.item.equals(other.item))) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/routing/EditableListModel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.routing; import java.util.*; import javax.swing.AbstractListModel; public class EditableListModel extends AbstractListModel { private static final long serialVersionUID = 1L; private List backed = new ArrayList<>(); private Comparator sortComparator = new Comparator() { @Override public int compare(final T o1, final T o2) { return o2.hashCode() - o1.hashCode(); } }; public EditableListModel() { } public EditableListModel(final List initial) { backed.addAll(initial); } public EditableListModel(final List initial, final Comparator sortComparator) { backed.addAll(initial); setSortComparator(sortComparator); } public final void setSortComparator(final Comparator sortComparator) { this.sortComparator = sortComparator; Collections.sort(backed, sortComparator); } public Comparator getSortComparator() { return sortComparator; } public List getAll() { return Collections.unmodifiableList(backed); } @Override public int getSize() { return backed.size(); } @Override public T getElementAt(final int index) { return backed.get(index); } public T remove(final int index) { T b = backed.remove(index); fireRemoved(index, index); return b; } public void clear() { if (backed.isEmpty()) { return; } int end = backed.size() - 1; backed.clear(); fireRemoved(0, end); } public boolean remove(final T o) { int index = backed.indexOf(o); boolean b = backed.remove(o); if (b) { fireRemoved(index, index); } return b; } public boolean add(final T e) { boolean b = backed.add(e); Collections.sort(backed, sortComparator); int index = backed.indexOf(e); fireAdded(index, index); return b; } public boolean addAll(final Collection c) { boolean b = true; for (T t : c) { b = add(t) && b; } return b; } public boolean contains(final T o) { return backed.contains(o); } private void fireRemoved(final int index0, final int index1) { super.fireIntervalRemoved(this, index0, index1); } private void fireAdded(final int index0, final int index1) { super.fireIntervalAdded(this, index0, index1); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/routing/JAvoid.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.routing; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.RouteAvoidSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JAutoCompleteDialog; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.i18n.TabsRouting; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class JAvoid { public static final SolarSystemComparator SOLAR_SYSTEM_COMPARATOR = new SolarSystemComparator(); private enum AvoidAction { AVOID_ADD, AVOID_REMOVE, AVOID_CLEAR, AVOID_SAVE, AVOID_LOAD, AVOID_MANAGE, SAVE } //Filter private final JList jAvoid; private final EditableListModel avoidModel = new EditableListModel<>(); private final JButton jAdd; private final JButton jRemove; private final JButton jClear; private final JButton jSave; private final JDropDownButton jLoad; private final JLabel jSecurityIcon; private final JComboBox jSecurityMinimum; private final JLabel jSecuritySeparatorLabel; private final JComboBox jSecurityMaximum; private final JPanel jAvoidPanel; private final JPanel jSecurityPanel; //Dialogs private final JAutoCompleteDialog jSaveSystemDialog; private final JAvoidManagerDialog jAvoidManagerDialog; private final JAutoCompleteDialog jSystemDialog; private final Program program; private final ListenerClass listener; private final RouteAvoidSettings avoidSettings; private final boolean saveSettings; private final UpdateFilter updateFilter; public JAvoid(Program program, RouteAvoidSettings avoidSettings, boolean saveSettings, UpdateFilter updateFilter) { this.program = program; this.listener = new ListenerClass(); this.avoidSettings = avoidSettings; this.saveSettings = saveSettings; this.updateFilter = updateFilter; jSaveSystemDialog = new JAutoCompleteDialog<>(program, TabsRouting.get().saveFilterTitle(), Images.TOOL_ROUTING.getImage(), TabsRouting.get().saveFilterMsg(), false, JAutoCompleteDialog.STRING_OPTIONS); jAvoidManagerDialog = new JAvoidManagerDialog(this, program); jSystemDialog = new JAutoCompleteDialog<>(program, TabsRouting.get().addSystemTitle(), Images.TOOL_ROUTING.getImage(), TabsRouting.get().addSystemSelect(), true, JAutoCompleteDialog.SOLAR_SYSTEM_OPTIONS); jAvoidPanel = new JPanel(); jAvoidPanel.setBorder(BorderFactory.createTitledBorder(TabsRouting.get().avoid())); GroupLayout avoidLayout = new GroupLayout(jAvoidPanel); jAvoidPanel.setLayout(avoidLayout); avoidLayout.setAutoCreateGaps(true); avoidLayout.setAutoCreateContainerGaps(true); jSecurityPanel = new JPanel(); jSecurityPanel.setBorder(BorderFactory.createTitledBorder(TabsRouting.get().security())); GroupLayout securityLayout = new GroupLayout(jSecurityPanel); jSecurityPanel.setLayout(securityLayout); securityLayout.setAutoCreateGaps(true); securityLayout.setAutoCreateContainerGaps(true); avoidModel.setSortComparator(JAvoid.SOLAR_SYSTEM_COMPARATOR); avoidModel.addAll(avoidSettings.getAvoid().values()); jAvoid = new JList<>(avoidModel); jAvoid.addMouseListener(listener); jAvoid.addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { jRemove.setEnabled(jAvoid.getSelectedIndices().length > 0); } }); JFixedToolBar jToolBar = new JFixedToolBar(JFixedToolBar.Orientation.VERTICAL); jAdd = new JButton(TabsRouting.get().avoidAdd(), Images.EDIT_ADD.getIcon()); jAdd.setActionCommand(AvoidAction.AVOID_ADD.name()); jAdd.addActionListener(listener); jToolBar.addButton(jAdd); jRemove = new JButton(TabsRouting.get().avoidRemove(), Images.EDIT_DELETE.getIcon()); jRemove.setActionCommand(AvoidAction.AVOID_REMOVE.name()); jRemove.addActionListener(listener); jRemove.setEnabled(false); jToolBar.addButton(jRemove); jClear = new JButton(TabsRouting.get().avoidClear(), Images.FILTER_CLEAR.getIcon()); jClear.setActionCommand(AvoidAction.AVOID_CLEAR.name()); jClear.addActionListener(listener); jToolBar.addButton(jClear); jSave = new JButton(TabsRouting.get().avoidSave(), Images.FILTER_SAVE.getIcon()); jSave.setActionCommand(AvoidAction.AVOID_SAVE.name()); jSave.addActionListener(listener); jToolBar.addButton(jSave); jLoad = new JDropDownButton(TabsRouting.get().avoidLoad(), Images.FILTER_LOAD.getIcon()); jToolBar.addButton(jLoad); JScrollPane jAvoidScroll = new JScrollPane(jAvoid); Double[] security = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}; jSecurityIcon = new JLabel(); jSecurityMinimum = new JComboBox<>(security); jSecurityMinimum.setSelectedItem(avoidSettings.getSecMin()); jSecurityMinimum.setActionCommand(AvoidAction.SAVE.name()); jSecurityMinimum.addActionListener(listener); jSecuritySeparatorLabel = new JLabel(" - "); jSecurityMaximum = new JComboBox<>(security); jSecurityMaximum.setSelectedItem(avoidSettings.getSecMax()); jSecurityMaximum.setActionCommand(AvoidAction.SAVE.name()); jSecurityMaximum.addActionListener(listener); updateFilterLabels(); updateSavedFilters(); avoidLayout.setHorizontalGroup( avoidLayout.createSequentialGroup() .addComponent(jAvoidScroll, 300, 300, Integer.MAX_VALUE) .addComponent(jToolBar) ); avoidLayout.setVerticalGroup( avoidLayout.createParallelGroup(GroupLayout.Alignment.LEADING, false) .addComponent(jAvoidScroll, 160, 160, Integer.MAX_VALUE) .addComponent(jToolBar) ); securityLayout.setHorizontalGroup( securityLayout.createSequentialGroup() .addComponent(jSecurityIcon) .addComponent(jSecurityMinimum, 80, 80, Short.MAX_VALUE) .addComponent(jSecuritySeparatorLabel) .addComponent(jSecurityMaximum, 80, 80, Short.MAX_VALUE) ); securityLayout.setVerticalGroup( securityLayout.createParallelGroup(GroupLayout.Alignment.LEADING, false) .addComponent(jSecurityIcon, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSecurityMinimum, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSecuritySeparatorLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSecurityMaximum, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } public void setData(RouteAvoidSettings current) { avoidSettings.update(current); avoidModel.clear(); avoidModel.addAll(current.getAvoid().values()); jSecurityMinimum.setSelectedItem(current.getSecMin()); jSecurityMaximum.setSelectedItem(current.getSecMax()); updateFilterLabels(); updateSavedFilters(); } public void setEnabled(boolean b) { jAvoid.setEnabled(b); jAdd.setEnabled(b); if (b) { jRemove.setEnabled(jAvoid.getSelectedIndices().length > 0); jClear.setEnabled(!avoidModel.getAll().isEmpty()); jSave.setEnabled(!avoidModel.getAll().isEmpty()); jLoad.setEnabled(!avoidSettings.getPresets().isEmpty()); } else { jRemove.setEnabled(b); jClear.setEnabled(b); jSave.setEnabled(b); jLoad.setEnabled(b); } jSecurityMinimum.setEnabled(b); jSecuritySeparatorLabel.setEnabled(b); jSecurityMaximum.setEnabled(b); } public Double getSecurityMinimum() { if (jSecurityMinimum != null) { return (Double) jSecurityMinimum.getSelectedItem(); } else { return 0.0; } } private void setSecurityMaximum(Double d) { jSecurityMaximum.setSelectedItem(d); } public Double getSecurityMaximum() { if (jSecurityMaximum != null) { return (Double) jSecurityMaximum.getSelectedItem(); } else { return 1.0; } } public void updateSystemDialog(Set nodes) { jSystemDialog.updateData(nodes); //Will be replaced by valid systems by processRouteInner() } public final void updateFilterLabels() { double secMin = avoidSettings.getSecMin(); if (secMin == 0.0) { jSecurityIcon.setIcon(Images.UPDATE_CANCELLED.getIcon()); } else if (secMin >= 0.5) { jSecurityIcon.setIcon(Images.UPDATE_DONE_OK.getIcon()); } else { jSecurityIcon.setIcon(Images.UPDATE_DONE_SOME.getIcon()); } jClear.setEnabled(!avoidModel.getAll().isEmpty()); jSave.setEnabled(!avoidModel.getAll().isEmpty()); jLoad.setEnabled(!avoidSettings.getPresets().isEmpty()); if (updateFilter != null) { updateFilter.updateFilterLabels(); } } private void updateSavedFilters() { jLoad.removeAll(); JMenuItem jManage = new JMenuItem(TabsRouting.get().avoidManage(), Images.DIALOG_SETTINGS.getIcon()); jManage.setActionCommand(AvoidAction.AVOID_MANAGE.name()); jManage.addActionListener(listener); jLoad.add(jManage); if (!avoidSettings.getPresets().isEmpty()) { jLoad.addSeparator(); } ArrayList presets = new ArrayList<>(avoidSettings.getPresets().keySet()); Collections.sort(presets); for (String name : presets) { JMenuItem jMenuItem = new JLoadMenuItem(name, avoidSettings.getPresets().get(name)); jMenuItem.setActionCommand(AvoidAction.AVOID_LOAD.name()); jMenuItem.addActionListener(listener); jLoad.add(jMenuItem); } jLoad.setEnabled(!avoidSettings.getPresets().isEmpty()); jAvoidManagerDialog.updateData(); } public void loadFilter(Set systemIds) { avoidModel.clear(); if (saveSettings) { Settings.lock("Route Avoid (Load Filter)"); } avoidSettings.getAvoid().clear(); for (Long systemID : systemIds) { SolarSystem system = new SolarSystem(ApiIdConverter.getLocation(systemID)); avoidSettings.getAvoid().put(system.getSystemID(), system); avoidModel.add(system); } if (saveSettings) { Settings.unlock("Route Avoid (Load Filter)"); program.saveSettings("Route Avoid (Load Filter)"); } updateFilterLabels(); } public void deleteFilters(List list) { if (saveSettings) { Settings.lock("Route Avoid (Delete Filters)"); } for (String filter : list) { avoidSettings.getPresets().remove(filter); } if (saveSettings) { Settings.unlock("Route Avoid (Delete Filters)"); program.saveSettings("Route Avoid (Delete Filters)"); } updateSavedFilters(); } public void renameFilter(String name, String oldName) { if (saveSettings) { Settings.lock("Route Avoid (Rename Filter)"); } Set systemIDs = avoidSettings.getPresets().remove(oldName); avoidSettings.getPresets().put(name, systemIDs); if (saveSettings) { Settings.unlock("Route Avoid (Rename Filter)"); program.saveSettings("Route Avoid (Rename Filter)"); } updateSavedFilters(); } public void mergeFilters(String name, List list) { Set systemIDs = new HashSet<>(); if (saveSettings) { Settings.lock("Route Avoid (Merge Filters)"); } for (String mergeName : list) { systemIDs.addAll(avoidSettings.getPresets().get(mergeName)); } avoidSettings.getPresets().put(name, systemIDs); if (saveSettings) { Settings.unlock("Route Avoid (Merge Filters)"); program.saveSettings("Route Avoid (Merge Filters)"); } updateSavedFilters(); } private void removeSystems() { if (saveSettings) { Settings.lock("Route Avoid (Delete Systems)"); } for (SolarSystem system : jAvoid.getSelectedValuesList()) { avoidModel.remove(system); avoidSettings.getAvoid().remove(system.getSystemID()); } if (saveSettings) { Settings.unlock("Route Avoid (Delete Systems)"); program.saveSettings("Route Avoid (Delete Systems)"); } updateFilterLabels(); } public JPanel getAvoidPanel() { return jAvoidPanel; } public JPanel getSecurityPanel() { return jSecurityPanel; } public static class SolarSystemComparator implements Comparator { @Override public int compare(SolarSystem o1, SolarSystem o2) { return o1.getName().compareToIgnoreCase(o2.getName()); } } public static class JLoadMenuItem extends JMenuItem { private final Set systemIDs; public JLoadMenuItem(String name, Set systemIDs) { super(name, Images.FILTER_LOAD.getIcon()); this.systemIDs = systemIDs; } public Set getSystemIDs() { return systemIDs; } } private class ListenerClass extends MouseAdapter implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (AvoidAction.AVOID_REMOVE.name().equals(e.getActionCommand())) { removeSystems(); } else if (AvoidAction.AVOID_CLEAR.name().equals(e.getActionCommand())) { if (saveSettings) { Settings.lock("Route Avoid (Clear Systems)"); } avoidSettings.getAvoid().clear(); avoidModel.clear(); updateFilterLabels(); if (saveSettings) { Settings.unlock("Route Avoid (Clear Systems)"); program.saveSettings("Route Avoid (Clear Systems)"); } } else if (AvoidAction.AVOID_ADD.name().equals(e.getActionCommand())) { SolarSystem system = jSystemDialog.show(); if (system != null) { if (saveSettings) { Settings.lock("Route Avoid (Add System)"); } avoidSettings.getAvoid().put(system.getSystemID(), system); avoidModel.clear(); avoidModel.addAll(avoidSettings.getAvoid().values()); if (saveSettings) { Settings.unlock("Route Avoid (Add System)"); program.saveSettings("Route Avoid (Add System)"); } updateFilterLabels(); } } else if (AvoidAction.AVOID_SAVE.name().equals(e.getActionCommand())) { jSaveSystemDialog.updateData(new ArrayList<>(avoidSettings.getPresets().keySet())); String name = jSaveSystemDialog.show(); if (name != null) { if (saveSettings) { Settings.lock("Route Avoid (Save Filter)"); } Set systemIDs = new HashSet<>(); for (SolarSystem system : avoidModel.getAll()) { systemIDs.add(system.getSystemID()); } avoidSettings.getPresets().put(name, systemIDs); if (saveSettings) { Settings.unlock("Route Avoid (Save Filter)"); program.saveSettings("Route Avoid (Save Filter)"); } updateSavedFilters(); } } else if (AvoidAction.AVOID_LOAD.name().equals(e.getActionCommand())) { Object source = e.getSource(); if (source instanceof JLoadMenuItem) { JLoadMenuItem menuItem = (JLoadMenuItem) source; loadFilter(menuItem.getSystemIDs()); } } else if (AvoidAction.AVOID_MANAGE.name().equals(e.getActionCommand())) { jAvoidManagerDialog.updateData(); jAvoidManagerDialog.setVisible(true); } else if (AvoidAction.SAVE.name().equals(e.getActionCommand())) { double min = getSecurityMinimum(); double max = getSecurityMaximum(); if (max < min) { max = min; setSecurityMaximum(min); } if (saveSettings) { Settings.lock("Route Avoid (Security)"); } avoidSettings.setSecMin(min); avoidSettings.setSecMax(max); if (saveSettings) { Settings.unlock("Route Avoid (Security)"); program.saveSettings("Route Avoid (Security)"); } updateFilterLabels(); } } @Override public void mouseClicked(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount()% 2 == 0 && !e.isControlDown() && !e.isShiftDown() ) { if (e.getSource().equals(jAvoid) && jAvoid.isEnabled()) { removeSystems(); } } } } public static interface UpdateFilter { public void updateFilterLabels(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/routing/JAvoidManagerDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.routing; import java.util.List; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.components.JManagerDialog; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.i18n.TabsRouting; public class JAvoidManagerDialog extends JManagerDialog { private final JAvoid jAvoid; public JAvoidManagerDialog(JAvoid jAvoid, Program program) { super(program, program.getMainWindow().getFrame(), TabsRouting.get().manageFiltersTitle(), true, false, false, true, false); this.jAvoid = jAvoid; } public void updateData() { update(Settings.get().getRoutingSettings().getPresets().keySet()); } @Override protected void load(String name) { jAvoid.loadFilter(Settings.get().getRoutingSettings().getPresets().get(name)); setVisible(false); } @Override protected void edit(String name) { //Edit is not supported } @Override protected void merge(String name, List list) { jAvoid.mergeFilters(name, list); } @Override protected void copy(String fromName, String toName) { //Copy is not supported } @Override protected void rename(String name, String oldName) { jAvoid.renameFilter(name, oldName); } @Override protected void delete(List list) { jAvoid.deleteFilters(list); } @Override protected void export(List list) { //Export is not supported } @Override protected void importData() { //Import is not supported } @Override protected String textDeleteMultipleMsg(int size) { return TabsRouting.get().deleteAvoids(size); } @Override protected String textDelete() { return TabsRouting.get().deleteAvoid(); } @Override protected String textEnterName() { return TabsRouting.get().enterAvoidName(); } @Override protected String textMerge() { return TabsRouting.get().mergeAvoids(); } @Override protected String textRename() { return TabsRouting.get().renameAvoid(); } @Override protected String textOverwrite() { return TabsRouting.get().overwriteAvoid(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/routing/JRouteEditDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.routing; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.DefaultListModel; import javax.swing.DropMode; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.RouteResult; import net.nikr.eve.jeveasset.gui.dialogs.settings.ShowToolSettingsPanel.ListItemTransferHandler; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.i18n.TabsRouting; import uk.me.candle.eve.graph.DisconnectedGraphException; import uk.me.candle.eve.graph.Graph; public class JRouteEditDialog extends JDialogCentered { private final DefaultListModel model = new DefaultListModel<>(); private final JList jRoute; private final JButton jOK; private final JLabel jJumps; private final JLabel jDelta; private final JLabel jAvoid; private final JLabel jSecurity; private final RoutingTab routingTab; private Map systemCache; private Graph filteredGraph; private RouteResult routeResult; private RouteResult returnResult; private boolean updating = false; public JRouteEditDialog(RoutingTab routingTab, Program program) { super(program, TabsRouting.get().resultEditTitle()); this.routingTab = routingTab; jJumps = new JLabel(); jDelta = new JLabel(); jAvoid = new JLabel(); jSecurity = new JLabel(); JLabel jHelp = new JLabel(TabsRouting.get().resultEditHelp()); jHelp.setEnabled(false); jRoute = new JList<>(model); jRoute.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); jRoute.setTransferHandler(new ListItemTransferHandler()); jRoute.setDropMode(DropMode.INSERT); jRoute.setDragEnabled(true); jOK = new JButton(TabsRouting.get().ok()); jOK.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { save(); } }); JButton jCancel = new JButton(TabsRouting.get().cancel()); jCancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setVisible(false); } }); model.addListDataListener(new ListDataListener() { @Override public void intervalAdded(ListDataEvent e) { } @Override public void intervalRemoved(ListDataEvent e) { recalculateRoutes(); } @Override public void contentsChanged(ListDataEvent e) { } }); JScrollPane jToolsScroll = new JScrollPane(jRoute); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jJumps) .addGap(2) .addComponent(jDelta) ) .addComponent(jAvoid, 300, 300, 300) .addComponent(jSecurity, 300, 300, 300) .addComponent(jHelp, 300, 300, 300) .addComponent(jToolsScroll, 300, 300, 300) .addGroup(layout.createSequentialGroup() .addGap(0, 0, Integer.MAX_VALUE) .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jJumps) .addComponent(jDelta) ) .addComponent(jAvoid) .addComponent(jSecurity) .addComponent(jHelp) .addComponent(jToolsScroll, 300, 300, 300) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } private boolean recalculateRoutes() { if (updating) { return false; } List list = new ArrayList<>(); for (int i = 0; i < model.size(); i++) { list.add(model.get(i)); } try { int jumps = 0; Route last = null; for (Route route : list) { if (last != null) { jumps = jumps + distanceBetween(systemCache, filteredGraph, last, route); } last = route; } jumps = jumps + distanceBetween(systemCache, filteredGraph, last, list.get(0)); calculateInfo(jumps); return true; } catch (DisconnectedGraphException ex) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame() , ex.getMessage() , TabsRouting.get().error() , JOptionPane.ERROR_MESSAGE); return false; } } private void calculateInfo(int jumps) { if (jumps > routeResult.getJumps()) { jDelta.setText("+" + (jumps - routeResult.getJumps())); ColorSettings.config(jDelta, ColorEntry.GLOBAL_VALUE_NEGATIVE); } else if (jumps < routeResult.getJumps()) { jDelta.setText("-" + (routeResult.getJumps() - jumps)); ColorSettings.config(jDelta, ColorEntry.GLOBAL_VALUE_POSITIVE); } else { jDelta.setText(""); } jJumps.setText(TabsRouting.get().resultEditJumps(jumps)); } private static List routeBetween(Map systemCache, Graph filteredGraph, Route from, Route to) { return filteredGraph.routeBetween(systemCache.get(from.getSystemID()), systemCache.get(to.getSystemID())); } private static int distanceBetween(Map systemCache, Graph filteredGraph, Route from, Route to) { return filteredGraph.distanceBetween(systemCache.get(from.getSystemID()), systemCache.get(to.getSystemID())); } @Override protected JComponent getDefaultFocus() { return jOK; } @Override protected JButton getDefaultButton() { return jOK; } public RouteResult show(Map systemCache, Graph filteredGraph, RouteResult routeResult) { updating = true; this.filteredGraph = filteredGraph; this.systemCache = systemCache; this.routeResult = routeResult; this.returnResult = null; //Reset model.removeAllElements(); for (List jumps : routeResult.getRoute()) { SolarSystem solarSystem = jumps.get(0); Route route = new Route(solarSystem.getLocationID(), solarSystem.getSystem()); model.addElement(route); } jAvoid.setText(TabsRouting.get().resultEditAvoid(routingTab.getAvoidString())); jSecurity.setText((TabsRouting.get().resultEditSecurity(routingTab.getSecurityString()))); calculateInfo(routeResult.getJumps()); updating = false; boolean valid = recalculateRoutes(); if (valid) { setVisible(true); } return returnResult; } @Override protected void windowShown() {} @Override protected void save() { List list = new ArrayList<>(); for (int i = 0; i < model.size(); i++) { list.add(model.get(i)); } try { returnResult = makeRouteResult(routingTab, systemCache, filteredGraph, list, TabsRouting.get().resultEdited(), routeResult.getStations()); } catch (DisconnectedGraphException ex) { returnResult = null; } setVisible(false); } public static RouteResult makeRouteResult(RoutingTab routingTab, Map systemCache, Graph filteredGraph, List list, String algorithmName) throws DisconnectedGraphException { return makeRouteResult(routingTab, systemCache, filteredGraph, list, algorithmName, new HashMap<>()); } private static RouteResult makeRouteResult(RoutingTab routingTab, Map systemCache, Graph filteredGraph, List list, String algorithmName, Map> stations) throws DisconnectedGraphException { List> routes = new ArrayList<>(); int jumps = 0; Route last = null; for (Route route : list) { if (last != null) { jumps = jumps + distanceBetween(systemCache, filteredGraph, last, route); routes.add(routeBetween(systemCache, filteredGraph, last, route)); } last = route; } jumps = jumps + distanceBetween(systemCache, filteredGraph, last, list.get(0)); routes.add(routeBetween(systemCache, filteredGraph, last, list.get(0))); return new RouteResult(routes, stations, routes.size(), algorithmName, 0, jumps, routingTab.getAvoidString(), routingTab.getSecurityString()); } public static class Route implements Serializable { private final long systemID; private final String system; public Route(long systemID, String system) { this.systemID = systemID; this.system = system; } public long getSystemID() { return systemID; } @Override public String toString() { return system; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/routing/JRouteManagerDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.routing; import java.util.List; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.RouteResult; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.components.JManagerDialog; import net.nikr.eve.jeveasset.i18n.TabsRouting; public class JRouteManagerDialog extends JManagerDialog { private final RoutingTab routingTab; public JRouteManagerDialog(RoutingTab routingTab, Program program) { super(program, program.getMainWindow().getFrame(), TabsRouting.get().resultManageTitle(), true, false, false, false, false); this.routingTab = routingTab; } public void updateData() { update(Settings.get().getRoutingSettings().getRoutes().keySet()); } @Override protected void load(String name) { RouteResult routeResult = Settings.get().getRoutingSettings().getRoutes().get(name); routingTab.setRouteResult(routeResult); routingTab.updateRoutes(); setVisible(false); } @Override protected void edit(String name) { //Edit is not supported } @Override protected void merge(String name, List list) { //Merge is not supported } @Override protected void copy(String fromName, String toName) { //Copy is not supported } @Override protected void rename(String name, String oldName) { Settings.lock("Routing (Rename Route)"); RouteResult routeResult = Settings.get().getRoutingSettings().getRoutes().remove(oldName); Settings.get().getRoutingSettings().getRoutes().put(name, routeResult); Settings.unlock("Routing (Rename Route)"); program.saveSettings("Routing (Rename Route)"); routingTab.updateRoutes(); } @Override protected void delete(List list) { Settings.lock("Routing (Delete Routes)"); for (String name : list) { Settings.get().getRoutingSettings().getRoutes().remove(name); } Settings.unlock("Routing (Delete Routes)"); program.saveSettings("Routing (Delete Routes)"); routingTab.updateRoutes(); } @Override protected void export(List list) { //Export is not supported } @Override protected void importData() { //Import is not supported } @Override protected String textDeleteMultipleMsg(int size) { return TabsRouting.get().routeDeleteMsg(size); } @Override protected String textDelete() { return TabsRouting.get().routeDeleteTitle(); } @Override protected String textEnterName() { return TabsRouting.get().routeSaveMsg(); } @Override protected String textMerge() { return ""; } //Not supported @Override protected String textRename() { return TabsRouting.get().routeRenameTitle(); } @Override protected String textOverwrite() { return TabsRouting.get().routeOverwrite(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/routing/MoveJList.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.routing; import javax.swing.JList; import javax.swing.ListModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MoveJList extends JList { private static final Logger LOG = LoggerFactory.getLogger(MoveJList.class); private static final long serialVersionUID = 1L; public MoveJList() { setModel(new EditableListModel()); } public MoveJList(final EditableListModel editableListModel) { setModel(editableListModel); } public MoveJList(final ListModel dataModel) { EditableListModel m = new EditableListModel(); for (int i = 0; i < dataModel.getSize(); ++i) { m.add(dataModel.getElementAt(i)); } setModel(m); } public EditableListModel getEditableModel() { return (EditableListModel) getModel(); } /** * * @param to * @param limit * @return true if all the items were added. */ public boolean move(final MoveJList to, final int limit) { EditableListModel fModel = getEditableModel(); EditableListModel tModel = to.getEditableModel(); for (T ss : getSelectedValuesList()) { if (fModel.contains(ss)) { if (to.getModel().getSize() < limit) { LOG.debug("Moving {}", ss); if (fModel.remove(ss)) { tModel.add(ss); } } else { setSelectedIndices(new int[]{}); to.setSelectedIndices(new int[]{}); return false; } } } setSelectedIndices(new int[]{}); to.setSelectedIndices(new int[]{}); return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/routing/RoutingTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.routing; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.swing.AutoCompleteSupport; import java.awt.Color; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.JTextArea; import javax.swing.JToggleButton; import javax.swing.JToolBar; import javax.swing.SwingWorker; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.RouteFinder; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.RouteResult; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.TextImport; import net.nikr.eve.jeveasset.gui.shared.TextImport.TextImportHandler; import net.nikr.eve.jeveasset.gui.shared.components.JAutoCompleteDialog; import net.nikr.eve.jeveasset.gui.shared.components.JCustomFileChooser; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JImportDialog; import net.nikr.eve.jeveasset.gui.shared.components.JImportDialog.ImportReturn; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.components.JMultiSelectionDialog; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog.SimpleTextImport; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog.TextReturn; import net.nikr.eve.jeveasset.gui.shared.components.ListComboBoxModel; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuUI; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuUI.EveGatecampCheck; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.EventModels.StringFilterator; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewGroup; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewLocation; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewLocation.LocationType; import net.nikr.eve.jeveasset.gui.tabs.routing.JAvoid.UpdateFilter; import net.nikr.eve.jeveasset.gui.tabs.routing.JRouteEditDialog.Route; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.i18n.TabsRouting; import net.nikr.eve.jeveasset.io.esi.AbstractEsiGetter; import net.nikr.eve.jeveasset.io.local.SettingsReader; import net.nikr.eve.jeveasset.io.local.SettingsWriter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import uk.me.candle.eve.graph.DisconnectedGraphException; import uk.me.candle.eve.graph.Graph; import uk.me.candle.eve.graph.distances.Jumps; import uk.me.candle.eve.routing.BruteForce; import uk.me.candle.eve.routing.Crossover; import uk.me.candle.eve.routing.NearestNeighbour; import uk.me.candle.eve.routing.Progress; import uk.me.candle.eve.routing.RoutingAlgorithm; import uk.me.candle.eve.routing.SimpleUnisexMutatorHibrid2Opt; import uk.me.candle.eve.routing.cancel.CancelService; /** * * @author Candle */ public class RoutingTab extends JMainTabSecondary implements UpdateFilter { private static final Logger LOG = LoggerFactory.getLogger(RoutingTab.class); enum ImportSystemType implements SimpleTextImport { SYSTEM_NAMES(TabsRouting.get().resultImportNames(), SYSTEM_NAMES_EXAMPLE, Images.STOCKPILE_SHOPPING_LIST.getIcon()), SYSTEM_IDS(TabsRouting.get().resultImportIDs(), SYSTEM_IDS_EXAMPLE, Images.LOC_SYSTEM.getIcon()); private final String type; private final String example; private final Icon icon; private ImportSystemType(String type, String example, Icon icon) { this.type = type; this.example = example; this.icon = icon; } @Override public String getType() { return type; } @Override public String getExample() { return example; } @Override public Icon getIcon() { return icon; } } private static final String SYSTEM_NAMES_EXAMPLE = "Jita\n" + "Sobaseki\n" + "Malkalen\n" + "New Caldari\n" + "Niyabainen\n" + "Perimeter\n" + "Maurasi"; private static final String SYSTEM_IDS_EXAMPLE = "30000142 30001363 30001393 30000145 30000143 30000144 30000140"; private enum RoutingAction { ADD, REMOVE, IMPORT_SYSTEMS, ADD_SYSTEM, ADD_STATION, SOURCE, ALGORITHM, ALGORITHM_HELP, CALCULATE, EVE_UI, ROUTE_SAVE, ROUTE_EDIT, ROUTE_MANAGE, IMPORT_ROUTE_XML, IMPORT_ROUTE, ROUTE_EXPORT, } //Routing private JLabel jAlgorithmLabel; private JComboBox jAlgorithm; private JButton jAlgorithmInfo; private JLabel jFilterLabel; private JLabel jFilterSecurityIcon; private JLabel jFilterSecurity; private JLabel jFilterSystemIcon; private JLabel jFilterSystem; private JLabel jSourceLabel; private JComboBox jSource; private JToggleButton jSystems; private JToggleButton jStations; private JLabel jStartLabel; private JComboBox jStart; private EventList startEventList; private MoveJList jAvailable; private JLabel jAvailableRemaining; private JButton jAdd; private JButton jRemove; private JButton jImportSystems; private JButton jAddSystem; private JButton jAddStation; private MoveJList jWaypoints; private JLabel jWaypointsRemaining; //Filter private JAvoid jAvoid; //Progress private JProgressBar jProgress; private JButton jCalculate; //Result private JTextArea jResult; private JTextArea jFullResult; private JTextArea jInfo; private List resultToolbars = new ArrayList<>(); //Dialogs private TextImport textImport; private JTextDialog jImportSystemsDialog; private JAutoCompleteDialog jStationDialog; private JAutoCompleteDialog jSystemDialog; private JAutoCompleteDialog jSaveRouteDialog; private JRouteManagerDialog jRouteManagerDialog; private JRouteEditDialog jRouteEditDialog; private JMultiSelectionDialog jRouteSelectionDialog; private JCustomFileChooser jFileChooser; private JImportDialog jImportDialog; private ListenerClass listener; private RouteFind routeFind; //Data private final Map systemCache = new HashMap<>(); private final Set available = new HashSet<>(); protected Graph filteredGraph; private double lastSecMin = 0.0; private double lastSecMax = 1.0; private List lastAvoid = new ArrayList<>(); private boolean uiEnabled = true; private RouteResult routeResult = null; public static final String NAME = "routing"; //Not to be changed! /** * * @param load does nothing except change the signature. */ protected RoutingTab(final boolean load) { super(load); } public RoutingTab(final Program program) { super(program, NAME, TabsRouting.get().routingTitle(), Images.TOOL_ROUTING.getIcon(), true); listener = new ListenerClass(); textImport = new TextImport<>(program, NAME); jImportSystemsDialog = new JTextDialog(program.getMainWindow().getFrame()); jStationDialog = new JAutoCompleteDialog<>(program, TabsRouting.get().addStationTitle(), Images.TOOL_ROUTING.getImage(), TabsRouting.get().addStationSelect(), true, JAutoCompleteDialog.LOCATION_OPTIONS); jSystemDialog = new JAutoCompleteDialog<>(program, TabsRouting.get().addSystemTitle(), Images.TOOL_ROUTING.getImage(), TabsRouting.get().addSystemSelect(), true, JAutoCompleteDialog.SOLAR_SYSTEM_OPTIONS); jSaveRouteDialog = new JAutoCompleteDialog<>(program, TabsRouting.get().routeSaveTitle(), Images.TOOL_ROUTING.getImage(), TabsRouting.get().routeSaveMsg(), false, JAutoCompleteDialog.STRING_OPTIONS); jRouteManagerDialog = new JRouteManagerDialog(this, program); jRouteEditDialog = new JRouteEditDialog(this, program); jRouteSelectionDialog = new JMultiSelectionDialog<>(program, TabsRouting.get().resultSelectRoutes()); jFileChooser = new JCustomFileChooser("xml"); jFileChooser.setMultiSelectionEnabled(false); jFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); jImportDialog = new JImportDialog(program, new JImportDialog.ImportOptions() { @Override public boolean isRenameSupported() { return true; } @Override public boolean isMergeSupported() { return false; } @Override public boolean isOverwriteSupported() { return true; } @Override public boolean isSkipSupported() { return true; } @Override public String getTextRenameHelp() { return TabsRouting.get().importOptionsRenameHelp(); } @Override public String getTextMergeHelp() { return ""; } @Override public String getTextOverwriteHelp() { return TabsRouting.get().importOptionsOverwriteHelp(); } @Override public String getTextSkipHelp() { return TabsRouting.get().importOptionsSkipHelp(); } @Override public String getTextAll(int count) { return TabsRouting.get().importOptionsAll(count); } }); //Routing JPanel jRoutingPanel = new JPanel(); GroupLayout routingLayout = new GroupLayout(jRoutingPanel); jRoutingPanel.setLayout(routingLayout); routingLayout.setAutoCreateGaps(true); routingLayout.setAutoCreateContainerGaps(true); jAlgorithmLabel = new JLabel(TabsRouting.get().algorithm()); jAlgorithm = new JComboBox<>(new ListComboBoxModel<>(RoutingAlgorithmContainer.getRegisteredList())); jAlgorithm.setSelectedIndex(0); jAlgorithm.setActionCommand(RoutingAction.ALGORITHM.name()); jAlgorithm.addActionListener(listener); jAlgorithmInfo = new JButton(Images.MISC_HELP.getIcon()); jAlgorithmInfo.setActionCommand(RoutingAction.ALGORITHM_HELP.name()); jAlgorithmInfo.addActionListener(listener); jFilterLabel = new JLabel(TabsRouting.get().filters()); jFilterSecurityIcon = new JLabel(); jFilterSecurity = new JLabel(); jFilterSystemIcon = new JLabel(Images.LOC_SYSTEM.getIcon()); jFilterSystem = new JLabel(); jFilterSystem.setIconTextGap(4); jSourceLabel = new JLabel(TabsRouting.get().source()); jSource = new JComboBox<>(); jSource.setActionCommand(RoutingAction.SOURCE.name()); jSource.addActionListener(listener); ButtonGroup buttonGroup = new ButtonGroup(); jStations = new JToggleButton(Images.LOC_STATION.getIcon()); jStations.setHorizontalAlignment(JToggleButton.LEFT); jStations.setActionCommand(RoutingAction.SOURCE.name()); jStations.addActionListener(listener); buttonGroup.add(jStations); jSystems = new JToggleButton(Images.LOC_SYSTEM.getIcon()); jSystems.setHorizontalAlignment(JToggleButton.LEFT); jSystems.setSelected(true); jSystems.setActionCommand(RoutingAction.SOURCE.name()); jSystems.addActionListener(listener); buttonGroup.add(jSystems); //Start system jStartLabel = new JLabel(TabsRouting.get().startSystem()); jStart = new JComboBox<>(); jStart.setEnabled(false); startEventList = EventListManager.create(); AutoCompleteSupport startAutoComplete = AutoCompleteSupport.install(jStart, EventModels.createSwingThreadProxyList(startEventList), new StringFilterator()); startAutoComplete.setStrict(true); try { startEventList.getReadWriteLock().writeLock().lock(); startEventList.add(TabsRouting.get().startEmpty()); } finally { startEventList.getReadWriteLock().writeLock().unlock(); } jStart.setSelectedItem(TabsRouting.get().startEmpty()); jAvoid = new JAvoid(program, Settings.get().getRoutingSettings().getAvoidSettings(), true, this); jAvailable = new MoveJList<>(new EditableListModel<>()); jAvailable.getEditableModel().setSortComparator(JAvoid.SOLAR_SYSTEM_COMPARATOR); jAvailable.addMouseListener(listener); jAvailable.addListSelectionListener(listener); jAvailableRemaining = new JLabel(); jAdd = new JButton(TabsRouting.get().add()); jAdd.setActionCommand(RoutingAction.ADD.name()); jAdd.addActionListener(listener); jRemove = new JButton(TabsRouting.get().remove()); jRemove.setActionCommand(RoutingAction.REMOVE.name()); jRemove.addActionListener(listener); jImportSystems = new JButton(Images.EDIT_IMPORT.getIcon()); jImportSystems.setActionCommand(RoutingAction.IMPORT_SYSTEMS.name()); jImportSystems.addActionListener(listener); jAddSystem = new JButton(TabsRouting.get().addSystem(), Images.LOC_SYSTEM.getIcon()); jAddSystem.setHorizontalAlignment(JToggleButton.LEFT); jAddSystem.setActionCommand(RoutingAction.ADD_SYSTEM.name()); jAddSystem.addActionListener(listener); jAddStation = new JButton(TabsRouting.get().addStation(), Images.LOC_STATION.getIcon()); jAddStation.setHorizontalAlignment(JToggleButton.LEFT); jAddStation.setActionCommand(RoutingAction.ADD_STATION.name()); jAddStation.addActionListener(listener); jWaypoints = new MoveJList<>(new EditableListModel<>()); jWaypoints.getEditableModel().setSortComparator(JAvoid.SOLAR_SYSTEM_COMPARATOR); jWaypoints.addMouseListener(listener); jWaypoints.addListSelectionListener(listener); jWaypointsRemaining = new JLabel(); JScrollPane jAvailableScroll = new JScrollPane(jAvailable); JScrollPane jWaypointsScroll = new JScrollPane(jWaypoints); routingLayout.setHorizontalGroup( routingLayout.createSequentialGroup() .addGroup(routingLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(routingLayout.createSequentialGroup() .addGroup(routingLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jAlgorithmLabel) .addComponent(jSourceLabel) ) .addGroup(routingLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(routingLayout.createSequentialGroup() .addComponent(jAlgorithm) .addGap(5) .addComponent(jAlgorithmInfo, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) ) .addComponent(jSource) ) ) .addComponent(jAvailableScroll, 300, 300, Short.MAX_VALUE) .addGroup(routingLayout.createSequentialGroup() .addComponent(jAvailableRemaining, 0, 0, Short.MAX_VALUE) .addComponent(jSystems, 65, 65, 65) .addComponent(jStations, 65, 65, 65) ) ) .addGroup(routingLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jAdd, 80, 80, 80) .addComponent(jRemove, 80, 80, 80) ) .addGroup(routingLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(routingLayout.createSequentialGroup() .addGroup(routingLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jStartLabel) .addComponent(jFilterLabel) ) .addGroup(routingLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(routingLayout.createSequentialGroup() .addComponent(jFilterSecurityIcon) .addGap(0) .addComponent(jFilterSecurity) .addGap(20) .addComponent(jFilterSystemIcon) .addGap(4) .addComponent(jFilterSystem) ) .addComponent(jStart) ) ) .addComponent(jWaypointsScroll, 300, 300, Integer.MAX_VALUE) .addGroup(routingLayout.createSequentialGroup() .addComponent(jWaypointsRemaining, 0, 0, Integer.MAX_VALUE) .addComponent(jImportSystems, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) .addComponent(jAddSystem, 65, 65, 65) .addComponent(jAddStation, 65, 65, 65) ) ) ); routingLayout.setVerticalGroup( routingLayout.createSequentialGroup() .addGroup(routingLayout.createParallelGroup(GroupLayout.Alignment.LEADING, false) .addComponent(jAlgorithmLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jAlgorithm, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jAlgorithmInfo, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFilterLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFilterSecurityIcon, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFilterSecurity, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFilterSystemIcon, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFilterSystem, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(routingLayout.createParallelGroup(GroupLayout.Alignment.LEADING, false) .addComponent(jSourceLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSource, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jStartLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jStart, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(routingLayout.createParallelGroup(GroupLayout.Alignment.CENTER, false) .addComponent(jAvailableScroll, 130, 130, Integer.MAX_VALUE) .addComponent(jWaypointsScroll, 130, 130, Integer.MAX_VALUE) .addGroup(routingLayout.createSequentialGroup() .addComponent(jAdd, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRemove, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ) .addGroup(routingLayout.createParallelGroup(GroupLayout.Alignment.LEADING, false) .addComponent(jAvailableRemaining, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSystems, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jStations, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jWaypointsRemaining, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jImportSystems, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jAddStation, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jAddSystem, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); //Filters JPanel jFilterPanel = new JPanel(); GroupLayout filterLayout = new GroupLayout(jFilterPanel); jFilterPanel.setLayout(filterLayout); filterLayout.setAutoCreateGaps(true); filterLayout.setAutoCreateContainerGaps(true); filterLayout.setHorizontalGroup( filterLayout.createSequentialGroup() .addComponent(jAvoid.getAvoidPanel()) .addComponent(jAvoid.getSecurityPanel()) ); filterLayout.setVerticalGroup( filterLayout.createParallelGroup(GroupLayout.Alignment.LEADING, false) .addComponent(jAvoid.getAvoidPanel()) .addComponent(jAvoid.getSecurityPanel()) ); //Progress jProgress = new JProgressBar(); jProgress.setValue(0); jProgress.setMaximum(100); jProgress.setMinimum(0); jCalculate = new JButton(TabsRouting.get().calculate()); jCalculate.setActionCommand(RoutingAction.CALCULATE.name()); jCalculate.addActionListener(listener); //Result JPanel jResultPanel = new JPanel(); GroupLayout resultLayout = new GroupLayout(jResultPanel); jResultPanel.setLayout(resultLayout); resultLayout.setAutoCreateGaps(true); resultLayout.setAutoCreateContainerGaps(false); JPanel jFullResultPanel = new JPanel(); GroupLayout fullResultLayout = new GroupLayout(jFullResultPanel); jFullResultPanel.setLayout(fullResultLayout); fullResultLayout.setAutoCreateGaps(true); fullResultLayout.setAutoCreateContainerGaps(false); JPanel jInfoPanel = new JPanel(); GroupLayout infoLayout = new GroupLayout(jInfoPanel); jInfoPanel.setLayout(infoLayout); infoLayout.setAutoCreateGaps(true); infoLayout.setAutoCreateContainerGaps(false); ResultToolbar jResultPanelToolBar = new ResultToolbar(); resultToolbars.add(jResultPanelToolBar); jResult = new JTextArea(); jResult.setEditable(false); jResult.setFont(jPanel.getFont()); ResultToolbar jFullResultToolBar = new ResultToolbar(); resultToolbars.add(jFullResultToolBar); jFullResult = new JTextArea(); jFullResult.setEditable(false); jFullResult.setFont(jPanel.getFont()); ResultToolbar jInfoToolBar = new ResultToolbar(); resultToolbars.add(jInfoToolBar); jInfo = new JTextArea(); jInfo.setEditable(false); jInfo.setFont(jPanel.getFont()); final JScrollPane jResultScroll = new JScrollPane(jResult, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); JScrollPane jFullResultScroll = new JScrollPane(jFullResult, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); jFullResultScroll.getVerticalScrollBar().setModel(jResultScroll.getVerticalScrollBar().getModel()); jFullResultScroll.setWheelScrollingEnabled(false); jFullResultScroll.addMouseWheelListener(new MouseWheelListener() { @Override public void mouseWheelMoved(MouseWheelEvent e) { jResultScroll.dispatchEvent(e); } }); JScrollPane jInfoScroll = new JScrollPane(jInfo); resultLayout.setHorizontalGroup( resultLayout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jResultPanelToolBar.getComponent()) .addComponent(jResultScroll) ); resultLayout.setVerticalGroup( resultLayout.createSequentialGroup() .addComponent(jResultPanelToolBar.getComponent()) .addComponent(jResultScroll) ); fullResultLayout.setHorizontalGroup( fullResultLayout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jFullResultToolBar.getComponent()) .addComponent(jFullResultScroll) ); fullResultLayout.setVerticalGroup( fullResultLayout.createSequentialGroup() .addComponent(jFullResultToolBar.getComponent()) .addComponent(jFullResultScroll) ); infoLayout.setHorizontalGroup( infoLayout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jInfoToolBar.getComponent()) .addComponent(jInfoScroll) ); infoLayout.setVerticalGroup( infoLayout.createSequentialGroup() .addComponent(jInfoToolBar.getComponent()) .addComponent(jInfoScroll) ); JTabbedPane jResultTabs = new JTabbedPane(); jResultTabs.addTab(TabsRouting.get().resultTabShort(), jResultPanel); jResultTabs.addTab(TabsRouting.get().resultTabFull(), jFullResultPanel); jResultTabs.addTab(TabsRouting.get().resultTabInfo(), jInfoPanel); JTabbedPane jSystemTabs = new JTabbedPane(); jSystemTabs.addTab(TabsRouting.get().routingTab(), jRoutingPanel); jSystemTabs.addTab(TabsRouting.get().filtersTab(), jFilterPanel); // widths are defined in here. layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jSystemTabs) .addGroup(layout.createSequentialGroup() .addComponent(jProgress, GroupLayout.DEFAULT_SIZE, 100, Short.MAX_VALUE) .addComponent(jCalculate) ) .addComponent(jResultTabs) ); // heights are defined here. layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jSystemTabs, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, false) .addComponent(jProgress, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCalculate, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jResultTabs) ); buildGraph(true); //Build default Graph (0.0/All sec - no avoids) jSystemDialog.updateData(filteredGraph.getNodes()); //Will be replaced by valid systems by processRouteInner() jAvoid.updateSystemDialog(filteredGraph.getNodes()); //Will be replaced by valid systems by processRouteInner() } @Override public void updateData() { //Do everything the constructor does... jAvailable.getEditableModel().clear(); jWaypoints.getEditableModel().clear(); overviewGroupsChanged(); jAlgorithm.setSelectedIndex(0); jResult.setText(TabsRouting.get().emptyResult()); jResult.setCaretPosition(0); jResult.setEnabled(false); jFullResult.setText(TabsRouting.get().emptyResult()); jFullResult.setCaretPosition(0); jFullResult.setEnabled(false); jInfo.setText(TabsRouting.get().emptyResult()); jInfo.setCaretPosition(0); jInfo.setEnabled(false); List stations = new ArrayList<>(); for (MyLocation location : StaticData.get().getLocations()) { if (location.isStation()) { //Not Planet stations.add(location); } } jStationDialog.updateData(stations); updateRemaining(); processFilteredAssets(); updateRoutes(); } public void overviewGroupsChanged() { List sources = new ArrayList<>(); for (Entry entry : Settings.get().getOverviewGroups().entrySet()) { sources.add(new SourceItem(entry.getKey(), true)); } Collections.sort(sources); sources.add(0, new SourceItem(TabsRouting.get().filteredAssets())); sources.add(0, new SourceItem(General.get().all())); jSource.setModel(new ListComboBoxModel<>(sources)); } @Override public void clearData() { RoutingAlgorithm.setCache(false); //Clear cache } @Override public void updateCache() {} @Override public Collection getLocations() { return new ArrayList<>(); //No Location } public void updateRoutes() { for (ResultToolbar resultToolbar : resultToolbars) { resultToolbar.update(); } jRouteManagerDialog.updateData(); jSaveRouteDialog.updateData(Settings.get().getRoutingSettings().getRoutes().keySet()); } public SolarSystem getSolarSystem() { return jSystemDialog.show(); } private void updateRemaining() { updateWaypointsRemaining(); updateAvailableRemaining(); validateLists(); } private void updateWaypointsRemaining() { int max = ((RoutingAlgorithmContainer) jAlgorithm.getSelectedItem()).getWaypointLimit(); int cur = getWaypointsSize(); if (max < cur) { jWaypointsRemaining.setForeground(Color.RED); } else if (max == cur) { jWaypointsRemaining.setForeground(Color.BLUE); } else { jWaypointsRemaining.setForeground(Color.BLACK); } jWaypointsRemaining.setText(TabsRouting.get().allowed(cur, max)); } private void updateAvailableRemaining() { int cur = jAvailable.getModel().getSize(); int tot = cur + getWaypointsSize(); jAvailableRemaining.setText(TabsRouting.get().total(cur, tot)); } protected final void buildGraph(boolean all) { // build the graph. // filter the solarsystems based on the settings. if (filteredGraph != null) { filteredGraph.clear(); } filteredGraph = new Graph<>(new Jumps<>()); RouteFinder.generateGraph(systemCache, filteredGraph, all ? null : Settings.get().getRoutingSettings().getAvoidSettings()); } protected void processFilteredAssets() { // select the active places. List assets; SourceItem source = (SourceItem) jSource.getSelectedItem(); if (source.getName().equals(General.get().all())) { //ALL assets = new ArrayList<>(program.getAssetsList()); } else if (source.getName().equals(TabsRouting.get().filteredAssets())) { //FILTERS assets = program.getAssetsTab().getFilteredAssets(); } else { //OVERVIEW GROUP assets = new ArrayList<>(); OverviewGroup group = Settings.get().getOverviewGroups().get(source.getName()); for (OverviewLocation location : group.getLocations()) { for (MyAsset asset : program.getAssetsList()) { if ((location.getName().equals(asset.getLocation().getLocation())) || (location.getType() == LocationType.TYPE_SYSTEM && location.getName().equals(asset.getLocation().getSystem())) || (location.getType() == LocationType.TYPE_CONSTELLATION && location.getName().equals(asset.getLocation().getConstellation())) || (location.getType() == LocationType.TYPE_REGION && location.getName().equals(asset.getLocation().getRegion())) ) { assets.add(asset); } } } } SortedSet allLocs = new TreeSet<>(new Comparator() { @Override public int compare(final SolarSystem o1, final SolarSystem o2) { String n1 = o1.getName(); String n2 = o2.getName(); return n1.compareToIgnoreCase(n2); } }); for (MyAsset ea : assets) { SolarSystem loc = null; if (jSystems.isSelected()) { //System loc = systemCache.get(ea.getLocation().getSystemID()); } else if (ea.getLocation().isStation()) { //Not planet loc = new SolarSystem(ea.getLocation()); } if (loc != null && (loc.getRegionID() < 11000000 || loc.getRegionID() > 13000000)) { //Ignore Wormhole and Abyssal Regions allLocs.add(loc); } else { LOG.debug("ignoring {}", ea.getLocation().getLocation()); } } available.clear(); available.addAll(allLocs); jAvailable.getEditableModel().addAll(allLocs); for (SolarSystem system : jWaypoints.getEditableModel().getAll()) { jAvailable.getEditableModel().remove(system); } if (jSystems.isSelected()) { jSystems.setText(TabsRouting.get().checked()); jStations.setText(TabsRouting.get().unchecked()); } else { jSystems.setText(TabsRouting.get().unchecked()); jStations.setText(TabsRouting.get().checked()); } updateRemaining(); } /** * Moves the selected items in the 'from' JList to the 'to' JList. * * @param from * @param to * @return true if all the items were moved. */ private void move(final MoveJList from, final MoveJList to) { for (SolarSystem ss : from.getSelectedValuesList()) { if (from.getEditableModel().contains(ss)) { LOG.debug("Moving {}", ss); if (from.getEditableModel().remove(ss)) { to.getEditableModel().add(ss); } } } from.setSelectedIndices(new int[]{}); to.setSelectedIndices(new int[]{}); List systems = new ArrayList<>(jAvailable.getEditableModel().getAll()); for (SolarSystem system : systems) { if (!available.contains(system)) { jAvailable.getEditableModel().remove(system); } } to.requestFocusInWindow(); updateRemaining(); } private void processRoute() { //Disable the UI controls setUIEnabled(false); //Reset Progress jProgress.setValue(0); jProgress.setIndeterminate(true); //Create Thread routeFind = new RouteFind(); //Add progress listener routeFind.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { int progress = (Integer) evt.getNewValue(); if (jProgress.isIndeterminate() && progress > 0) { jProgress.setIndeterminate(false); } jProgress.setValue(progress); } } }); //Start Thread routeFind.execute(); } private void processRouteInner() { try { //Update Graph if needed (AKA filter has changed) if (lastSecMin != jAvoid.getSecurityMinimum() || lastSecMax != jAvoid.getSecurityMaximum() || !lastAvoid.equals(new ArrayList<>(Settings.get().getRoutingSettings().getAvoid().keySet()))) { buildGraph(false); lastSecMin = jAvoid.getSecurityMinimum(); lastSecMax = jAvoid.getSecurityMaximum(); lastAvoid = new ArrayList<>(Settings.get().getRoutingSettings().getAvoid().keySet()); } //Warning for 2 or less systems if (getWaypointsSize() <= 2) { Program.ensureEDT(new Runnable() { @Override public void run() { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsRouting.get().noSystems(), TabsRouting.get().noSystemsTitle(), JOptionPane.INFORMATION_MESSAGE); } }); return; } routeResult = null; //Clear previous results Program.ensureEDT(new Runnable() { @Override public void run() { jResult.setText(TabsRouting.get().emptyResult()); jResult.setCaretPosition(0); jResult.setEnabled(false); jFullResult.setText(TabsRouting.get().emptyResult()); jFullResult.setCaretPosition(0); jFullResult.setEnabled(false); jResult.setCaretPosition(0); jInfo.setText(TabsRouting.get().emptyResult()); jInfo.setCaretPosition(0); jInfo.setEnabled(false); for (ResultToolbar resultToolbar : resultToolbars) { resultToolbar.setEnabledResult(false); resultToolbar.update(); } } }); String start = jStart.getItemAt(jStart.getSelectedIndex()); String startSystem = null; //Update all SolarSystem with the latest from the new Graph //This is needed to get the proper Edge(s) parsed to the routing Algorithm Map> stationsMap = new HashMap<>(); Set waypoints = new HashSet<>(); for (SolarSystem solarSystem : jWaypoints.getEditableModel().getAll()) { if (solarSystem.isStation()) { //Not Planet List stations = stationsMap.get(solarSystem.getSystemID()); if (stations == null) { stations = new ArrayList<>(); stationsMap.put(solarSystem.getSystemID(), stations); } stations.add(solarSystem); } SolarSystem cachedSystem = systemCache.get(solarSystem.getSystemID()); if (start.equals(solarSystem.getName())) { startSystem = cachedSystem.getName(); } waypoints.add(cachedSystem); } List inputWaypoints = new ArrayList<>(waypoints); //Move frist system to the top.... if (!start.contains(TabsRouting.get().startEmpty())) { String startText; if (startSystem != null) { startText = startSystem; } else { startText = start; } Collections.sort(inputWaypoints, new Comparator() { @Override public int compare(SolarSystem o1, SolarSystem o2) { if (o1.getName().equals(startText) && o2.getName().equals(startText)) { return 0; //Equal } else if (o1.getName().equals(startText)) { return -1; //Before } else if (o2.getName().equals(startText)) { return 1; //After } else { return o1.getName().compareTo(o2.getName()); } } }); } //Start route finding: RoutingAlgorithmContainer algorithm = (RoutingAlgorithmContainer) jAlgorithm.getSelectedItem(); List nodeRoute = executeRouteFinding(inputWaypoints, algorithm); if (nodeRoute.isEmpty()) { //Cancelled algorithm.resetCancelService(); return; } else { //Completed! Program.ensureEDT(new Runnable() { @Override public void run() { jProgress.setValue(jProgress.getMaximum()); } }); } SolarSystem last = null; List> route = new ArrayList<>(); for (SolarSystem current : nodeRoute) { if (last != null) { route.add(new ArrayList<>(filteredGraph.routeBetween(last, current))); } last = current; } if (last != null) { route.add(new ArrayList<>(filteredGraph.routeBetween(last, nodeRoute.get(0)))); } setRouteResult(new RouteResult(route, stationsMap, inputWaypoints.size(), algorithm.getName(), algorithm.getLastTimeTaken(), algorithm.getLastDistance(), getAvoidString(), getSecurityString())); } catch (DisconnectedGraphException dce) { Program.ensureEDT(new Runnable() { @Override public void run() { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), dce.getMessage(), TabsRouting.get().error(), JOptionPane.ERROR_MESSAGE); } }); } } public String getSecurityString() { final StringBuilder builder = new StringBuilder(); builder.append(Formatter.securityFormat(jAvoid.getSecurityMinimum())); builder.append(" - "); builder.append(Formatter.securityFormat(jAvoid.getSecurityMaximum())); return builder.toString(); } public String getAvoidString() { final StringBuilder builder = new StringBuilder(); for (SolarSystem avoidSystem : Settings.get().getRoutingSettings().getAvoid().values()) { if (!builder.toString().isEmpty()) { builder.append(", "); } builder.append(avoidSystem.getName()); } if (builder.toString().isEmpty()) { builder.append(TabsRouting.get().avoidNone()); } return builder.toString(); } public void setRouteResult(RouteResult routeResult) { this.routeResult = routeResult; //Route Result final StringBuilder fullRouteString = new StringBuilder(); final StringBuilder routeString = new StringBuilder(); boolean first = true; for (List systems : routeResult.getRoute()) { if (first) { first = false; } else { fullRouteString.append('\n'); routeString.append('\n'); } boolean firstFull = true; for (SolarSystem routeSystem : systems) { if (firstFull) { firstFull = false; fullRouteString.append(routeSystem.getName()); } else { fullRouteString.append(TabsRouting.get().resultArrow()); fullRouteString.append(routeSystem.getName()); } } routeString.append(systems.get(0).getName()); List stations = routeResult.getStations().get(systems.get(0).getSystemID()); if (stations != null) { for (SolarSystem station : stations) { fullRouteString.append("\n • "); fullRouteString.append(station.getName()); routeString.append("\n • "); routeString.append(station.getName()); } } } //Set results Program.ensureEDT(new Runnable() { @Override public void run() { jResult.setText(routeString.toString()); jResult.setEnabled(true); jResult.setCaretPosition(0); jFullResult.setText(fullRouteString.toString()); jFullResult.setEnabled(true); jFullResult.setCaretPosition(0); jInfo.setText(TabsRouting.get().resultText(routeResult.getAlgorithmName(), routeResult.getJumps(), routeResult.getWaypoints(), routeResult.getSecurity(), routeResult.getAvoid(), Formatter.milliseconds(routeResult.getAlgorithmTime()))); jInfo.setEnabled(true); jInfo.setCaretPosition(0); for (ResultToolbar resultToolbar : resultToolbars) { resultToolbar.setEnabledResult(true); resultToolbar.update(); } } }); } protected Graph getGraph() { return filteredGraph; } private List executeRouteFinding(final List inputWaypoints, final RoutingAlgorithmContainer algorithm) { return algorithm.execute(routeFind, filteredGraph, inputWaypoints); } private void setUIEnabled(final boolean b) { uiEnabled = b; //Routing jAlgorithmLabel.setEnabled(b); jAlgorithm.setEnabled(b); jAlgorithmInfo.setEnabled(b); jFilterLabel.setEnabled(b); jFilterSecurity.setEnabled(b); jFilterSystem.setEnabled(b); jSourceLabel.setEnabled(b); jSource.setEnabled(b); jStartLabel.setEnabled(b); if (jStart.getItemAt(jStart.getSelectedIndex()).contains(TabsRouting.get().startEmpty())) { jStart.setEnabled(false); } else { jStart.setEnabled(b); } jAvailable.setEnabled(b); jAvailableRemaining.setEnabled(b); jAdd.setEnabled(b); jRemove.setEnabled(b); jImportSystems.setEnabled(b); jAddSystem.setEnabled(b); jAddStation.setEnabled(b); jSystems.setEnabled(b); jStations.setEnabled(b); jWaypoints.setEnabled(b); jWaypointsRemaining.setEnabled(b); //Filters jAvoid.setEnabled(b); for (ResultToolbar resultToolbar : resultToolbars) { resultToolbar.setEnabled(b); } //Process if (b) { jCalculate.setText(TabsRouting.get().calculate()); } else { jCalculate.setText(TabsRouting.get().cancel()); } } private void cancelProcessing() { ((RoutingAlgorithmContainer) jAlgorithm.getSelectedItem()).getCancelService().cancel(); } private int getWaypointsSize() { Set waypoints = new HashSet<>(); for (SolarSystem solarSystem : jWaypoints.getEditableModel().getAll()) { waypoints.add(solarSystem.getSystemID()); } return waypoints.size(); } private void validateLists() { int waypointsSize = getWaypointsSize(); if (uiEnabled) { jRemove.setEnabled(jWaypoints.getSelectedIndices().length > 0); jAdd.setEnabled(jAvailable.getSelectedIndices().length > 0); } jCalculate.setEnabled(waypointsSize <= ((RoutingAlgorithmContainer) jAlgorithm.getSelectedItem()).getWaypointLimit()); if (jWaypoints.getEditableModel().getAll().isEmpty()) { try { startEventList.getReadWriteLock().writeLock().lock(); startEventList.clear(); startEventList.add(TabsRouting.get().startEmpty()); } finally { startEventList.getReadWriteLock().writeLock().unlock(); } jStart.setSelectedItem(TabsRouting.get().startEmpty()); jStart.setEnabled(false); } else { String selected = jStart.getItemAt(jStart.getSelectedIndex()); Set systems = new TreeSet<>(); for (SolarSystem system : jWaypoints.getEditableModel().getAll()) { systems.add(system.getName()); } try { startEventList.getReadWriteLock().writeLock().lock(); startEventList.clear(); startEventList.addAll(systems); } finally { startEventList.getReadWriteLock().writeLock().unlock(); } jStart.setEnabled(true); if (systems.contains(selected)) { jStart.setSelectedItem(selected); } else { jStart.setSelectedItem(systems.iterator().next()); } } } public void addLocation(MyLocation location) { if (location == null) { return; //Cancel } SolarSystem system = systemCache.get(location.getSystemID()); if (system == null) { return; //Ignore system that was not found } SolarSystem solarSystem = new SolarSystem(location); if (!jWaypoints.getEditableModel().contains(solarSystem) && !jAvailable.getEditableModel().contains(solarSystem)) { //New jWaypoints.getEditableModel().add(solarSystem); } else if (jAvailable.getEditableModel().contains(solarSystem)) { //In available: moving to waypoints jAvailable.getEditableModel().remove(solarSystem); jWaypoints.getEditableModel().add(solarSystem); } //Else: Already in waypoints - do nothing updateRemaining(); } private ImportReturn importOptions(final RouteResult routeResult, final String routeName, ImportReturn importReturn, final int count) { if (importReturn != ImportReturn.OVERWRITE_ALL && importReturn != ImportReturn.MERGE_ALL && importReturn != ImportReturn.RENAME_ALL && importReturn != ImportReturn.SKIP_ALL) { //Not decided - ask what to do importReturn = jImportDialog.show(routeName, count); } //Rename if (importReturn == ImportReturn.RENAME || importReturn == ImportReturn.RENAME_ALL) { String name = jSaveRouteDialog.show(routeName); if (name == null) { return importOptions(routeResult, routeName, ImportReturn.RENAME, count); } Settings.get().getRoutingSettings().getRoutes().put(name, routeResult); updateRoutes(); } //Overwrite if (importReturn == ImportReturn.OVERWRITE || importReturn == ImportReturn.OVERWRITE_ALL) { Settings.get().getRoutingSettings().getRoutes().put(routeName, routeResult); updateRoutes(); } //Skip - Do nothing return importReturn; } private boolean makeRoute(List list) { if (list.isEmpty()) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsRouting.get().resultImportRouteEmpty(), TabsRouting.get().resultImportRoute(), JOptionPane.PLAIN_MESSAGE); return false; } if (list.size() < 2) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsRouting.get().resultImportRouteInvalid(), TabsRouting.get().resultImportRoute(), JOptionPane.PLAIN_MESSAGE); return false; } RouteResult result; try { result = JRouteEditDialog.makeRouteResult(this, systemCache, filteredGraph, list, TabsRouting.get().resultImported()); } catch (DisconnectedGraphException ex) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), ex.getMessage(), TabsRouting.get().error(), JOptionPane.ERROR_MESSAGE); return false; } if (jResult.isEnabled()) { int value = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), TabsRouting.get().resultOverwrite(), TabsRouting.get().resultImportRoute(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (value != JOptionPane.OK_OPTION) { return false; } } setRouteResult(result); return true; } private void importText() { ImportSystemType systemType = ImportSystemType.SYSTEM_NAMES; try { systemType = ImportSystemType.valueOf(Settings.get().getImportSettings(NAME, systemType)); } catch (IllegalArgumentException ex) { //No problem, use default } importText("", systemType); } private void importText(String text, ImportSystemType selected) { textImport.importText(text, ImportSystemType.values(), selected, new TextImportHandler() { @Override public void addItems(TextReturn textReturn) { String importText = textReturn.getText(); ImportSystemType importType = textReturn.getType(); if (importText == null || importType == null) { return; //Cancel } List list = new ArrayList<>(); if (importType == ImportSystemType.SYSTEM_NAMES) { //Build lookup map Map systems = new HashMap<>(); for (SolarSystem node : systemCache.values()) { systems.put(node.getSystem().toLowerCase(), node); } //For each line, check if the line matches a system name for (String line : importText.split("[\r\n]+")) { SolarSystem system = systems.get(line.toLowerCase().trim()); if (system != null) { list.add(new Route(system.getSystemID(), system.getName())); } } } else if (importType == ImportSystemType.SYSTEM_IDS) { //For each line, check if the line matches a system name for (String line : importText.split("\\s+")) { try { long systemID = Long.parseLong(line.toLowerCase().trim()); SolarSystem system = systemCache.get(systemID); if (system != null) { list.add(new Route(system.getSystemID(), system.getName())); } } catch (NumberFormatException ex) { //Try next line... } } } boolean update = makeRoute(list); if (!update) { importText(importText, importType); } } }); } @Override public void updateFilterLabels() { double secMin = Settings.get().getRoutingSettings().getSecMin(); double secMax = Settings.get().getRoutingSettings().getSecMax(); int size = Settings.get().getRoutingSettings().getAvoid().size(); jFilterSecurity.setText(Formatter.securityFormat(secMin) + " - " + Formatter.securityFormat(secMax)); if (secMin == 0.0) { jFilterSecurityIcon.setIcon(Images.UPDATE_CANCELLED.getIcon()); } else if (secMin >= 0.5) { jFilterSecurityIcon.setIcon(Images.UPDATE_DONE_OK.getIcon()); } else { jFilterSecurityIcon.setIcon(Images.UPDATE_DONE_SOME.getIcon()); } jFilterSystem.setText(String.valueOf(size)); } private class ListenerClass extends MouseAdapter implements ActionListener, ListSelectionListener { @Override public void actionPerformed(final ActionEvent e) { LOG.debug(e.getActionCommand()); if (RoutingAction.ADD.name().equals(e.getActionCommand())) { move(jAvailable, jWaypoints); } else if (RoutingAction.REMOVE.name().equals(e.getActionCommand())) { move(jWaypoints, jAvailable); } else if (RoutingAction.CALCULATE.name().equals(e.getActionCommand())) { if (jCalculate.getText().equals(TabsRouting.get().cancel())) { cancelProcessing(); } else { if (jResult.isEnabled()) { int value = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), TabsRouting.get().resultOverwrite(), TabsRouting.get().calculate(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (value != JOptionPane.OK_OPTION) { return; } } processRoute(); } } else if (RoutingAction.SOURCE.name().equals(e.getActionCommand())) { jAvailable.getEditableModel().clear(); processFilteredAssets(); } else if (RoutingAction.ALGORITHM.name().equals(e.getActionCommand())) { updateRemaining(); } else if (RoutingAction.ALGORITHM_HELP.name().equals(e.getActionCommand())) { RoutingAlgorithmContainer rac = ((RoutingAlgorithmContainer) jAlgorithm.getSelectedItem()); JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), rac.getBasicDescription(), rac.getName(), JOptionPane.INFORMATION_MESSAGE); } else if (RoutingAction.IMPORT_SYSTEMS.name().equals(e.getActionCommand())) { String importText = jImportSystemsDialog.importText("", SYSTEM_NAMES_EXAMPLE); if (importText == null || importText.isEmpty()) { return; } //Build lookup map Map systems = new HashMap<>(); for (SolarSystem node : systemCache.values()) { systems.put(node.getSystem().toLowerCase(), node); } //For each line, check if the line matches a system name for (String line : importText.split("[\r\n]+")) { SolarSystem system = systems.get(line.toLowerCase().trim()); if (system != null) { if (!jWaypoints.getEditableModel().contains(system) && !jAvailable.getEditableModel().contains(system)) { //New jWaypoints.getEditableModel().add(system); } else if (jAvailable.getEditableModel().contains(system)) { //In available: moving to waypoints jAvailable.getEditableModel().remove(system); jWaypoints.getEditableModel().add(system); } //Else: Already in waypoints - do nothing } } updateRemaining(); } else if (RoutingAction.ADD_STATION.name().equals(e.getActionCommand())) { MyLocation station = jStationDialog.show(); addLocation(station); } else if (RoutingAction.ADD_SYSTEM.name().equals(e.getActionCommand())) { SolarSystem system = jSystemDialog.show(); if (system != null) { if (!jWaypoints.getEditableModel().contains(system) && !jAvailable.getEditableModel().contains(system)) { //New jWaypoints.getEditableModel().add(system); } else if (jAvailable.getEditableModel().contains(system)) { //In available: moving to waypoints jAvailable.getEditableModel().remove(system); jWaypoints.getEditableModel().add(system); } //Else: Already in waypoints - do nothing updateRemaining(); } } else if (RoutingAction.EVE_UI.name().equals(e.getActionCommand())) { EsiOwner owner = JMenuUI.selectOwner(program, JMenuUI.EsiOwnerRequirement.AUTOPILOT); if (owner == null) { return; } Set locationIDs = new HashSet<>(); JMenuUI.getLockWindow(program).show(GuiShared.get().updating(), new JMenuUI.EsiUpdate(owner) { @Override protected void updateESI() throws Throwable { boolean clear = true; for (List systems : routeResult.getRoute()) { SolarSystem system = systems.get(0); List stations = routeResult.getStations().get(system.getSystemID()); if (stations != null && !stations.isEmpty()) { //Station(s) for (SolarSystem station : stations) { getApi().postUiAutopilotWaypoint(false, clear, station.getLocationID(), AbstractEsiGetter.COMPATIBILITY_DATE, null, null, null); locationIDs.add(station.getLocationID()); } } else { //System getApi().postUiAutopilotWaypoint(false, clear, system.getSystemID(), AbstractEsiGetter.COMPATIBILITY_DATE, null, null, null); locationIDs.add(system.getSystemID()); } if (clear) { clear = false; } } } @Override protected void ok() { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsRouting.get().resultUiOk(), GuiShared.get().uiWaypointTitle(), JOptionPane.PLAIN_MESSAGE); EveGatecampCheck.open(program, owner, locationIDs); } @Override protected void fail() { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsRouting.get().resultUiFail(), GuiShared.get().uiWaypointTitle(), JOptionPane.PLAIN_MESSAGE); } }); } else if (RoutingAction.ROUTE_SAVE.name().equals(e.getActionCommand())) { String name = jSaveRouteDialog.show(); if (name == null) { return; //Cancel } Settings.lock("Routing (Save Route)"); Settings.get().getRoutingSettings().getRoutes().put(name, routeResult); Settings.unlock("Routing (Save Route)"); program.saveSettings("Routing (Save Route)"); updateRoutes(); } else if (RoutingAction.ROUTE_EDIT.name().equals(e.getActionCommand())) { buildGraph(false); RouteResult result = jRouteEditDialog.show(systemCache, filteredGraph, routeResult); if (result == null) { return; } setRouteResult(result); } else if (RoutingAction.ROUTE_MANAGE.name().equals(e.getActionCommand())) { jRouteManagerDialog.updateData(); jRouteManagerDialog.setVisible(true); } else if (RoutingAction.IMPORT_ROUTE_XML.name().equals(e.getActionCommand())) { jFileChooser.setSelectedFile(null); jFileChooser.setCurrentDirectory(null); int returnValue = jFileChooser.showOpenDialog(program.getMainWindow().getFrame()); if (returnValue != JCustomFileChooser.APPROVE_OPTION) { return; } File file = jFileChooser.getSelectedFile(); if (file == null || !file.exists()) { return; } Map routes = SettingsReader.loadRoutes(file.getAbsolutePath()); if (routes == null) { routes = new HashMap<>(); } List selected = jRouteSelectionDialog.show(routes.keySet(), false); if (selected == null) { return; } List added = new ArrayList<>(); List existing = new ArrayList<>(); for (String routeName : selected) { if (Settings.get().getRoutingSettings().getRoutes().containsKey(routeName)) { existing.add(routeName); } else { added.add(routeName); } } int count = existing.size(); ImportReturn importReturn = null; jImportDialog.resetToDefault(); Settings.lock("Routing (Import Route)"); for (String routeName : added) { RouteResult result = routes.get(routeName); Settings.get().getRoutingSettings().getRoutes().put(routeName, result); } updateRoutes(); for (String routeName : existing) { RouteResult routeResult = routes.get(routeName); importReturn = importOptions(routeResult, routeName, importReturn, count); count--; } Settings.unlock("Routing (Import Route)"); program.saveSettings("Routing (Import Route)"); } else if (RoutingAction.IMPORT_ROUTE.name().equals(e.getActionCommand())) { importText(); } else if (RoutingAction.ROUTE_EXPORT.name().equals(e.getActionCommand())) { List selected = jRouteSelectionDialog.show(Settings.get().getRoutingSettings().getRoutes().keySet(), false); if (selected == null) { return; } jFileChooser.setSelectedFile(null); jFileChooser.setCurrentDirectory(null); int returnValue = jFileChooser.showSaveDialog(program.getMainWindow().getFrame()); if (returnValue != JCustomFileChooser.APPROVE_OPTION) { return; } File file = jFileChooser.getSelectedFile(); if (file == null) { return; } Map routes = new HashMap<>(); for (String routeName : selected) { RouteResult result = Settings.get().getRoutingSettings().getRoutes().get(routeName); if (result != null) { routes.put(routeName, result); } } SettingsWriter.saveRoutes(routes, file.getAbsolutePath()); } } @Override public void mouseClicked(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount()% 2 == 0 && !e.isControlDown() && !e.isShiftDown() ) { if (e.getSource().equals(jAvailable) && jAvailable.isEnabled()) { move(jAvailable, jWaypoints); } else if (e.getSource().equals(jWaypoints) && jWaypoints.isEnabled()) { move(jWaypoints, jAvailable); } } } @Override public void valueChanged(ListSelectionEvent e) { if (e.getSource().equals(jAvailable) || e.getSource().equals(jWaypoints)) { validateLists(); } } } private class ResultToolbar { private final JToolBar jToolBar; private final JLabel jName; private final JButton jEveUiSetRoute; private final JButton jEditRoute; private final JButton jExportRoute; private final JButton jSaveRoute; private final JDropDownButton jLoadRoute; private final JMenuItem jManageRoutes; private final Font plain; private final Font italic; public ResultToolbar() { jToolBar = new JToolBar(); GroupLayout layout = new GroupLayout(jToolBar); jToolBar.setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(false); jToolBar.setFloatable(false); jToolBar.setRollover(true); jName = new JLabel(); plain = jName.getFont(); italic = new Font(plain.getName(), Font.ITALIC, plain.getSize()); jEveUiSetRoute = new JButton(TabsRouting.get().resultUiWaypoints(), Images.MISC_EVE.getIcon()); jEveUiSetRoute.setActionCommand(RoutingAction.EVE_UI.name()); jEveUiSetRoute.addActionListener(listener); jEveUiSetRoute.setEnabled(false); jEditRoute = new JButton(TabsRouting.get().resultEdit(), Images.EDIT_EDIT.getIcon()); jEditRoute.setHorizontalAlignment(JButton.LEFT); jEditRoute.setActionCommand(RoutingAction.ROUTE_EDIT.name()); jEditRoute.addActionListener(listener); jEditRoute.setEnabled(false); jExportRoute = new JButton(TabsRouting.get().resultExport(), Images.DIALOG_CSV_EXPORT.getIcon()); jExportRoute.setHorizontalAlignment(JButton.LEFT); jExportRoute.setActionCommand(RoutingAction.ROUTE_EXPORT.name()); jExportRoute.addActionListener(listener); jExportRoute.setEnabled(false); JDropDownButton jImport = new JDropDownButton(TabsRouting.get().resultImport(), Images.EDIT_IMPORT.getIcon()); JMenuItem jImportXml = new JMenuItem(TabsRouting.get().resultImportXml(), Images.TOOL_ROUTING.getIcon()); jImportXml.setHorizontalAlignment(JButton.LEFT); jImportXml.setActionCommand(RoutingAction.IMPORT_ROUTE_XML.name()); jImportXml.addActionListener(listener); jImport.add(jImportXml); jImport.addSeparator(); JMenuItem jImportText = new JMenuItem(TabsRouting.get().resultImportText(), Images.STOCKPILE_SHOPPING_LIST.getIcon()); jImportText.setHorizontalAlignment(JButton.LEFT); jImportText.setActionCommand(RoutingAction.IMPORT_ROUTE.name()); jImportText.addActionListener(listener); jImport.add(jImportText); jSaveRoute = new JButton(TabsRouting.get().resultSave(), Images.FILTER_SAVE.getIcon()); jSaveRoute.setHorizontalAlignment(JButton.LEFT); jSaveRoute.setActionCommand(RoutingAction.ROUTE_SAVE.name()); jSaveRoute.addActionListener(listener); jSaveRoute.setEnabled(false); jLoadRoute = new JDropDownButton(TabsRouting.get().resultLoad(), Images.FILTER_LOAD.getIcon()); jLoadRoute.setHorizontalAlignment(JButton.LEFT); layout.setHorizontalGroup( layout.createSequentialGroup() .addContainerGap() .addComponent(jName, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addGap(0, 0, Integer.MAX_VALUE) .addComponent(jEveUiSetRoute) .addComponent(jEditRoute, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, 100) .addComponent(jExportRoute, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, 100) .addComponent(jImport, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, 100) .addComponent(jSaveRoute, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, 100) .addComponent(jLoadRoute, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, 100) .addContainerGap() ); layout.setVerticalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jName) .addComponent(jEveUiSetRoute) .addComponent(jEditRoute) .addComponent(jExportRoute) .addComponent(jImport) .addComponent(jSaveRoute) .addComponent(jLoadRoute) ); jManageRoutes = new JMenuItem(TabsRouting.get().resultManage(), Images.DIALOG_SETTINGS.getIcon()); jManageRoutes.setActionCommand(RoutingAction.ROUTE_MANAGE.name()); jManageRoutes.addActionListener(listener); } public JToolBar getComponent() { return jToolBar; } public void update() { jLoadRoute.removeAll(); jLoadRoute.setEnabled(!Settings.get().getRoutingSettings().getRoutes().isEmpty()); if (!Settings.get().getRoutingSettings().getRoutes().isEmpty()) { jLoadRoute.add(jManageRoutes); jLoadRoute.addSeparator(); } if (routeResult != null) { String name = null; for (Map.Entry entry : Settings.get().getRoutingSettings().getRoutes().entrySet()) { if (entry.getValue().equals(routeResult)) { name = entry.getKey(); break; } } if (name == null) { name = TabsRouting.get().resultUntitled(); jName.setFont(italic); jName.setEnabled(false); } else { jName.setFont(plain); jName.setEnabled(true); } jName.setText(name); } else { jName.setText(TabsRouting.get().resultEmpty()); jName.setFont(italic); jName.setEnabled(false); } for (Map.Entry entry : Settings.get().getRoutingSettings().getRoutes().entrySet()) { JMenuItem jMenuItem = new JMenuItem(entry.getKey(), Images.FILTER_LOAD.getIcon()); jMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setRouteResult(entry.getValue()); updateRoutes(); } }); jLoadRoute.add(jMenuItem); } jExportRoute.setEnabled(!Settings.get().getRoutingSettings().getRoutes().isEmpty()); } public void setEnabledResult(boolean b) { jEveUiSetRoute.setEnabled(b); jEditRoute.setEnabled(b); jSaveRoute.setEnabled(b); } public void setEnabled(boolean b) { if (b) { jLoadRoute.setEnabled(!Settings.get().getRoutingSettings().getRoutes().isEmpty()); } else { jLoadRoute.setEnabled(b); } } } /** * A GUI compatible container for the routing algorithms. */ private static class RoutingAlgorithmContainer { private RoutingAlgorithm contained; public RoutingAlgorithmContainer(final RoutingAlgorithm contained) { this.contained = contained; } public int getWaypointLimit() { return contained.getWaypointLimit(); } public String getName() { return contained.getName(); } public String getTechnicalDescription() { return contained.getTechnicalDescription(); } public String getBasicDescription() { return contained.getBasicDescription(); } public List execute(final Progress progress, final Graph g, final List assetLocations) { return contained.execute(progress, g, assetLocations); } public long getLastTimeTaken() { return contained.getLastTimeTaken(); } public int getLastDistance() { return contained.getLastDistance(); } public CancelService getCancelService() { return contained.getCancelService(); } public void resetCancelService() { contained.resetCancelService(); } @Override public String toString() { return getName(); } public static List getRegisteredList() { List list = new ArrayList<>(); list.add(new RoutingAlgorithmContainer(new BruteForce<>())); list.add(new RoutingAlgorithmContainer(new SimpleUnisexMutatorHibrid2Opt<>())); list.add(new RoutingAlgorithmContainer(new Crossover<>())); list.add(new RoutingAlgorithmContainer(new NearestNeighbour<>())); return list; } } private class RouteFind extends SwingWorker implements Progress { private int maximum = 1; private int minimum = 0; private int value = 0; private int oldProgress = 0; @Override protected Void doInBackground() throws Exception { processRouteInner(); return null; } @Override protected void done() { setUIEnabled(true); jProgress.setValue(0); jProgress.setIndeterminate(false); } @Override public int getMaximum() { return maximum; } @Override public void setMaximum(int maximum) { this.maximum = maximum; } @Override public int getMinimum() { return minimum; } @Override public void setMinimum(int minimum) { this.minimum = minimum; } @Override public int getValue() { return value; } @Override public void setValue(int value) { this.value = value; int progress = (int) Math.floor(value * 100.0 / getMaximum()); if (progress < 0) { progress = 0; } if (progress > 100) { progress = 100; } if (progress != oldProgress) { oldProgress = progress; setProgress(oldProgress); } } } static class SourceItem implements Comparable { private final String name; private final boolean group; public SourceItem(final String name) { this.name = name; this.group = false; } public SourceItem(final String name, final boolean group) { this.name = name; this.group = group; } @Override public String toString() { if (group) { return TabsRouting.get().overviewGroup(name); } else { return name; } } public String getName() { return name; } @Override public int compareTo(final SourceItem o) { return this.getName().compareToIgnoreCase(o.getName()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/routing/SolarSystem.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.routing; import java.util.Map; import net.nikr.eve.jeveasset.data.sde.MyLocation; import uk.me.candle.eve.graph.Node; /** * * @author Candle */ public class SolarSystem extends Node { private final MyLocation location; public static SolarSystem create(Map systemCache, final MyLocation location) { SolarSystem cached = systemCache.get(location.getSystemID()); if (cached == null) { cached = new SolarSystem(location); systemCache.put(location.getSystemID(), cached); } return cached; } public SolarSystem(final MyLocation location) { super(location.getLocation()); this.location = location; } public final boolean isStation() { return location.isStation(); //Not Planet } public String getSecurity() { return location.getSecurity(); } public long getRegionID() { return location.getRegionID(); } public long getLocationID() { return location.getLocationID(); } public long getSystemID() { return location.getSystemID(); } public String getSystem() { return location.getSystem(); } @Override public boolean equals(final Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final SolarSystem other = (SolarSystem) obj; if (this.location != other.location && (this.location == null || !this.location.equals(other.location))) { return false; } return true; } @Override public int hashCode() { int hash = 7; hash = 79 * hash + (this.location != null ? this.location.hashCode() : 0); return hash; } @Override public String toString() { return getName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/skills/JSkillPlansManageDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.skills; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.components.JManagerDialog; import net.nikr.eve.jeveasset.i18n.TabsSkills; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class JSkillPlansManageDialog extends JManagerDialog { private final SkillsOverviewTab skillsOverviewTab; public JSkillPlansManageDialog(Program program, SkillsOverviewTab skillsOverviewTab) { super(program, program.getMainWindow().getFrame(), TabsSkills.get().manageTitle(), false, true, true, true, false); this.skillsOverviewTab = skillsOverviewTab; } @Override protected void load(String name) { } @Override protected void edit(String name) { Map oldSkills = Settings.get().getSkillPlans().getOrDefault(name, Collections.emptyMap()); StringBuilder builder = new StringBuilder(); for (Map.Entry e : oldSkills.entrySet()) { Item item = ApiIdConverter.getItem(e.getKey()); if (!item.isEmpty()) { builder.append(item.getTypeName()).append(' ').append(e.getValue()).append('\n'); } } Map newSkills = skillsOverviewTab.importSkillPlan(builder.toString()); if (newSkills == null || newSkills.isEmpty()) { return; } Settings.lock("Skills Overview (Edit Plan)"); Settings.get().getSkillPlans().put(name, newSkills); Settings.unlock("Skills Overview (Edit Plan)"); program.saveSettings("Skills Overview (Edit Plan)"); skillsOverviewTab.updateData(); } @Override protected void merge(String name, List list) { Map output = new HashMap<>(); for (String s : list) { for (Map.Entry entry : Settings.get().getSkillPlans().getOrDefault(s, Collections.emptyMap()).entrySet()) { Integer key = entry.getKey(); Integer newValue = entry.getValue(); Integer oldValue = output.get(key); if (oldValue == null) { output.put(key, newValue); } else { output.put(key, Math.max(newValue, oldValue)); } } } Settings.lock("Skills Overview (Merge Plans)"); Settings.get().getSkillPlans().put(name, output); Settings.unlock("Skills Overview (Merge Plans)"); program.saveSettings("Skills Overview (Merge Plans)"); updateData(); skillsOverviewTab.updateData(); } @Override protected void copy(String fromName, String toName) { Map skills = Settings.get().getSkillPlans().getOrDefault(fromName, Collections.emptyMap()); Settings.lock("Skills Overview (Copy Plan)"); Settings.get().getSkillPlans().put(toName, skills); Settings.unlock("Skills Overview (Copy Plan)"); program.saveSettings("Skills Overview (Copy Plan)"); updateData(); skillsOverviewTab.updateData(); } @Override protected void rename(String name, String oldName) { Settings.lock("Skills Overview (Rename Plan)"); Map remove = Settings.get().getSkillPlans().remove(oldName); Settings.get().getSkillPlans().put(name, remove); Settings.unlock("Skills Overview (Rename Plan)"); program.saveSettings("Skills Overview (Rename Plan)"); updateData(); skillsOverviewTab.updateData(); } @Override protected void delete(List list) { Settings.lock("Skills Overview (Delete Plans)"); Settings.get().getSkillPlans().keySet().removeAll(list); Settings.unlock("Skills Overview (Delete Plans)"); program.saveSettings("Skills Overview (Delete Plans)"); updateData(); skillsOverviewTab.updateData(); } @Override protected void export(List list) { //Export is not supported } @Override protected void importData() { //Import is not supported } @Override public void setVisible(boolean b) { if (b) { updateData(); } super.setVisible(b); } private void updateData() { update(Settings.get().getSkillPlans().keySet()); } @Override protected String textDeleteMultipleMsg(int size) { return TabsSkills.get().deleteSkillPlans(size); } @Override protected String textDelete() { return TabsSkills.get().deleteSkillPlan(); } @Override protected String textEnterName() { return TabsSkills.get().enterName(); } @Override protected String textMerge() { return TabsSkills.get().merge(); } @Override protected String textRename() { return TabsSkills.get().rename(); } @Override protected String textOverwrite() { return TabsSkills.get().overwrite(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/skills/SkillsOverviewTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.skills; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.awt.Canvas; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.swing.GroupLayout; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.UIDefaults; import javax.swing.UIManager; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MySkill; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.components.JAutoCompleteDialog; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.i18n.TabsSkills; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class SkillsOverviewTab extends JMainTabSecondary { private enum SkillsOverviewAction { ADD_SKILL_PLAN, MANAGE_SKILL_PLANS, } private static final double[] RANK_1_LEVELS = new double[]{250, 1415, 8000, 45255, 256000}; private static final String SKILL_PLAN_EXAMPLE = "Power Grid Management 1\n" + "Science 1\n" + "Gunnery 1\n" + "Navigation 1\n" + "Spaceship Command 1\n" + "CPU Management 1\n" + "Drones 1\n" + "Small Hybrid Turret 1\n" + "Afterburner 1\n" + "Drone Avionics 1\n" + "Gallente Frigate 1\n" + "Power Grid Management 2\n" + "CPU Management 2\n" + "Drones 2\n" + "Gunnery 2\n" + "Drone Avionics 2\n" + "Weapon Upgrades 1\n" + "Shield Upgrades 1\n" + "Gallente Frigate 2\n" + "Electronics Upgrades 1\n" + "Shield Upgrades 2\n" + "Power Grid Management 3\n" + "Drones 3\n" + "Drone Avionics 3\n" + "Tactical Shield Manipulation 1\n" + "Gallente Frigate 3\n"; private final JFixedToolBar jToolBar; private final JAutoColumnTable jTable; //Dialog private final JSkillPlansManageDialog jSkillPlansManageDialog; private final JTextDialog jTextDialog; private final JAutoCompleteDialog jSaveDialog; private final SkillsOverviewFilterControl filterControl; private final DefaultEventTableModel tableModel; private final EventList eventList; private final FilterList filterList; private final EnumTableFormatAdaptor tableFormat; private final List> dynamicColumns = new ArrayList<>(); private final DefaultEventSelectionModel selectionModel; public static final String NAME = "skillsoverview"; public SkillsOverviewTab(Program program) { super(program, NAME, TabsSkills.get().skillsOverview(), Images.TOOL_SKILLS.getIcon(), true); jSkillPlansManageDialog = new JSkillPlansManageDialog(program, this); jTextDialog = new JTextDialog(program.getMainWindow().getFrame()); jSaveDialog = new JAutoCompleteDialog<>(program, TabsSkills.get().add(), Images.TOOL_SKILLS.getImage(), TabsSkills.get().enterName(), false, true, JAutoCompleteDialog.STRING_OPTIONS); final ListenerClass listener = new ListenerClass(); jToolBar = new JFixedToolBar(); JDropDownButton jSkills = new JDropDownButton(TabsSkills.get().skillPlans(), Images.TOOL_SKILLS.getIcon()); jToolBar.addButton(jSkills); JMenuItem jManage = new JMenuItem(TabsSkills.get().manage(), Images.DIALOG_SETTINGS.getIcon()); jManage.setActionCommand(SkillsOverviewAction.MANAGE_SKILL_PLANS.name()); jManage.addActionListener(listener); jSkills.add(jManage); jSkills.addSeparator(); JMenuItem jAdd = new JMenuItem(TabsSkills.get().add(), Images.EDIT_ADD.getIcon()); jAdd.setActionCommand(SkillsOverviewAction.ADD_SKILL_PLAN.name()); jAdd.addActionListener(listener); jSkills.add(jAdd); //Table Format tableFormat = TableFormatFactory.skillsOverviewTableFormat(); //Backend eventList = EventListManager.create(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedColumns = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Sorting (total) eventList.getReadWriteLock().readLock().lock(); SortedList sorted = new SortedList<>(sortedColumns, new TotalComparator()); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sorted); eventList.getReadWriteLock().readLock().unlock(); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table UIDefaults uiDefaults = UIManager.getLookAndFeelDefaults(); Font font = uiDefaults.getFont("ToolTip.font"); if (font == null) { font = new JTable().getFont(); //Better safe, than sorry... } FontMetrics fontMetrics = new Canvas().getFontMetrics(font); double maxHeight = Toolkit.getDefaultToolkit().getScreenSize().getHeight(); int lineHeight = fontMetrics.getHeight(); jTable = new JAutoColumnTable(program, tableModel) { @Override public String getToolTipText(java.awt.event.MouseEvent e) { int row = rowAtPoint(e.getPoint()); int column = columnAtPoint(e.getPoint()); if (row < 0 || column < 0) { return null; } int modelColumn = convertColumnIndexToModel(column); String columnName = tableModel.getColumnName(modelColumn); Map> plans = Settings.get().getSkillPlans(); if (!plans.containsKey(columnName)) { return null; } try { SkillsOverview skillsOverview = filterList.get(row); Map have = skillsOverview.getOwnerSkillPoints(); Map plan = plans.get(columnName); StringBuilder builder = new StringBuilder(); int missing = 0; for (Map.Entry required : plan.entrySet()) { int typeID = required.getKey(); int targetLevel = Math.max(1, Math.min(5, required.getValue())); double targetSkillPoints = skillPointsForLevel(typeID, targetLevel); long currentSkillPoints = have.getOrDefault(typeID, 0L); if (currentSkillPoints < targetSkillPoints) { missing++; String name; name = ApiIdConverter.getItem(typeID).getTypeName(); int approximateLevel = approximateLevelFromSkillPoints(currentSkillPoints); String percent = Formatter.percentFormat(Math.min(1.0, currentSkillPoints / Math.max(1.0, targetSkillPoints))); builder.append(TabsSkills.get().tableToolTipSkill(name, approximateLevel, targetLevel, percent)); if (lineHeight * (missing + 3) > maxHeight) { builder.append(TabsSkills.get().tableToolTipTruncated()); break; } } } if (missing == 0) { return TabsSkills.get().tableToolTipCompleted(); } return TabsSkills.get().tableToolTipMissing(missing) + builder.toString().trim(); } catch (Throwable t) { return null; } } }; jTable.setToolTipText(""); jTable.setCellSelectionEnabled(true); jTable.setRowSelectionAllowed(true); jTable.setColumnSelectionAllowed(true); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedColumns, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jScrollPane = new JScrollPane(jTable); //Table Filter filterControl = new SkillsOverviewFilterControl(sorted); //Menu installTableTool(new SkillsOverviewTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, eventList, SkillsOverview.class); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, jToolBar.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jScrollPane, 0, 0, Short.MAX_VALUE)); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jScrollPane, 0, 0, Short.MAX_VALUE)); } @Override public void updateData() { List skillsOverviews = new ArrayList<>(); for (EnumTableColumn column : new ArrayList<>(dynamicColumns)) { tableFormat.removeColumn(column); } dynamicColumns.clear(); for (String planName : Settings.get().getSkillPlans().keySet()) { PlanColumn column = new PlanColumn(planName); tableFormat.addColumn(column); dynamicColumns.add(column); } tableModel.fireTableStructureChanged(); filterControl.updateColumns(true); Map> plans = Settings.get().getSkillPlans(); Map> ownerSkillPoints = new LinkedHashMap<>(); try { program.getProfileData().getSkillsEventList().getReadWriteLock().readLock().lock(); for (MySkill skill : program.getProfileData().getSkillsEventList()) { Map map = ownerSkillPoints.computeIfAbsent(skill.getOwnerName(), k -> new LinkedHashMap<>()); map.put(skill.getTypeID(), skill.getSkillpoints()); } } finally { program.getProfileData().getSkillsEventList().getReadWriteLock().readLock().unlock(); } for (Map.Entry> entry : ownerSkillPoints.entrySet()) { SkillsOverview skillsOverview = new SkillsOverview(entry.getKey()); skillsOverview.setOwnerSkillPoints(entry.getValue()); // Populate Total SP and Unallocated SP for this character OwnerType ownerType = null; for (OwnerType owner : program.getOwnerTypes()) { if (owner.getOwnerName().equals(entry.getKey())) { ownerType = owner; break; } } if (ownerType != null) { skillsOverview.setTotalSkillPoints(ownerType.getTotalSkillPoints()); skillsOverview.setUnallocatedSkillPoints(ownerType.getUnallocatedSkillPoints()); } for (Map.Entry> plan : plans.entrySet()) { double planPercent = computePlanPercent(entry.getValue(), plan.getValue()); skillsOverview.planToPercent.put(plan.getKey(), Percent.create(planPercent)); } skillsOverviews.add(skillsOverview); } SkillsOverview total = new SkillsOverview(TabsSkills.get().total()); for (String plan : plans.keySet()) { double sum = 0; int count = 0; for (SkillsOverview skillsOverview : skillsOverviews) { Percent p = skillsOverview.planToPercent.get(plan); if (p != null) { sum += p.getDouble(); count++; } } total.planToPercent.put(plan, Percent.create(count == 0 ? 0 : (sum / 100.0 / count))); } skillsOverviews.add(total); try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(skillsOverviews); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } private static class TotalComparator implements Comparator { @Override public int compare(SkillsOverview a, SkillsOverview b) { if (a.isTotal() && b.isTotal()) { return 0; } else if (a.isTotal()) { return 1; } else if (b.isTotal()) { return -1; } else { return 0; } } } private double computePlanPercent(Map ownerSkillSp, Map plan) { double have = 0; double need = 0; for (Map.Entry required : plan.entrySet()) { int typeID = required.getKey(); int level = Math.max(1, Math.min(5, required.getValue())); double targetSkillPoints = skillPointsForLevel(typeID, level); long currentSkillPoints = ownerSkillSp.getOrDefault(typeID, 0L); have += Math.min(currentSkillPoints, targetSkillPoints); need += targetSkillPoints; } if (need <= 0) { return 0; } return have / need; } private static int approximateLevelFromSkillPoints(long currentSkillPoints) { for (int i = 5; i >= 1; i--) { if (currentSkillPoints >= RANK_1_LEVELS[i - 1]) { return i; } } return 0; } private double skillPointsForLevel(int typeID, int level) { double rank = 1.0; ApiIdConverter.getItem(typeID); return RANK_1_LEVELS[level - 1] * rank; } public Map importSkillPlan(String text) { String importText = jTextDialog.importText(text, SKILL_PLAN_EXAMPLE); if (importText == null) { return null; } //Lookup Table Map names = new HashMap<>(); for (Item item : StaticData.get().getItems().values()) { names.put(item.getTypeName().toLowerCase(), item.getTypeID()); } String[] lines = importText.split("[\r\n]+"); Map skills = new LinkedHashMap<>(); for (String line : lines) { String trimmed = line.trim(); if (trimmed.isEmpty()) { continue; } int space = lastSpaceIndex(trimmed); if (space <= 0 || space == trimmed.length() - 1) { continue; } String skillName = trimmed.substring(0, space).trim(); String levelStr = trimmed.substring(space + 1).trim(); int level = 0; try { level = Integer.parseInt(levelStr); } catch (NumberFormatException ex) { switch (levelStr.toLowerCase()) { case "i": level = 1; break; case "ii": level = 2; break; case "iii": level = 3; break; case "iv": level = 4; break; case "v": level = 5; break; } } if (level == 0) { continue; } level = Math.max(1, Math.min(5, level)); Integer typeID = names.get(skillName.toLowerCase()); if (typeID == null || typeID == 0) { continue; } skills.put(typeID, level); } if (skills.isEmpty()) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsSkills.get().noValidSkills (), TabsSkills.get().add(), JOptionPane.WARNING_MESSAGE); return importSkillPlan(text); } return skills; } public void newSkillPlan(Map skills) { if (skills == null || skills.isEmpty()) { return; } jSaveDialog.updateData(Settings.get().getSkillPlans().keySet()); String name = jSaveDialog.show(); if (name == null) { return; //Cancel } Settings.lock("Skills Overview (New Plan)"); Settings.get().getSkillPlans().put(name, skills); Settings.unlock("Skills Overview (New Plan)"); program.saveSettings("Skills Overview (New Plan)"); updateData(); } private static int lastSpaceIndex(String s) { for (int i = s.length() - 1; i >= 0; i--) { if (Character.isWhitespace(s.charAt(i))) return i; } return -1; } @Override public void clearData() { try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); } finally { eventList.getReadWriteLock().writeLock().unlock(); } filterControl.clearCache(); } @Override public void updateCache() { filterControl.createCache(); } @Override public Collection getLocations() { return new ArrayList<>(); } public class SkillsOverview implements Comparable { private final String owner; private final Map planToPercent = new LinkedHashMap<>(); private Long totalSkillsPoints; private Integer unallocatedSkillsPoints; private Map ownerSkillPoints; public SkillsOverview(String owner) { this.owner = owner; } public String getOwner() { return owner; } public Percent getPercent(String plan) { return planToPercent.getOrDefault(plan, Percent.create(0)); } public void setOwnerSkillPoints(Map ownerSkillPoints) { this.ownerSkillPoints = ownerSkillPoints; } public Map getOwnerSkillPoints() { return ownerSkillPoints != null ? ownerSkillPoints : new LinkedHashMap<>(); } public void setTotalSkillPoints(Long totalSkillsPoints) { this.totalSkillsPoints = totalSkillsPoints; } public Long getTotalSkillPoints() { return totalSkillsPoints; } public void setUnallocatedSkillPoints(Integer unallocatedSkillsPoints) { this.unallocatedSkillsPoints = unallocatedSkillsPoints; } public Integer getUnallocatedSkillPoints() { return unallocatedSkillsPoints; } public boolean isTotal() { return owner.equals(TabsSkills.get().total()); } @Override public int compareTo(SkillsOverview o) { return 0; } } private static class PlanColumn implements EnumTableColumn { private final String plan; PlanColumn(String plan) { this.plan = plan; } @Override public Class getType() { return Percent.class; } @Override public Comparator getComparator() { return EnumTableColumn.getComparator(Percent.class); } @Override public String getColumnName() { return plan; } @Override public Object getColumnValue(SkillsOverview from) { return from.getPercent(plan); } @Override public String toString() { return getColumnName(); } @Override public String name() { return plan; } @Override public boolean isShowDefault() { return true; } } private class SkillsOverviewTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { } @Override public void addToolMenu(JComponent jComponent) { } } private class SkillsOverviewFilterControl extends FilterControl { public SkillsOverviewFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList); } @Override public void saveSettings(final String msg) { program.saveSettings("Skills Overview Table: " + msg); } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (SkillsOverviewAction.ADD_SKILL_PLAN.name().equals(e.getActionCommand())) { Map skills = importSkillPlan(""); newSkillPlan(skills); } else if (SkillsOverviewAction.MANAGE_SKILL_PLANS.name().equals(e.getActionCommand())) { jSkillPlansManageDialog.setVisible(true); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/skills/SkillsOverviewTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.skills; import java.util.Comparator; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.tabs.skills.SkillsOverviewTab.SkillsOverview; import net.nikr.eve.jeveasset.i18n.TabsSkills; public enum SkillsOverviewTableFormat implements EnumTableColumn { OWNER(String.class) { @Override public String getColumnName() { return TabsSkills.get().columnCharacter(); } @Override public Object getColumnValue(SkillsOverview from) { return from.getOwner(); } }, TOTAL_SP(Long.class) { @Override public String getColumnName() { return TabsSkills.get().columnTotal(); } @Override public Object getColumnValue(SkillsOverview from) { return from.getTotalSkillPoints(); } }, UNALLOCATED_SP(Long.class) { @Override public String getColumnName() { return TabsSkills.get().columnUnallocated(); } @Override public Object getColumnValue(SkillsOverview from) { return from.getUnallocatedSkillPoints(); } }; private final Class type; private final Comparator comparator; private SkillsOverviewTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/skills/SkillsTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.skills; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.util.ArrayList; import java.util.Collection; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MySkill; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabPrimary; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.TabsSkills; public class SkillsTab extends JMainTabPrimary { //GUI private final JAutoColumnTable jTable; //Table private final SkillsFilterControl filterControl; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventTableModel tableModel; private final EventList eventList; private final FilterList filterList; private final DefaultEventSelectionModel selectionModel; public static final String NAME = "skills"; //Not to be changed! public SkillsTab(Program program) { super(program, NAME, TabsSkills.get().skills(), Images.TOOL_SKILLS.getIcon(), true); //Table Format tableFormat = TableFormatFactory.skillsTableFormat(); //Backend eventList = program.getProfileData().getSkillsEventList(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedList); eventList.getReadWriteLock().readLock().unlock(); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JAutoColumnTable(program, tableModel); jTable.setCellSelectionEnabled(true); jTable.setRowSelectionAllowed(true); jTable.setColumnSelectionAllowed(true); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new SkillsFilterControl(sortedList); //Menu installTableTool(new SkillsTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, MySkill.class); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void updateCache() { } @Override public void clearData() { } @Override public Collection getLocations() { return new ArrayList<>(); //No Location } private class SkillsTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { } @Override public void addToolMenu(JComponent jComponent) { } } private class SkillsFilterControl extends FilterControl { public SkillsFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("Skills Table: " + msg); //Save Asset Filters and Export Settings } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/skills/SkillsTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.skills; import java.util.Comparator; import net.nikr.eve.jeveasset.data.api.my.MySkill; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.TabsSkills; public enum SkillsTableFormat implements EnumTableColumn { NAME(String.class) { @Override public String getColumnName() { return TabsSkills.get().columnSkill(); } @Override public Object getColumnValue(final MySkill from) { return from.getName(); } }, GROUP(String.class) { @Override public String getColumnName() { return TabsSkills.get().columnGroup(); } @Override public Object getColumnValue(final MySkill from) { return from.getItem().getGroup(); } }, OWNER(String.class) { @Override public String getColumnName() { return TabsSkills.get().columnCharacter(); } @Override public Object getColumnValue(final MySkill from) { return from.getOwnerName(); } }, ACTIVE(Integer.class) { @Override public String getColumnName() { return TabsSkills.get().columnActive(); } @Override public Object getColumnValue(final MySkill from) { return from.getActiveSkillLevel(); } }, TRAINED(Integer.class) { @Override public String getColumnName() { return TabsSkills.get().columnTrained(); } @Override public Object getColumnValue(final MySkill from) { return from.getTrainedSkillLevel(); } }; private final Class type; private final Comparator comparator; private SkillsTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/slots/JSlotsTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.slots; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; public class JSlotsTable extends JAutoColumnTable { private final DefaultEventTableModel tableModel; public JSlotsTable(final Program program, final DefaultEventTableModel tableModel) { super(program, tableModel); this.tableModel = tableModel; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); boolean isSelected = isCellSelected(row, column); Slots slots = tableModel.getElementAt(row); String columnName = (String) this.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); //Grand Total if (slots.isGrandTotal()) { ColorSettings.configCell(component, ColorEntry.GLOBAL_GRAND_TOTAL, isSelected); return component; } if (slots.isEmpty() && columnName.equals(SlotsTableFormat.NAME.getColumnName())) { ColorSettings.configCell(component, ColorEntry.GLOBAL_ENTRY_INVALID, isSelected); return component; } if (slots.isManufacturingFree() && columnName.equals(SlotsTableFormat.MANUFACTURING_FREE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_FREE, isSelected); return component; } if (slots.isManufacturingDone() && columnName.equals(SlotsTableFormat.MANUFACTURING_DONE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_DONE, isSelected); return component; } if (slots.isManufacturingFull() && columnName.equals(SlotsTableFormat.MANUFACTURING_FREE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_FULL, isSelected); return component; } if (slots.isReactionsFree() && columnName.equals(SlotsTableFormat.REACTIONS_FREE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_FREE, isSelected); return component; } if (slots.isReactionsDone() && columnName.equals(SlotsTableFormat.REACTIONS_DONE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_DONE, isSelected); return component; } if (slots.isReactionsFull() && columnName.equals(SlotsTableFormat.REACTIONS_FREE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_FULL, isSelected); return component; } if (slots.isResearchFree() && columnName.equals(SlotsTableFormat.RESEARCH_FREE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_FREE, isSelected); return component; } if (slots.isResearchDone() && columnName.equals(SlotsTableFormat.RESEARCH_DONE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_DONE, isSelected); return component; } if (slots.isResearchFull() && columnName.equals(SlotsTableFormat.RESEARCH_FREE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_FULL, isSelected); return component; } if (slots.isMarketOrdersFree() && columnName.equals(SlotsTableFormat.MARKET_ORDERS_FREE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_FREE, isSelected); return component; } if (slots.isMarketOrdersFull() && columnName.equals(SlotsTableFormat.MARKET_ORDERS_FREE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_FULL, isSelected); return component; } if (slots.isContractCharacterFree() && columnName.equals(SlotsTableFormat.CONTRACT_CHARACTER_FREE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_FREE, isSelected); return component; } if (slots.isContractCharacterFull() && columnName.equals(SlotsTableFormat.CONTRACT_CHARACTER_FREE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_FULL, isSelected); return component; } if (slots.isContractCorporationFree() && columnName.equals(SlotsTableFormat.CONTRACT_CORPORATION_FREE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_FREE, isSelected); return component; } if (slots.isContractCorporationFull() && columnName.equals(SlotsTableFormat.CONTRACT_CORPORATION_FREE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.INDUSTRY_SLOTS_FULL, isSelected); return component; } return component; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/slots/Slots.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.slots; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyShip; import net.nikr.eve.jeveasset.data.api.my.MySkill; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob.IndustryJobStatus; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.types.LocationType; public class Slots implements Comparable, LocationType { private final String name; private final boolean total; private final boolean empty; private int manufacturingActive = 0; private int reactionsActive = 0; private int researchActive = 0; private int marketOrdersActive = 0; private int contractCharacterActive = 0; private int contractCorporationActive = 0; private int manufacturingDone = 0; private int reactionsDone = 0; private int researchDone = 0; private int manufacturingMax = 0; private int reactionsMax = 0; private int researchMax = 0; private int marketOrdersMax = 0; private int contractCharacterMax = 0; private int contractCorporationMax = 0; private MyShip activeShip = null; public Slots(OwnerType ownerType) { this.name = ownerType.getOwnerName(); this.total = false; this.empty = ownerType.getSkills().isEmpty(); if(ownerType.isCharacter() && ownerType.getActiveShip() != null && ownerType.getActiveShip().getLocation() != null) { this.activeShip = ownerType.getActiveShip(); } count(ownerType); } public Slots(String name) { this.name = name; this.total = true; this.empty = false; } public final void count(Slots slots) { manufacturingActive += slots.manufacturingActive; reactionsActive += slots.reactionsActive; researchActive += slots.researchActive; manufacturingDone += slots.manufacturingDone; reactionsDone += slots.reactionsDone; researchDone += slots.researchDone; manufacturingMax += slots.manufacturingMax; reactionsMax += slots.reactionsMax; researchMax += slots.researchMax; marketOrdersActive += slots.marketOrdersActive; marketOrdersMax += slots.marketOrdersMax; contractCharacterActive += slots.contractCharacterActive; contractCharacterMax += slots.contractCharacterMax; contractCorporationActive += slots.contractCorporationActive; contractCorporationMax += slots.contractCorporationMax; } public final void count(MyIndustryJob industryJob) { if (industryJob.isDone()) { return; //Doesn't count as active } switch (industryJob.getActivity()) { case ACTIVITY_MANUFACTURING: if (industryJob.getStatus() == IndustryJobStatus.READY) { manufacturingDone++; } manufacturingActive++; break; case ACTIVITY_REACTIONS: if (industryJob.getStatus() == IndustryJobStatus.READY) { reactionsDone++; } reactionsActive++; break; case ACTIVITY_RESEARCHING_METERIAL_PRODUCTIVITY: case ACTIVITY_RESEARCHING_TECHNOLOGY: case ACTIVITY_RESEARCHING_TIME_PRODUCTIVITY: case ACTIVITY_REVERSE_ENGINEERING: case ACTIVITY_REVERSE_INVENTION: case ACTIVITY_DUPLICATING: case ACTIVITY_COPYING: if (industryJob.getStatus() == IndustryJobStatus.READY) { researchDone++; } researchActive++; break; } } public final void count(MyContract contract) { //Only count open contracts if (!contract.isOpen()) { return; } //Internal corporation contracts does not count as a used slot (no matter who issued them, corp or char) if (!contract.getIssuerCorp().isEmpty() && contract.getIssuerCorp().equals(contract.getAssignee())) { return; } if (contract.isForCorp()) { //Corporation contractCorporationActive++; } else { //Character contractCharacterActive++; } } public final void count(MyMarketOrder marketOrder) { if (marketOrder.isActive()) { marketOrdersActive++; } } public final void count(OwnerType ownerType) { //Default manufacturingMax = manufacturingMax + 1; reactionsMax = reactionsMax + 1; researchMax = researchMax + 1; marketOrdersMax = marketOrdersMax + 5; contractCharacterMax = contractCharacterMax + 1; contractCorporationMax = contractCorporationMax + 10; //From Skills for (MySkill skill : ownerType.getSkills()) { switch (skill.getTypeID()) { case 3387: //Mass Production (+1) case 24625: //Advanced Mass Production (+1) manufacturingMax = manufacturingMax + skill.getActiveSkillLevel(); break; case 45748: //Mass Reactions (+1) case 45749: //Advanced Mass Reactions (+1) reactionsMax = reactionsMax + skill.getActiveSkillLevel(); break; case 3406: //Laboratory Operation (+1) case 24624: //Advanced Laboratory Operation (+1) researchMax = researchMax + skill.getActiveSkillLevel(); break; case 3443: //Trade (+4) marketOrdersMax = marketOrdersMax + (skill.getActiveSkillLevel() * 4); break; case 3444: //Retail (+8) marketOrdersMax = marketOrdersMax + (skill.getActiveSkillLevel() * 8); break; case 16596: //Wholesale (+16) marketOrdersMax = marketOrdersMax + (skill.getActiveSkillLevel() * 16); break; case 18580: //Tycoon (+32) marketOrdersMax = marketOrdersMax + (skill.getActiveSkillLevel() * 32); break; case 25235: //Contracting (+4) case 73912: //Advanced Contracting (+4) contractCharacterMax = contractCharacterMax + (skill.getActiveSkillLevel() * 4); break; case 25233: //Corporation Contracting (+10) contractCorporationMax = contractCorporationMax + (skill.getActiveSkillLevel() * 10); break; } } } public String getName() { return name; } public int getManufacturingFree() { return manufacturingMax - manufacturingActive; } public int getResearchFree() { return researchMax - researchActive; } public int getReactionsFree() { return reactionsMax - reactionsActive; } public int getMarketOrdersFree() { return marketOrdersMax - marketOrdersActive; } public int getContractCharacterFree() { return contractCharacterMax - contractCharacterActive; } public int getContractCorporationFree() { return contractCorporationMax - contractCorporationActive; } public int getManufacturingActive() { return manufacturingActive; } public int getReactionsActive() { return reactionsActive; } public int getResearchActive() { return researchActive; } public int getMarketOrdersActive() { return marketOrdersActive; } public int getContractCharacterActive() { return contractCharacterActive; } public int getContractCorporationActive() { return contractCorporationActive; } public int getManufacturingDone() { return manufacturingDone; } public int getReactionsDone() { return reactionsDone; } public int getResearchDone() { return researchDone; } public int getManufacturingMax() { return manufacturingMax; } public int getReactionsMax() { return reactionsMax; } public int getResearchMax() { return researchMax; } public int getMarketOrdersMax() { return marketOrdersMax; } public int getContractCharacterMax() { return contractCharacterMax; } public int getContractCorporationMax() { return contractCorporationMax; } public String getActiveShip() { if (activeShip != null) { return activeShip.getName(); } return null; } public String getCurrentStation() { if (activeShip != null) { return activeShip.getLocation().getStation(); } return null; } public String getCurrentSystem() { if (activeShip != null) { return activeShip.getLocation().getSystem(); } return null; } public String getCurrentConstellation() { if (activeShip != null) { return activeShip.getLocation().getConstellation(); } return null; } public String getCurrentRegion() { if (activeShip != null) { return activeShip.getLocation().getRegion(); } return null; } public boolean isGrandTotal() { return total; } public boolean isEmpty() { return empty; } public boolean isManufacturingFree() { return manufacturingActive < manufacturingMax; } public boolean isResearchFree() { return researchActive < researchMax; } public boolean isReactionsFree() { return reactionsActive < reactionsMax; } public boolean isMarketOrdersFree() { return marketOrdersActive < marketOrdersMax; } public boolean isContractCharacterFree() { return contractCharacterActive < contractCharacterMax; } public boolean isContractCorporationFree() { return contractCorporationActive < contractCorporationMax; } public boolean isManufacturingDone() { return manufacturingDone > 0; } public boolean isResearchDone() { return researchDone > 0; } public boolean isReactionsDone() { return reactionsDone > 0; } public boolean isManufacturingFull() { return !isManufacturingFree(); } public boolean isResearchFull() { return !isResearchFree(); } public boolean isReactionsFull() { return !isReactionsFree(); } public boolean isMarketOrdersFull() { return !isMarketOrdersFree(); } public boolean isContractCharacterFull() { return !isContractCharacterFree(); } public boolean isContractCorporationFull() { return !isContractCorporationFree(); } @Override public MyLocation getLocation() { if(activeShip != null) { return activeShip.getLocation(); } return null; } //Comparable Impl @Override public int compareTo(Slots o) { return this.getName().compareTo(o.getName()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/slots/SlotsData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.slots; import ca.odell.glazedlists.EventList; import java.util.HashMap; import java.util.Map; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.profile.TableData; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.i18n.TabsSlots; public class SlotsData extends TableData { public SlotsData(Program program) { super(program); } public SlotsData(ProfileManager profileManager, ProfileData profileData) { super(profileManager, profileData); } public EventList getData() { EventList eventList = EventListManager.create(); updateData(eventList); return eventList; } public void updateData(EventList eventList) { Map slotsByOwnerID = new HashMap<>(); Slots total = new Slots(TabsSlots.get().grandTotal()); for (OwnerType ownerType : profileManager.getOwnerTypes()) { if (ownerType.isCorporation()) { continue; } Slots old = slotsByOwnerID.put(ownerType.getOwnerID(), new Slots(ownerType)); if (old == null) { total.count(ownerType); } } for (MyIndustryJob industryJob : profileData.getIndustryJobsList()) { Slots slots = slotsByOwnerID.get(industryJob.getInstallerID()); if (slots == null) { slots = slotsByOwnerID.get(industryJob.getOwnerID()); } if (slots == null) { continue; } slots.count(industryJob); total.count(industryJob); } for (MyContract contract : profileData.getContractList()) { Slots slots = slotsByOwnerID.get(contract.getIssuerID()); if (slots == null) { continue; } slots.count(contract); total.count(contract); } for (MyMarketOrder marketOrder : profileData.getMarketOrdersList()) { Slots slots; if (marketOrder.getIssuedBy() != null) { slots = slotsByOwnerID.get((long) marketOrder.getIssuedBy()); } else { slots = slotsByOwnerID.get(marketOrder.getOwnerID()); } if (slots == null) { continue; } slots.count(marketOrder); total.count(marketOrder); } slotsByOwnerID.put(0L, total); try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(slotsByOwnerID.values()); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/slots/SlotsTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.slots; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.SortableRenderer; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.awt.Component; import java.awt.Graphics2D; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.Objects; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JToggleButton; import javax.swing.SwingConstants; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.JStatusLabel; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.AutoNumberFormat; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.PaddingTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.TabsSlots; public class SlotsTab extends JMainTabSecondary { //GUI private final JAutoColumnTable jTable; private final JToggleButton jIcons; private final JToggleButton jText; private final JLabel jManufacturing; private final JStatusLabel jManufacturingDone; private final JStatusLabel jManufacturingFree; private final JStatusLabel jManufacturingActive; private final JStatusLabel jManufacturingMax; private final JLabel jResearch; private final JStatusLabel jResearchDone; private final JStatusLabel jResearchFree; private final JStatusLabel jResearchActive; private final JStatusLabel jResearchMax; private final JLabel jReactions; private final JStatusLabel jReactionsDone; private final JStatusLabel jReactionsFree; private final JStatusLabel jReactionsActive; private final JStatusLabel jReactionsMax; private final JLabel jMarketOrders; private final JStatusLabel jMarketOrdersFree; private final JStatusLabel jMarketOrdersActive; private final JStatusLabel jMarketOrdersMax; private final JLabel jContractCharacter; private final JStatusLabel jContractCharacterFree; private final JStatusLabel jContractCharacterActive; private final JStatusLabel jContractCharacterMax; private final JLabel jContractCorporation; private final JStatusLabel jContractCorporationFree; private final JStatusLabel jContractCorporationActive; private final JStatusLabel jContractCorporationMax; //Table private final SlotsFilterControl filterControl; private final DefaultEventTableModel tableModel; private final EventList eventList; private final FilterList filterList; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventSelectionModel selectionModel; private final IconHeaderRender iconHeaderRender; public static final String NAME = "industryslots"; //Not to be changed! private final SlotsData slotsData; public SlotsTab(final Program program) { super(program, NAME, TabsSlots.get().title(), Images.TOOL_SLOTS.getIcon(), true); ListenerClass listener = new ListenerClass(); slotsData = new SlotsData(program); //Table Format tableFormat = TableFormatFactory.slotTableFormat(); //Backend eventList = EventListManager.create(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList columnSortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Sorting Total eventList.getReadWriteLock().readLock().lock(); SortedList totalSortedList = new SortedList<>(columnSortedList, new TotalComparator()); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(totalSortedList); eventList.getReadWriteLock().readLock().unlock(); filterList.addListEventListener(listener); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JSlotsTable(program, tableModel); jTable.setCellSelectionEnabled(true); jTable.setRowSelectionAllowed(true); jTable.setColumnSelectionAllowed(true); iconHeaderRender = new IconHeaderRender(jTable); jTable.getTableHeader().setDefaultRenderer(iconHeaderRender); PaddingTableCellRenderer.install(jTable, 3); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, columnSortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new SlotsFilterControl(totalSortedList); //Menu installTableTool(new SlotsTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, Slots.class); JFixedToolBar jToolBar = new JFixedToolBar(); JLabel jTableHeaderLabel = new JLabel(TabsSlots.get().tableHeader()); jToolBar.add(jTableHeaderLabel); jToolBar.addSpace(10); ButtonGroup buttonGroup = new ButtonGroup(); jText = new JToggleButton(Images.SETTINGS_COLOR_FOREGROUND.getIcon()); jText.setToolTipText(TabsSlots.get().tableHeaderText()); jText.setSelected(true); jText.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { iconHeaderRender.setShowIcon(false); jTable.autoResizeColumns(); } }); jToolBar.addButtonIcon(jText); buttonGroup.add(jText); jIcons = new JToggleButton(Images.MISC_MANUFACTURING.getIcon()); jIcons.setToolTipText(TabsSlots.get().tableHeaderIcon()); jIcons.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { iconHeaderRender.setShowIcon(true); jTable.autoResizeColumns(); } }); jToolBar.addButtonIcon(jIcons); buttonGroup.add(jIcons); jManufacturing = StatusPanel.createIcon(Images.MISC_MANUFACTURING.getIcon(), TabsSlots.get().manufacturing()); this.addStatusbarLabel(jManufacturing); jManufacturingDone = StatusPanel.createLabel(TabsSlots.get().columnManufacturingDone(), Images.EDIT_SET.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jManufacturingDone); jManufacturingFree = StatusPanel.createLabel(TabsSlots.get().columnManufacturingFree(), Images.EDIT_ADD.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jManufacturingFree); jManufacturingActive = StatusPanel.createLabel(TabsSlots.get().columnManufacturingActive(), Images.UPDATE_WORKING.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jManufacturingActive); jManufacturingMax = StatusPanel.createLabel(TabsSlots.get().columnManufacturingMax(), Images.UPDATE_DONE_OK.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jManufacturingMax); jResearch = StatusPanel.createIcon(Images.MISC_INVENTION.getIcon(), TabsSlots.get().research()); this.addStatusbarLabel(jResearch); jResearchDone = StatusPanel.createLabel(TabsSlots.get().columnResearchDone(), Images.EDIT_SET.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jResearchDone); jResearchFree = StatusPanel.createLabel(TabsSlots.get().columnResearchFree(), Images.EDIT_ADD.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jResearchFree); jResearchActive = StatusPanel.createLabel(TabsSlots.get().columnResearchActive(), Images.UPDATE_WORKING.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jResearchActive); jResearchMax = StatusPanel.createLabel(TabsSlots.get().columnResearchMax(), Images.UPDATE_DONE_OK.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jResearchMax); jReactions = StatusPanel.createIcon(Images.MISC_REACTION.getIcon(), TabsSlots.get().reactions()); this.addStatusbarLabel(jReactions); jReactionsDone = StatusPanel.createLabel(TabsSlots.get().columnReactionsDone(), Images.EDIT_SET.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jReactionsDone); jReactionsFree = StatusPanel.createLabel(TabsSlots.get().columnReactionsFree(), Images.EDIT_ADD.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jReactionsFree); jReactionsActive = StatusPanel.createLabel(TabsSlots.get().columnReactionsActive(), Images.UPDATE_WORKING.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jReactionsActive); jReactionsMax = StatusPanel.createLabel(TabsSlots.get().columnReactionsMax(), Images.UPDATE_DONE_OK.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jReactionsMax); jMarketOrders = StatusPanel.createIcon(Images.MISC_MARKET_ORDERS.getIcon(), TabsSlots.get().marketOrders()); this.addStatusbarLabel(jMarketOrders); jMarketOrdersFree = StatusPanel.createLabel(TabsSlots.get().columnMarketOrdersFree(), Images.EDIT_ADD.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jMarketOrdersFree); jMarketOrdersActive = StatusPanel.createLabel(TabsSlots.get().columnMarketOrdersActive(), Images.UPDATE_WORKING.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jMarketOrdersActive); jMarketOrdersMax = StatusPanel.createLabel(TabsSlots.get().columnMarketOrdersMax(), Images.UPDATE_DONE_OK.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jMarketOrdersMax); jContractCharacter = StatusPanel.createIcon(Images.MISC_CONTRACTS.getIcon(), TabsSlots.get().contractCharacter()); this.addStatusbarLabel(jContractCharacter); jContractCharacterFree = StatusPanel.createLabel(TabsSlots.get().columnMarketOrdersFree(), Images.EDIT_ADD.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jContractCharacterFree); jContractCharacterActive = StatusPanel.createLabel(TabsSlots.get().columnMarketOrdersActive(), Images.UPDATE_WORKING.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jContractCharacterActive); jContractCharacterMax = StatusPanel.createLabel(TabsSlots.get().columnMarketOrdersMax(), Images.UPDATE_DONE_OK.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jContractCharacterMax); jContractCorporation = StatusPanel.createIcon(Images.MISC_CONTRACTS_CORP.getIcon(), TabsSlots.get().contractCorporation()); this.addStatusbarLabel(jContractCorporation); jContractCorporationFree = StatusPanel.createLabel(TabsSlots.get().columnMarketOrdersFree(), Images.EDIT_ADD.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jContractCorporationFree); jContractCorporationActive = StatusPanel.createLabel(TabsSlots.get().columnMarketOrdersActive(), Images.UPDATE_WORKING.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jContractCorporationActive); jContractCorporationMax = StatusPanel.createLabel(TabsSlots.get().columnMarketOrdersMax(), Images.UPDATE_DONE_OK.getIcon(), AutoNumberFormat.LONG); this.addStatusbarLabel(jContractCorporationMax); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(jToolBar, jToolBar.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void updateData() { //Update Data slotsData.updateData(eventList); } @Override public void clearData() { try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); } finally { eventList.getReadWriteLock().writeLock().unlock(); } filterControl.clearCache(); } @Override public void updateCache() { filterControl.createCache(); } @Override public Collection getLocations() { try { eventList.getReadWriteLock().readLock().lock(); return new ArrayList<>(eventList); } finally { eventList.getReadWriteLock().readLock().unlock(); } } public EventList getEventList() { return eventList; } private class SlotsTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { JMenuInfo.slots(jPopupMenu, selectionModel.getSelected()); } @Override public void addToolMenu(JComponent jComponent) { } } private class ListenerClass implements ListEventListener { @Override public void listChanged(final ListEvent listChanges) { Slots total = new Slots(""); try { filterList.getReadWriteLock().readLock().lock(); for (Slots slots : filterList) { if (slots.isGrandTotal()) { continue; } total.count(slots); } } finally { filterList.getReadWriteLock().readLock().unlock(); } jManufacturingDone.setNumber(total.getManufacturingDone()); jManufacturingFree.setNumber(total.getManufacturingFree()); jManufacturingActive.setNumber(total.getManufacturingActive()); jManufacturingMax.setNumber(total.getManufacturingMax()); jReactionsDone.setNumber(total.getReactionsDone()); jReactionsFree.setNumber(total.getReactionsFree()); jReactionsActive.setNumber(total.getReactionsActive()); jReactionsMax.setNumber(total.getReactionsMax()); jResearchDone.setNumber(total.getResearchDone()); jResearchFree.setNumber(total.getResearchFree()); jResearchActive.setNumber(total.getResearchActive()); jResearchMax.setNumber(total.getResearchMax()); jMarketOrdersFree.setNumber(total.getMarketOrdersFree()); jMarketOrdersActive.setNumber(total.getMarketOrdersActive()); jMarketOrdersMax.setNumber(total.getMarketOrdersMax()); jContractCharacterFree.setNumber(total.getContractCharacterFree()); jContractCharacterActive.setNumber(total.getContractCharacterActive()); jContractCharacterMax.setNumber(total.getContractCharacterMax()); jContractCorporationFree.setNumber(total.getContractCorporationFree()); jContractCorporationActive.setNumber(total.getContractCorporationActive()); jContractCorporationMax.setNumber(total.getContractCorporationMax()); } } private class SlotsFilterControl extends FilterControl { public SlotsFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("ISK Table: " + msg); //Save ISK Filters and Export Settings } } public static class TotalComparator implements Comparator { @Override public int compare(final Slots o1, final Slots o2) { if (o1.isGrandTotal() && o2.isGrandTotal()) { return 0; //Equal (both StockpileTotal) } else if (o1.isGrandTotal()) { return 1; //After } else if (o2.isGrandTotal()) { return -1; //Before } else { return 0; //Equal (not StockpileTotal) } } } public static class IconHeaderRender implements TableCellRenderer, SortableRenderer { private static final Map icons = new HashMap<>(); private static final String MANUFACTURING = "Manufacturing"; private static final String RESEARCH = "Research"; private static final String REACTIONS = "Reactions"; private static final String MARKET_ORDERS = "Market Orders"; private static final String CONTRACTS_CHARACTER = "Character Contracts"; private static final String CONTRACTS_CORPORATION = "Corporation Contracts"; private boolean showIcon = false; private TableCellRenderer delegateRenderer; private Icon sortIcon; public IconHeaderRender(JTable jTable) { this.delegateRenderer = jTable.getTableHeader().getDefaultRenderer(); } public TableCellRenderer getDelegateRenderer() { return delegateRenderer; } public void setShowIcon(boolean showIcon) { this.showIcon = showIcon; } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component rendered = getDelegateTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (rendered instanceof JLabel) { final JLabel jLabel = (JLabel) rendered; jLabel.setHorizontalTextPosition(SwingConstants.LEADING); if (showIcon) { String text = jLabel.getText(); Icon icon = null; if (text.startsWith(MANUFACTURING)) { icon = Images.SLOTS_MANUFACTURING.getIcon(); jLabel.setText(text.replace(MANUFACTURING, "").trim()); } else if (text.startsWith(RESEARCH)) { icon = Images.SLOTS_RESEARCH.getIcon(); jLabel.setText(text.replace(RESEARCH, "").trim()); } else if (text.startsWith(REACTIONS)) { icon = Images.SLOTS_REACTIONS.getIcon(); jLabel.setText(text.replace(REACTIONS, "").trim()); } else if (text.startsWith(MARKET_ORDERS)) { icon = Images.SLOTS_MARKET_ORDERS.getIcon(); jLabel.setText(text.replace(MARKET_ORDERS, "").trim()); } else if (text.contains(CONTRACTS_CHARACTER)) { icon = Images.SLOTS_CONTRACTS.getIcon(); jLabel.setText(text.replace(CONTRACTS_CHARACTER + " ", "").trim()); } else if (text.contains(CONTRACTS_CORPORATION)) { icon = Images.SLOTS_CONTRACTS_CORP.getIcon(); jLabel.setText(text.replace(CONTRACTS_CORPORATION + " ", "").trim()); } if (sortIcon != null && icon != null) { jLabel.setIcon(getIcon(icon, sortIcon)); } else if (sortIcon != null) { jLabel.setIcon(sortIcon); } else if (icon != null) { jLabel.setIcon(icon); } else { jLabel.setIcon(null); } } else { jLabel.setIcon(sortIcon); } } return rendered; } @Override public void setSortIcon(Icon sortIcon) { this.sortIcon = sortIcon; } private Component getDelegateTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { try { return delegateRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); } catch (RuntimeException e) { delegateRenderer = new DefaultTableCellRenderer(); return delegateRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); } } private Icon getIcon(Icon icon1, Icon icon2) { Icons key = new Icons(icon1, icon2); Icon value = icons.get(key); if (value != null) { return value; } value = createIcon(icon1, icon2); icons.put(key, value); return value; } private Icon createIcon(Icon icon1, Icon icon2) { int w = icon1.getIconWidth() + icon2.getIconWidth() + 3; int h = Math.max(icon1.getIconHeight(), icon2.getIconHeight()); int y1 = 0; int y2 = 0; if (icon1.getIconHeight() > icon2.getIconHeight()) { y2 = (int) Math.ceil((h - icon2.getIconHeight()) / 2.0); } else if (icon2.getIconHeight() > icon1.getIconHeight()) { y1 = (int) Math.ceil((h - icon1.getIconHeight()) / 2.0); } Image image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = (Graphics2D) image.getGraphics(); icon1.paintIcon(null, g2, 0, y1); icon2.paintIcon(null, g2, icon1.getIconWidth() + 3, y2); g2.dispose(); return new ImageIcon(image); } private static class Icons { private final Icon icon1; private final Icon icon2; public Icons(Icon icon1, Icon icon2) { this.icon1 = icon1; this.icon2 = icon2; } @Override public int hashCode() { int hash = 7; hash = 83 * hash + Objects.hashCode(this.icon1); hash = 83 * hash + Objects.hashCode(this.icon2); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Icons other = (Icons) obj; if (!Objects.equals(this.icon1, other.icon1)) { return false; } if (!Objects.equals(this.icon2, other.icon2)) { return false; } return true; } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/slots/SlotsTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.slots; import java.util.Comparator; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.TabsSlots; public enum SlotsTableFormat implements EnumTableColumn { NAME(String.class) { @Override public String getColumnName() { return TabsSlots.get().columnOwner(); } @Override public Object getColumnValue(final Slots from) { return from.getName(); } }, MANUFACTURING_DONE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnManufacturingDone(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnManufacturingDone(); } @Override public Object getColumnValue(final Slots from) { return from.getManufacturingDone(); } }, MANUFACTURING_FREE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnManufacturingFree(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnManufacturingFree(); } @Override public Object getColumnValue(final Slots from) { return from.getManufacturingFree(); } }, MANUFACTURING_ACTIVE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnManufacturingActive(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnManufacturingActive(); } @Override public Object getColumnValue(final Slots from) { return from.getManufacturingActive(); } }, MANUFACTURING_MAX(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnManufacturingMax(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnManufacturingMax(); } @Override public Object getColumnValue(final Slots from) { return from.getManufacturingMax(); } }, RESEARCH_DONE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnResearchDone(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnResearchDone(); } @Override public Object getColumnValue(final Slots from) { return from.getResearchDone(); } }, RESEARCH_FREE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnResearchFree(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnResearchFree(); } @Override public Object getColumnValue(final Slots from) { return from.getResearchFree(); } }, RESEARCH_ACTIVE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnResearchActive(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnResearchActive(); } @Override public Object getColumnValue(final Slots from) { return from.getResearchActive(); } }, RESEARCH_MAX(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnResearchMax(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnResearchMax(); } @Override public Object getColumnValue(final Slots from) { return from.getResearchMax(); } }, REACTIONS_DONE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnReactionsDone(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnReactionsDone(); } @Override public Object getColumnValue(final Slots from) { return from.getReactionsDone(); } }, REACTIONS_FREE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnReactionsFree(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnReactionsFree(); } @Override public Object getColumnValue(final Slots from) { return from.getReactionsFree(); } }, REACTIONS_ACTIVE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnReactionsActive(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnReactionsActive(); } @Override public Object getColumnValue(final Slots from) { return from.getReactionsActive(); } }, REACTIONS_MAX(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnReactionsMax(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnReactionsMax(); } @Override public Object getColumnValue(final Slots from) { return from.getReactionsMax(); } }, MARKET_ORDERS_FREE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnMarketOrdersFree(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnMarketOrdersFree(); } @Override public Object getColumnValue(final Slots from) { return from.getMarketOrdersFree(); } }, MARKET_ORDERS_ACTIVE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnMarketOrdersActive(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnMarketOrdersActive(); } @Override public Object getColumnValue(final Slots from) { return from.getMarketOrdersActive(); } }, MARKET_ORDERS_MAX(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnMarketOrdersMax(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnMarketOrdersMax(); } @Override public Object getColumnValue(final Slots from) { return from.getMarketOrdersMax(); } }, CONTRACT_CHARACTER_FREE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnContractCharacterFree(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnContractCharacterFree(); } @Override public Object getColumnValue(final Slots from) { return from.getContractCharacterFree(); } }, CONTRACT_CHARACTER_ACTIVE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnContractCharacterActive(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnContractCharacterActive(); } @Override public Object getColumnValue(final Slots from) { return from.getContractCharacterActive(); } }, CONTRACT_CHARACTER_MAX(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnContractCharacterMax(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnContractCharacterMax(); } @Override public Object getColumnValue(final Slots from) { return from.getContractCharacterMax(); } }, CONTRACT_CORPORATION_FREE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnContractCorporationFree(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnContractCorporationFree(); } @Override public Object getColumnValue(final Slots from) { return from.getContractCorporationFree(); } }, CONTRACT_CORPORATION_ACTIVE(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnContractCorporationActive(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnContractCorporationActive(); } @Override public Object getColumnValue(final Slots from) { return from.getContractCorporationActive(); } }, CONTRACT_CORPORATION_MAX(Integer.class) { @Override public String getColumnName() { return TabsSlots.get().columnContractCorporationMax(); } @Override public String getColumnToolTip() { return TabsSlots.get().columnContractCorporationMax(); } @Override public Object getColumnValue(final Slots from) { return from.getContractCorporationMax(); } }, CURRENT_SHIP(String.class) { @Override public String getColumnName() { return TabsSlots.get().columnCurrentShip(); } @Override public Object getColumnValue(final Slots from) { return from.getActiveShip(); } }, CURRENT_STATION(String.class) { @Override public String getColumnName() { return TabsSlots.get().columnCurrentStation(); } @Override public Object getColumnValue(final Slots from) { return from.getCurrentStation(); } }, CURRENT_SYSTEM(String.class) { @Override public String getColumnName() { return TabsSlots.get().columnCurrentSystem(); } @Override public Object getColumnValue(final Slots from) { return from.getCurrentSystem(); } }, CURRENT_CONSTELLATION(String.class) { @Override public String getColumnName() { return TabsSlots.get().columnCurrentConstellation(); } @Override public Object getColumnValue(final Slots from) { return from.getCurrentConstellation(); } }, CURRENT_REGION(String.class) { @Override public String getColumnName() { return TabsSlots.get().columnCurrentRegion(); } @Override public Object getColumnValue(final Slots from) { return from.getCurrentRegion(); } }; private final Class type; private final Comparator comparator; private SlotsTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/standing/NpcStandingTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.standing; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.settings.tag.TagUpdate; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabPrimary; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.PaddingTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.TabsNpcStanding; public class NpcStandingTab extends JMainTabPrimary implements TagUpdate { //GUI private final JAutoColumnTable jTable; //Table private final NpcStandingFilterControl filterControl; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventTableModel tableModel; private final EventList eventList; private final FilterList filterList; private final DefaultEventSelectionModel selectionModel; public static final String NAME = "npcstanding"; //Not to be changed! public NpcStandingTab(final Program program) { super(program, NAME, TabsNpcStanding.get().npcStanding(), Images.TOOL_NPC_STANDING.getIcon(), true); layout.setAutoCreateGaps(true); //Table Format tableFormat = TableFormatFactory.npcStandingTableFormat(); //Backend eventList = program.getProfileData().getNpcStandingsEventList(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedList); eventList.getReadWriteLock().readLock().unlock(); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JAutoColumnTable(program, tableModel); jTable.setCellSelectionEnabled(true); jTable.setRowSelectionAllowed(true); jTable.setColumnSelectionAllowed(true); jTable.setRowHeight(MyNpcStanding.IMAGE_SIZE.getSize()); PaddingTableCellRenderer.install(jTable, 0, 5, 0, 5); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new NpcStandingFilterControl(sortedList); //Menu installTableTool(new NpcStandingTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, MyNpcStanding.class); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void updateTags() { beforeUpdateData(); tableModel.fireTableDataChanged(); filterControl.refilter(); afterUpdateData(); } @Override public void clearData() { } @Override public void updateCache() { filterControl.createCache(); } @Override public Collection getLocations() { return new ArrayList<>(); //LocationsType } public boolean isFiltersEmpty() { return filterControl.isFiltersEmpty(); } public void addFilters(final List filters) { filterControl.addFilters(filters); } public void clearFilters() { filterControl.clearCurrentFilters(); } public String getCurrentFilterName() { return filterControl.getCurrentFilterName(); } private class NpcStandingTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { } @Override public void addToolMenu(JComponent jComponent) { } } private class NpcStandingFilterControl extends FilterControl { public NpcStandingFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("Npc Standing Table: " + msg); //Save Npc Standing Filters and Export Settings } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/standing/NpcStandingTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.standing; import java.util.Comparator; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.api.raw.RawNpcStanding.FromType; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.Security; import net.nikr.eve.jeveasset.gui.shared.table.containers.Standing; import net.nikr.eve.jeveasset.gui.shared.table.containers.TextIcon; import net.nikr.eve.jeveasset.i18n.TabsNpcStanding; public enum NpcStandingTableFormat implements EnumTableColumn { OWNER(TextIcon.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnOwner(); } @Override public Object getColumnValue(final MyNpcStanding from) { return from.getOwnerTextIcon(); } }, FACTION(TextIcon.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnFaction(); } @Override public Object getColumnValue(final MyNpcStanding from) { return from.getFactionTextIcon(); } }, CORPORATION(TextIcon.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnCorporation(); } @Override public Object getColumnValue(final MyNpcStanding from) { return from.getCorporationTextIcon(); } }, AGENT(TextIcon.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnAgent(); } @Override public Object getColumnValue(final MyNpcStanding from) { return from.getAgentTextIcon(); } }, LEVEL(Integer.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnAgentLevel(); } @Override public Object getColumnValue(final MyNpcStanding from) { return from.getAgent().getLevel(); } }, DIVISION(String.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnAgentDivision(); } @Override public Object getColumnValue(final MyNpcStanding from) { return from.getAgent().getDivision(); } }, AGENT_TYPE(String.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnAgentType(); } @Override public Object getColumnValue(final MyNpcStanding from) { return from.getAgent().getAgentType(); } }, TYPE(FromType.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnType(); } @Override public Object getColumnValue(final MyNpcStanding from) { return from.getFromType(); } }, RAW_STANDING(Standing.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnRawStanding(); } @Override public String getColumnToolTip() { return TabsNpcStanding.get().columnRawStandingToolTip(); } @Override public Object getColumnValue(final MyNpcStanding from) { return Standing.create(from.getStanding()); } }, STANDING(Standing.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnStanding(); } @Override public String getColumnToolTip() { return TabsNpcStanding.get().columnStandingToolTip(); } @Override public Object getColumnValue(final MyNpcStanding from) { return Standing.create(from.getStandingEffective()); } }, MAX_STANDING(Standing.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnStandingMax(); } @Override public String getColumnToolTip() { return TabsNpcStanding.get().columnStandingMaxToolTip(); } @Override public Object getColumnValue(final MyNpcStanding from) { return Standing.create(from.getStandingMaximum()); } }, LOCATION(String.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnLocation(); } @Override public Object getColumnValue(final MyNpcStanding from) { return from.getLocation(); } }, SECURITY(Security.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnSecurity(); } @Override public Object getColumnValue(final MyNpcStanding from) { return from.getSecurityObject(); } }, SYSTEM(String.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnSystem(); } @Override public Object getColumnValue(final MyNpcStanding from) { return from.getSystem(); } }, CONSTELLATION(String.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnConstellation(); } @Override public Object getColumnValue(final MyNpcStanding from) { return from.getConstellation(); } }, REGION(String.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnRegion(); } @Override public Object getColumnValue(final MyNpcStanding from) { return from.getRegion(); } }, ID(Integer.class) { @Override public String getColumnName() { return TabsNpcStanding.get().columnID(); } @Override public Object getColumnValue(final MyNpcStanding from) { return from.getFromID(); } }; private final Class type; private final Comparator comparator; private NpcStandingTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/stockpile/JStockpileItemMenu.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.stockpile; import ca.odell.glazedlists.SeparatorList; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.Icon; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.IndustryMaterial; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.MenuScroller; import static net.nikr.eve.jeveasset.gui.shared.menu.JMenuStockpile.getBlueprintSelect; import static net.nikr.eve.jeveasset.gui.shared.menu.JMenuStockpile.getFormulaSelect; import static net.nikr.eve.jeveasset.gui.shared.menu.JMenuStockpile.match; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileTotal; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileBpDialog.BpData; import net.nikr.eve.jeveasset.i18n.TabsStockpile; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class JStockpileItemMenu extends JMenu { private enum StockpileItemMenuAction { EDIT_ITEM, ADD_TO, DELETE_ITEM, ORIGINAL, COPY, RUNS } private final StockpileTab stockpileTab; private Program program; public JStockpileItemMenu(final StockpileTab stockpileTab, final Program program, final List edit, final List delete, final List items) { super(TabsStockpile.get().stockpile()); this.program = program; this.stockpileTab = stockpileTab; this.setIcon(Images.TOOL_STOCKPILE.getIcon()); ListenerClass listener = new ListenerClass(); JMenuItem jMenuItem; JMenu jMenu; JMenu jAddToo = new JMenu(TabsStockpile.get().addToStockpile()); jAddToo.setIcon(Images.EDIT_ADD.getIcon()); jAddToo.setEnabled(!items.isEmpty()); this.add(jAddToo); MenuScroller menuScroller = new MenuScroller(jAddToo); menuScroller.keepVisible(2); menuScroller.setTopFixedCount(2); menuScroller.setInterval(125); if (!items.isEmpty()) { jMenuItem = new JStockpileMenuItem(TabsStockpile.get().addToNewStockpile(), Images.EDIT_ADD.getIcon(), items); jMenuItem.setActionCommand(StockpileItemMenuAction.ADD_TO.name()); jMenuItem.addActionListener(listener); jAddToo.add(jMenuItem); jAddToo.addSeparator(); for (Stockpile stockpile : StockpileTab.getShownStockpiles(program)) { jMenuItem = new JStockpileMenuItem(stockpile, Images.TOOL_STOCKPILE.getIcon(), items); jMenuItem.setActionCommand(StockpileItemMenuAction.ADD_TO.name()); jMenuItem.addActionListener(listener); jAddToo.add(jMenuItem); } } jMenuItem = new JStockpileMenuItem(TabsStockpile.get().editItem(), Images.EDIT_EDIT.getIcon(), edit); jMenuItem.setActionCommand(StockpileItemMenuAction.EDIT_ITEM.name()); jMenuItem.addActionListener(listener); jMenuItem.setEnabled(edit.size() == 1); this.add(jMenuItem); jMenuItem = new JStockpileMenuItem(TabsStockpile.get().deleteItem(), Images.EDIT_DELETE.getIcon(), delete); jMenuItem.setActionCommand(StockpileItemMenuAction.DELETE_ITEM.name()); jMenuItem.addActionListener(listener); jMenuItem.setEnabled(!delete.isEmpty()); this.add(jMenuItem); boolean blueprint = false; for (Object object : items) { if (object instanceof SeparatorList.Separator || object instanceof StockpileTotal || (!(object instanceof StockpileItem))) { continue; } StockpileItem item = (StockpileItem) object; if (item.isBlueprint()) { blueprint = true; break; } } this.addSeparator(); jMenu = new JMenu(TabsStockpile.get().blueprints()); jMenu.setIcon(Images.MISC_BLUEPRINT.getIcon()); this.add(jMenu); jMenuItem = new JStockpileMenuItem(TabsStockpile.get().original(), Images.MISC_BPO.getIcon(), items); jMenuItem.setActionCommand(StockpileItemMenuAction.ORIGINAL.name()); jMenuItem.addActionListener(listener); jMenuItem.setEnabled(blueprint); jMenu.add(jMenuItem); jMenuItem = new JStockpileMenuItem(TabsStockpile.get().copy(), Images.MISC_BPC.getIcon(), items); jMenuItem.setActionCommand(StockpileItemMenuAction.COPY.name()); jMenuItem.addActionListener(listener); jMenuItem.setEnabled(blueprint); jMenu.add(jMenuItem); jMenuItem = new JStockpileMenuItem(TabsStockpile.get().runs(), Images.MISC_RUNS.getIcon(), items); jMenuItem.setActionCommand(StockpileItemMenuAction.RUNS.name()); jMenuItem.addActionListener(listener); jMenuItem.setEnabled(blueprint); jMenu.add(jMenuItem); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(ActionEvent e) { if (StockpileItemMenuAction.ADD_TO.name().equals(e.getActionCommand())) { //Add item to Object source = e.getSource(); if (source instanceof JStockpileMenuItem) { JStockpileMenuItem jMenuItem = (JStockpileMenuItem) source; List items = new ArrayList<>(); BpData blueprintSelect = null; BpData formulaSelect = null; for (StockpileItem stockpileItem : jMenuItem.getItems()) { Stockpile stockpile = stockpileItem.getStockpile(); Item item = stockpileItem.getItem(); if (stockpileItem.isBlueprint() && blueprintSelect == null) { blueprintSelect = getBlueprintSelect(program, true); if (blueprintSelect == null) { return; //Cancel } } if (item.isFormula() && formulaSelect == null) { formulaSelect = getFormulaSelect(program); if (formulaSelect == null) { return; //Cancel } } if (match(item, blueprintSelect, formulaSelect, TabsStockpile.get().original())) { //PBO items.add(new StockpileItem(stockpile, item, item.getTypeID(), stockpileItem.getCountMinimum(), false)); } else if (match(item, blueprintSelect, null, TabsStockpile.get().copy())) { //BPC items.add(new StockpileItem(stockpile, item, -item.getTypeID(), stockpileItem.getCountMinimum(), false)); } else if (match(item, blueprintSelect, null, TabsStockpile.get().runs())) { //BPC Runs items.add(new StockpileItem(stockpile, item, -item.getTypeID(), stockpileItem.getCountMinimum(), true)); } else if (match(item, blueprintSelect, null, TabsStockpile.get().materialsManufacturing())) { //BP Materials for (IndustryMaterial material : item.getManufacturingMaterials()) { double count = blueprintSelect.doMath(material.getQuantity(), stockpileItem.getCountMinimum()); Item materialItem = ApiIdConverter.getItem(material.getTypeID()); items.add(new StockpileItem(stockpile, materialItem, material.getTypeID(), count, false)); } } else if (match(item, null, formulaSelect, TabsStockpile.get().materialsReaction())) { //Reaction Materials for (IndustryMaterial material : item.getReactionMaterials()) { Item materialItem = ApiIdConverter.getItem(material.getTypeID()); double count = formulaSelect.doMath(material.getQuantity(), stockpileItem.getCountMinimum()); items.add(new StockpileItem(stockpile, materialItem, material.getTypeID(), count, false)); } } else { //source or not bluepint/formula items.add(stockpileItem); } } stockpileTab.addToStockpile(jMenuItem.getStockpile(), items, true, true); } } else if (StockpileItemMenuAction.RUNS.name().equals(e.getActionCommand())) { //Runs Object source = e.getSource(); if (source instanceof JStockpileMenuItem) { updateBlueprint((JStockpileMenuItem) source, new ChangeBlueprintType() { @Override public StockpileItem getUpdatedItem(StockpileItem item) { //Runs: -typeID & runs=true return new StockpileItem(item.getStockpile(), item.getItem(), -item.getTypeID(), item.getCountMinimum(), true); } @Override public boolean include(StockpileItem item) { return !item.isRuns(); } }); } } else if (StockpileItemMenuAction.ORIGINAL.name().equals(e.getActionCommand())) { //Original Object source = e.getSource(); if (source instanceof JStockpileMenuItem) { updateBlueprint((JStockpileMenuItem) source, new ChangeBlueprintType() { @Override public StockpileItem getUpdatedItem(StockpileItem item) { //BPO: +typeID & runs=false return new StockpileItem(item.getStockpile(), item.getItem(), item.getTypeID(), item.getCountMinimum(), false); } @Override public boolean include(StockpileItem item) { return !item.isBPO(); } }); } } else if (StockpileItemMenuAction.COPY.name().equals(e.getActionCommand())) { //Copy Object source = e.getSource(); if (source instanceof JStockpileMenuItem) { updateBlueprint((JStockpileMenuItem) source, new ChangeBlueprintType() { @Override public StockpileItem getUpdatedItem(StockpileItem item) { //BPC: -typeID & runs=false return new StockpileItem(item.getStockpile(), item.getItem(), -item.getTypeID(), item.getCountMinimum(), false); } @Override public boolean include(StockpileItem item) { return item.isBPO() || item.isRuns(); } }); } } else if (StockpileItemMenuAction.EDIT_ITEM.name().equals(e.getActionCommand())) { //Edit item Object source = e.getSource(); if (source instanceof JStockpileMenuItem) { JStockpileMenuItem jMenuItem = (JStockpileMenuItem) source; List items = jMenuItem.getItems(); if (items.size() == 1) { stockpileTab.editItem(items.get(0)); } } } else if (StockpileItemMenuAction.DELETE_ITEM.name().equals(e.getActionCommand())) { //Delete item Object source = e.getSource(); if (source instanceof JStockpileMenuItem) { JStockpileMenuItem jMenuItem = (JStockpileMenuItem) source; List items = jMenuItem.getItems(); if (!items.isEmpty()) { int value; if (items.size() == 1) { value = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), items.get(0).getName(), TabsStockpile.get().deleteItemTitle(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); } else { value = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), TabsStockpile.get().deleteItems(items.size()), TabsStockpile.get().deleteItemTitle(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); } if (value == JOptionPane.OK_OPTION) { Settings.lock("Stokcpile (Stockpile Menu)"); //Lock for Stokcpile (Stockpile Menu) for (StockpileItem item : items) { item.getStockpile().remove(item); } Settings.unlock("Stokcpile (Stockpile Menu)"); //Unlock for Stokcpile (Stockpile Menu) program.saveSettings("Stokcpile (Stockpile Menu)"); //Save Stokcpile (Stockpile Menu) stockpileTab.removeItems(items); } } } } } } private void updateBlueprint(JStockpileMenuItem jMenuItem, ChangeBlueprintType blueprintTypeChange) { //Find items that will be changed Map> update = new HashMap<>(); for (StockpileItem stockpileItem : jMenuItem.getItems()) { if (stockpileItem.isBlueprint() && blueprintTypeChange.include(stockpileItem)) { List list = update.get(stockpileItem.getStockpile()); if (list == null) { list = new ArrayList<>(); update.put(stockpileItem.getStockpile(), list); } list.add(stockpileItem); } } Settings.lock("Stokcpile (Stockpile Menu)"); //Lock for Stokcpile (Stockpile Menu) //Remove items that will be changed for (Map.Entry> entry : update.entrySet()) { for (StockpileItem item : entry.getValue()) { entry.getKey().remove(item); } stockpileTab.removeItems(entry.getValue()); } //Change items for (Map.Entry> entry : update.entrySet()) { for (StockpileItem item : entry.getValue()) { item.update(blueprintTypeChange.getUpdatedItem(item)); } } Settings.unlock("Stokcpile (Stockpile Menu)"); //Unlock for Stokcpile (Stockpile Menu) //Add changed items for (Map.Entry> entry : update.entrySet()) { stockpileTab.addToStockpile(entry.getKey(), entry.getValue(), true, false); } program.saveSettings("Stockpile (Stockpile Menu)"); //Save Stockpile (Stockpile Menu) } private interface ChangeBlueprintType { public StockpileItem getUpdatedItem(StockpileItem item); public boolean include(StockpileItem item); } public static class JStockpileMenuItem extends JMenuItem { private final List items = new ArrayList<>(); private final Stockpile stockpile; public JStockpileMenuItem(final Stockpile stockpile, final Icon icon, final List items) { this(stockpile.getName(), icon, items, stockpile); } public JStockpileMenuItem(final String title, final Icon icon, final List items) { this(title, icon, items, null); } private JStockpileMenuItem(final String title, final Icon icon, final List items, final Stockpile stockpile) { super(title, icon); this.stockpile = stockpile; for (int i = 0; i < items.size(); i++) { //Remove StockpileTotal and SeparatorList.Separator Object item = items.get(i); if (!(item instanceof SeparatorList.Separator) && !(item instanceof StockpileTotal)) { this.items.add((StockpileItem) item); } } } public List getItems() { return items; } public Stockpile getStockpile() { return stockpile; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/stockpile/JStockpileTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.stockpile; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import java.awt.Cursor; import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import javax.swing.JLabel; import javax.swing.ToolTipManager; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.InstantToolTip; import net.nikr.eve.jeveasset.gui.shared.table.JSeparatorTable; import net.nikr.eve.jeveasset.gui.shared.table.TableCellRenderers.TargetCellRenderer; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileTotal; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.SubpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.SubpileStock; import net.nikr.eve.jeveasset.i18n.TabsStockpile; public class JStockpileTable extends JSeparatorTable { private final DefaultEventTableModel tableModel; private int lastColumn = -1; private int lastRow = -1; public JStockpileTable(final Program program, final DefaultEventTableModel tableModel, SeparatorList separatorList) { super(program, tableModel, separatorList); this.tableModel = tableModel; InstantToolTip.install(this); this.setDefaultRenderer(Double.class, new TargetCellRenderer(tableModel)); this.disableColumnResizeCache(StockpileTableFormat.COUNT_MINIMUM); final Cursor cursor = getCursor(); addMouseMotionListener(new MouseMotionListener() { @Override public void mouseDragged(MouseEvent e) { } @Override public void mouseMoved(MouseEvent e) { Point p = e.getPoint(); int column = columnAtPoint(p); int row = rowAtPoint(p); if (lastColumn == column && lastRow == row) { return; } if (column < 0 || column >= getColumnCount()) { return; //Out of bounce } if (row < 0 || row >= getRowCount()) { return; //Out of bounce } lastColumn = column; lastRow = row; String columnName = (String) getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); if (columnName.equals(StockpileTableFormat.COUNT_MINIMUM.getColumnName())) { Object object = tableModel.getElementAt(row); if (object instanceof StockpileItem) { StockpileItem stockpileItem = (StockpileItem) object; if (stockpileItem.isEditable()) { setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); ToolTipManager.sharedInstance().setEnabled(false); ToolTipManager.sharedInstance().setEnabled(true); setToolTipText(TabsStockpile.get().editCell()); return; //Don't set default } } } //Default setToolTipText(null); setCursor(cursor); } }); } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); boolean isSelected = isCellSelected(row, column); Object object = tableModel.getElementAt(row); String columnName = (String) this.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); if (object instanceof StockpileItem) { StockpileItem stockpileItem = (StockpileItem) object; if (stockpileItem.isEditable() && columnName.equals(StockpileTableFormat.COUNT_MINIMUM.getColumnName())) { if (component instanceof JLabel) { JLabel jLabel = (JLabel) component; int columnWidth = getColumnModel().getColumn(column).getWidth() - 2 + TargetCellRenderer.MINIMUM_ICON_TEXT_GAP; int jLabelWidth = jLabel.getPreferredSize().width; jLabel.setIconTextGap(Math.max(TargetCellRenderer.MINIMUM_ICON_TEXT_GAP, columnWidth - jLabelWidth)); } } //Background if (object instanceof SubpileStock) { //Subpile if (columnName.equals(StockpileTableFormat.COUNT_MINIMUM.getColumnName())) { if (!stockpileItem.isEditable()) { ColorSettings.configCell(component, ColorEntry.GLOBAL_GRAND_TOTAL, isSelected); return component; } } else if (columnName.equals(StockpileTableFormat.NAME.getColumnName())) { ColorSettings.configCell(component, ColorEntry.GLOBAL_GRAND_TOTAL, isSelected); return component; } else if (columnName.equals(StockpileTableFormat.TAGS.getColumnName())) { ColorSettings.configCell(component, ColorEntry.GLOBAL_GRAND_TOTAL, isSelected); return component; } else if (!columnName.equals(StockpileTableFormat.GROUP.getColumnName()) && !columnName.equals(StockpileTableFormat.COUNT_MINIMUM_MULTIPLIED.getColumnName())) { component.setForeground(component.getBackground()); return component; } } else if (object instanceof SubpileItem) { //Total if (!stockpileItem.isEditable() && columnName.equals(StockpileTableFormat.COUNT_MINIMUM.getColumnName())) { ColorSettings.configCell(component, ColorEntry.GLOBAL_GRAND_TOTAL, isSelected); } else if (columnName.equals(StockpileTableFormat.TAGS.getColumnName())) { ColorSettings.configCell(component, ColorEntry.GLOBAL_GRAND_TOTAL, isSelected); } } else if (object instanceof StockpileTotal) { //Total ColorSettings.configCell(component, ColorEntry.GLOBAL_GRAND_TOTAL, isSelected); } if (columnName.equals(StockpileTableFormat.NAME.getColumnName())) { if (Settings.get().isStockpileHalfColors()) { if (stockpileItem.getPercentNeeded() >= (Settings.get().getStockpileColorGroup3() / 100.0) ) { //Group 3 ColorSettings.configCell(component, ColorEntry.STOCKPILE_TABLE_OVER_THRESHOLD, isSelected); } else if (stockpileItem.getPercentNeeded() >= (Settings.get().getStockpileColorGroup2() / 100.0) ) { //Group 2 ColorSettings.configCell(component, ColorEntry.STOCKPILE_TABLE_BELOW_THRESHOLD_2ND, isSelected); } else { //Group 1 ColorSettings.configCell(component, ColorEntry.STOCKPILE_TABLE_BELOW_THRESHOLD, isSelected); } } else { if (stockpileItem.getPercentNeeded() >= (Settings.get().getStockpileColorGroup2() / 100.0) ) { //Group 2 ColorSettings.configCell(component, ColorEntry.STOCKPILE_TABLE_OVER_THRESHOLD, isSelected); } else { //Group 1 ColorSettings.configCell(component, ColorEntry.STOCKPILE_TABLE_BELOW_THRESHOLD, isSelected); } } } else if (stockpileItem.isIgnoreMultiplier() && columnName.equals(StockpileTableFormat.COUNT_MINIMUM_MULTIPLIED.getColumnName())) { ColorSettings.configCell(component, ColorEntry.GLOBAL_GRAND_TOTAL, isSelected); } //Foreground if (columnName.equals(StockpileTableFormat.COUNT_NOW_INVENTORY.getColumnName()) && !stockpileItem.getStockpile().isAssets()) { component.setForeground(component.getBackground()); } else if (columnName.equals(StockpileTableFormat.COUNT_NOW_BUY_ORDERS.getColumnName()) && (!stockpileItem.getStockpile().isBuyOrders() || stockpileItem.isRuns())) { component.setForeground(component.getBackground()); } else if (columnName.equals(StockpileTableFormat.COUNT_NOW_SELL_ORDERS.getColumnName()) && (!stockpileItem.getStockpile().isSellOrders() || stockpileItem.isRuns())) { component.setForeground(component.getBackground()); } else if (columnName.equals(StockpileTableFormat.COUNT_NOW_BUY_TRANSACTIONS.getColumnName()) && (!stockpileItem.getStockpile().isBuyTransactions() || stockpileItem.isRuns())) { component.setForeground(component.getBackground()); } else if (columnName.equals(StockpileTableFormat.COUNT_NOW_SELL_TRANSACTIONS.getColumnName()) && (!stockpileItem.getStockpile().isSellTransactions() || stockpileItem.isRuns())) { component.setForeground(component.getBackground()); } else if (columnName.equals(StockpileTableFormat.COUNT_NOW_JOBS.getColumnName()) && !stockpileItem.getStockpile().isJobs()) { component.setForeground(component.getBackground()); } else if (columnName.equals(StockpileTableFormat.COUNT_NOW_SELLING_CONTRACTS.getColumnName()) && (!stockpileItem.getStockpile().isSellingContracts() || stockpileItem.isRuns())) { component.setForeground(component.getBackground()); } else if (columnName.equals(StockpileTableFormat.COUNT_NOW_SOLD_CONTRACTS.getColumnName()) && (!stockpileItem.getStockpile().isSoldContracts() || stockpileItem.isRuns())) { component.setForeground(component.getBackground()); } else if (columnName.equals(StockpileTableFormat.COUNT_NOW_BUYING_CONTRACTS.getColumnName()) && (!stockpileItem.getStockpile().isBuyingContracts() || stockpileItem.isRuns())) { component.setForeground(component.getBackground()); } else if (columnName.equals(StockpileTableFormat.COUNT_NOW_BOUGHT_CONTRACTS.getColumnName()) && (!stockpileItem.getStockpile().isBoughtContracts() || stockpileItem.isRuns())) { component.setForeground(component.getBackground()); } else if (columnName.equals(StockpileTableFormat.COUNT_NEEDED.getColumnName()) && stockpileItem.getCountNeeded() < 0) { ColorSettings.configCell(component, ColorEntry.GLOBAL_VALUE_NEGATIVE, isSelected); } else if (columnName.equals(StockpileTableFormat.VALUE_NEEDED.getColumnName()) && stockpileItem.getValueNeeded() < 0) { ColorSettings.configCell(component, ColorEntry.GLOBAL_VALUE_NEGATIVE, isSelected); } else if (columnName.equals(StockpileTableFormat.VOLUME_NEEDED.getColumnName()) && stockpileItem.getVolumeNeeded() < 0) { ColorSettings.configCell(component, ColorEntry.GLOBAL_VALUE_NEGATIVE, isSelected); } } return component; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/stockpile/Stockpile.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.stockpile; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.TimeZone; import java.util.TreeSet; import java.util.concurrent.atomic.AtomicLong; import javax.swing.JButton; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.ItemFlag; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.PriceData; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.tag.TagID; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.data.settings.types.BlueprintType; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.data.settings.types.LocationsType; import net.nikr.eve.jeveasset.data.settings.types.MarketDetailType; import net.nikr.eve.jeveasset.data.settings.types.OwnersType; import net.nikr.eve.jeveasset.data.settings.types.PriceType; import net.nikr.eve.jeveasset.data.settings.types.TagsType; import net.nikr.eve.jeveasset.gui.shared.CopyHandler.CopySeparator; import net.nikr.eve.jeveasset.gui.shared.components.JButtonComparable; import net.nikr.eve.jeveasset.gui.shared.components.JButtonNull; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileContainer; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileFlag; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.i18n.TabsStockpile; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class Stockpile implements Comparable, LocationsType, OwnersType { private static final Calendar CALENDAR = Calendar.getInstance(TimeZone.getTimeZone("GMT")); private static final AtomicLong TS = new AtomicLong(); private final long id; private String name; private String ownerName; private String flagName; private String locationName; private String containerName; private List filters = new ArrayList<>(); private final Set items = new TreeSet<>(); private final StockpileTotal totalItem = new StockpileTotal(this); private final Map subpiles = new HashMap<>(); private final List subpileLinks = new ArrayList<>(); private final List subpileAll = new ArrayList<>(); private final List subpileItems = new ArrayList<>(); private final List subpileStocks = new ArrayList<>(); private double percentFull; private double multiplier; private boolean matchAll; private boolean assets = false; private boolean jobs = false; private boolean buyOrders = false; private boolean sellOrders = false; private boolean transactions = false; private boolean buyTransactions = false; private boolean sellTransactions = false; private boolean contracts = false; private boolean buyingContracts = false; private boolean sellingContracts = false; private boolean soldContracts = false; private boolean boughtContracts = false; private Stockpile(final Stockpile stockpile) { update(stockpile); for (StockpileItem item : stockpile.getItems()) { if (item.isTotal()) { continue; //Ignore Total } items.add(new StockpileItem(this, item)); } items.add(totalItem); this.id = getNewID(); //New stockpile = new id } /** * Copy with new name. * @param name * @param stockpile */ public Stockpile(final String name, final Stockpile stockpile) { update(stockpile); this.name = name; this.id = getNewID(); //New stockpile = new id items.add(totalItem); updateDynamicValues(); } public Stockpile(final String name, final Long id, final List filters, double multiplier, boolean matchAll) { this.name = name; this.filters = filters; this.multiplier = multiplier; this.matchAll = matchAll; if (id == null) { this.id = getNewID(); } else { this.id = id; } items.add(totalItem); updateDynamicValues(); } final void update(final Stockpile stockpile) { this.name = stockpile.getName(); this.ownerName = stockpile.getOwnerName(); this.filters = stockpile.getFilters(); this.flagName = stockpile.getFlagName(); this.multiplier = stockpile.getMultiplier(); this.matchAll = stockpile.isMatchAll(); updateDynamicValues(); } final void updateDynamicValues() { createContainerName(); createLocationName(); createInclude(); } void updateTags() { for (StockpileItem item : items) { item.updateTags(); } } public long getStockpileID() { return id; } public String getGroup() { return Settings.get().getStockpileGroupSettings().getGroup(this); } private static long getNewID() { long micros = System.currentTimeMillis() * 1000; for ( ; ; ) { long value = TS.get(); if (micros <= value) micros = value + 1; if (TS.compareAndSet(value, micros)) return micros; } } public void addSubpileLink(Stockpile subpile) { subpileLinks.add(subpile); } public void removeSubpileLink(Stockpile subpile) { subpileLinks.remove(subpile); } public List getSubpileLinks() { return Collections.unmodifiableList(subpileLinks); } public Map getSubpiles() { return subpiles; } public List getSubpileItems() { return subpileAll; } public List getSubpileStocks() { return subpileStocks; } public List getSubpileTableItems() { if (Settings.get().isShowSubpileTree()) { return subpileAll; } else { return subpileItems; } } public void clearSubpileItems() { subpileAll.clear(); subpileItems.clear(); subpileStocks.clear(); } public void addSubpileItem(SubpileItem subpileItem) { subpileAll.add(subpileItem); subpileItems.add(subpileItem); } public void addSubpileStock(SubpileStock subpileStock) { subpileAll.add(subpileStock); subpileStocks.add(subpileStock); } private void createLocationName() { locationName = General.get().all(); for (StockpileFilter filter : filters) { //Update Location MyLocation location = ApiIdConverter.getLocation(filter.getLocation().getLocationID()); filter.setLocation(location); if (location != null && !location.isEmpty()) { //Not All if (filters.size() > 1) { locationName = TabsStockpile.get().multiple(); } else { locationName = location.getLocation(); } break; } } } private void createContainerName() { Set containers = new HashSet<>(); for (StockpileFilter filter : getFilters()) { for (StockpileContainer container : filter.getContainers()) { containers.add(container.getContainer()); } } if (containers.isEmpty()) { containerName = General.get().all(); } else if (containers.size() == 1) { for (String container : containers) { containerName = container; //first (and only) } } else { containerName = TabsStockpile.get().multiple(); } } private void createInclude() { if (getFilters().isEmpty()) { assets = true; jobs = true; buyOrders = true; sellOrders = true; transactions = true; buyTransactions = true; sellTransactions = true; contracts = true; buyingContracts = true; sellingContracts = true; boughtContracts = true; soldContracts = true; } else { assets = false; jobs = false; buyOrders = false; sellOrders = false; transactions = false; buyTransactions = false; sellTransactions = false; contracts = false; buyingContracts = false; sellingContracts = false; boughtContracts = false; soldContracts = false; } for (StockpileFilter filter : getFilters()) { if (filter.isAssets()) { assets = true; } if (filter.isBuyOrders()) { buyOrders = true; } if (filter.isSellOrders()) { sellOrders = true; } if (filter.isBuyTransactions()) { buyTransactions = true; transactions = true; } if (filter.isSellTransactions()) { sellTransactions = true; transactions = true; } if (filter.isJobs()) { jobs = true; } if (filter.isSellingContracts()) { sellingContracts = true; contracts = true; } if (filter.isSoldContracts()) { soldContracts = true; contracts = true; } if (filter.isBuyingContracts()) { contracts = true; buyingContracts = true; } if (filter.isBoughtContracts()) { contracts = true; boughtContracts = true; } } } public boolean isEmpty() { return (items.size() <= 1); } public boolean add(final StockpileItem item) { return items.add(item); } public void remove(final StockpileItem item) { if (items.contains(item)) { items.remove(item); } if (items.isEmpty()) { items.add(totalItem); } } public void reset() { for (StockpileItem item : items) { item.reset(); } } public String getName() { return name; } public double getMultiplier() { return multiplier; } public boolean isMatchAll() { return matchAll; } public boolean isAssets() { return assets; } public boolean isBuyOrders() { return buyOrders; } public boolean isSellOrders() { return sellOrders; } public boolean isTransactions() { return transactions; } public boolean isBuyTransactions() { return buyTransactions; } public boolean isSellTransactions() { return sellTransactions; } public boolean isJobs() { return jobs; } public boolean isContracts() { return contracts; } public boolean isSellingContracts() { return sellingContracts; } public boolean isSoldContracts() { return soldContracts; } public boolean isBuyingContracts() { return buyingContracts; } public boolean isBoughtContracts() { return boughtContracts; } public String getOwnerName() { return ownerName; } public void setMultiplier(double multiplier) { this.multiplier = multiplier; } public final void setOwnerName(final List ownerNames) { if (ownerNames.isEmpty()) { this.ownerName = General.get().all(); } else if (ownerNames.size() == 1) { this.ownerName = ownerNames.get(0); } else { this.ownerName = TabsStockpile.get().multiple(); } } public String getContainerName() { return containerName; } public String getFlagName() { return flagName; } public final void setFlagName(final Set flagNames) { if (flagNames.isEmpty()) { this.flagName = General.get().all(); } else if (flagNames.size() == 1) { this.flagName = flagNames.iterator().next().toString(); } else { this.flagName = TabsStockpile.get().multiple(); } } public Collection getItems() { return items; } public List getClaims() { return new ArrayList<>(getClaimsMap().values()); } public Map getClaimsMap() { Map map = new HashMap<>(); //Items for (StockpileItem item : items) { if (item.isTotal()) { continue; } map.put(item.getType(), item); } //SubpileItem (Overwrites StockpileItem items) for (SubpileItem item : subpileItems) { map.put(item.getType(), item); } return map; } @Override public Set getLocations() { Set locations = new HashSet<>(); for (StockpileFilter filter : filters) { if (!filter.getLocation().isEmpty()) { locations.add(filter.getLocation()); } } return locations; } @Override public Set getOwners() { Set owners = new HashSet<>(); for (StockpileFilter filter : filters) { if (!filter.getOwnerIDs().isEmpty()) { owners.addAll(filter.getOwnerIDs()); } } return owners; } public List getFilters() { return filters; } public String getLocationName() { return locationName; } public double getPercentFull() { return percentFull; } public void updateTotal() { totalItem.reset(); percentFull = Double.MAX_VALUE; //For each item type for (StockpileItem item : getClaims()) { if (item.isTotal()) { continue; //Ignore Total } percentFull = Math.min(item.getPercentNeeded(), percentFull); totalItem.updateTotal(item); } if (percentFull == Double.MAX_VALUE) { //Default value percentFull = 1; } } public StockpileTotal getTotal() { return totalItem; } @Override public String toString() { return getName(); } @Override public boolean equals(final Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Stockpile other = (Stockpile) obj; return !((this.name == null) ? (other.name != null) : !this.name.equals(other.name)); } @Override public int hashCode() { int hash = 5; hash = 71 * hash + (this.name != null ? this.name.hashCode() : 0); return hash; } public Stockpile deepClone() { return new Stockpile(this); } @Override public int compareTo(final Stockpile o) { return this.getName().compareToIgnoreCase(o.getName()); } public static class StockpileItem implements Comparable, LocationsType, ItemType, BlueprintType, PriceType, CopySeparator, TagsType, OwnersType, MarketDetailType { private static final AtomicLong TS = new AtomicLong(); //Constructor private final long id; private Stockpile stockpile; private Item item; private int typeID; private TypeIdentifier type; private double countMinimum; private boolean runs; private boolean ignoreMultiplier; //soft init protected JButton jButton; //Updated values private double price = 0.0; private double volume = 0.0f; private Double transactionAveragePrice; //can be null! private PriceData priceData = new PriceData(); //Dynamic values private Tags tags; //Updated counts private long inventoryCountNow = 0; private long sellOrdersCountNow = 0; private long buyOrdersCountNow = 0; private long jobsCountNow = 0; private long buyTransactionsCountNow = 0; private long sellTransactionsCountNow = 0; private long buyingContractsCountNow = 0; private long boughtContractsCountNow = 0; private long sellingContractsCountNow = 0; private long soldContractsCountNow = 0; public StockpileItem(final Stockpile stockpile, final StockpileItem stockpileItem) { this(stockpile, stockpileItem.item, stockpileItem.typeID, stockpileItem.countMinimum, stockpileItem.runs, stockpileItem.ignoreMultiplier ); } public StockpileItem(final Stockpile stockpile, final Item item, final int typeID, final double countMinimum, final boolean runs) { this(stockpile, item, typeID, countMinimum, runs, false, getNewID()); } public StockpileItem(final Stockpile stockpile, final Item item, final int typeID, final double countMinimum, final boolean runs, boolean ignoreMultiplier) { this(stockpile, item, typeID, countMinimum, runs, ignoreMultiplier, getNewID()); } public StockpileItem(final Stockpile stockpile, final Item item, final int typeID, final double countMinimum, final boolean runs, boolean ignoreMultiplier, final long id) { this.stockpile = stockpile; this.item = item; this.typeID = typeID; this.countMinimum = countMinimum; this.runs = runs; this.ignoreMultiplier = ignoreMultiplier; this.id = id; this.type = new TypeIdentifier(typeID, runs); } void update(StockpileItem stockpileItem) { this.stockpile = stockpileItem.stockpile; this.item = stockpileItem.item; this.typeID = stockpileItem.typeID; this.countMinimum = stockpileItem.countMinimum; this.runs = stockpileItem.runs; this.ignoreMultiplier = stockpileItem.ignoreMultiplier; this.type = new TypeIdentifier(typeID, runs); } @Override public JButton getButton() { if (jButton == null) { //Soft init jButton = new JButtonComparable(TabsStockpile.get().eveUiOpen()); } return jButton; } private void updateTags() { setTags(Settings.get().getTags(getTagID())); } public boolean isEditable() { return true; } public boolean isIgnoreMultiplier() { return ignoreMultiplier; } public void setIgnoreMultiplier(boolean ignoreMultiplier) { this.ignoreMultiplier = ignoreMultiplier; } private void reset() { inventoryCountNow = 0; sellOrdersCountNow = 0; buyOrdersCountNow = 0; jobsCountNow = 0; buyTransactionsCountNow = 0; sellTransactionsCountNow = 0; buyingContractsCountNow = 0; boughtContractsCountNow = 0; sellingContractsCountNow = 0; soldContractsCountNow = 0; price = 0.0; volume = 0.0f; } public void updateValues(final double updatePrice, final float updateVolume, Double transactionAveragePrice, PriceData priceData) { this.price = updatePrice; this.volume = updateVolume; this.transactionAveragePrice = transactionAveragePrice; this.priceData = priceData; } Long matches(Object object) { if (object instanceof MyAsset) { return matchesAsset((MyAsset) object, false); } else if (object instanceof MyMarketOrder) { return matchesMarketOrder((MyMarketOrder) object, false); } else if (object instanceof MyIndustryJob) { return matchesIndustryJob((MyIndustryJob) object, false); } else if (object instanceof MyTransaction) { return matchesTransaction((MyTransaction) object, false); } else if (object instanceof MyContractItem) { return matchesContract((MyContractItem) object, false); } return null; } boolean matchesAsset(MyAsset asset) { Long l = matchesAsset(asset, false); return l != null && l > 0; } void updateAsset(MyAsset asset) { matchesAsset(asset, true); } private Long matchesAsset(MyAsset asset, boolean add) { if (asset != null) { //better safe then sorry return matches(add, asset.isBPC() ? -asset.getTypeID() : asset.getTypeID(), asset.getOwnerID(), null, asset.getLocation(), asset, null, null, null, null); } else { return null; } } void updateMarketOrder(final MyMarketOrder marketOrder) { matchesMarketOrder(marketOrder, true); } private Long matchesMarketOrder(final MyMarketOrder marketOrder, boolean add) { if (marketOrder != null) { //better safe then sorry return matches(add, marketOrder.getTypeID(), marketOrder.getOwnerID(), null, marketOrder.getLocation(), null, marketOrder, null, null, null); } else { return null; } } void updateIndustryJob(final MyIndustryJob industryJob) { matchesIndustryJob(industryJob, true); } private Long matchesIndustryJob(final MyIndustryJob industryJob, boolean add) { if (industryJob != null) { //better safe then sorry Integer productTypeID = industryJob.getProductTypeID(); Long productCount = null; if (productTypeID != null) { productCount = matches(add, productTypeID, industryJob.getOwnerID(), null, industryJob.getLocation(), null, null, industryJob, null, null); } Long runsCount = matches(add, -industryJob.getBlueprintTypeID(), industryJob.getOwnerID(), null, industryJob.getLocation(), null, null, industryJob, null, null); if (productCount != null && runsCount != null) { return productCount + runsCount; } else if (productCount != null) { return productCount; } else { return runsCount; //May be null - that is okay } } else { return null; } } void updateTransaction(MyTransaction transaction) { matchesTransaction(transaction, true); } private Long matchesTransaction(MyTransaction transaction, boolean add) { if (transaction != null) { //better safe then sorry return matches(add, transaction.getTypeID(), transaction.getOwnerID(), null, transaction.getLocation(), null, null, null, transaction, null); } else { return null; } } boolean matchesContract(MyContractItem contractItem) { Long l = matchesContract(contractItem, false); return l != null && l > 0; } void updateContract(MyContractItem contractItem) { matchesContract(contractItem, true); } private Long matchesContract(MyContractItem contractItem, boolean add) { if (contractItem != null) { //better safe then sorry return matches(add, contractItem.isBPC() ? -contractItem.getTypeID() : contractItem.getTypeID(), contractItem.getContract().isForCorp() ? contractItem.getContract().getIssuerCorpID() : contractItem.getContract().getIssuerID(), null, contractItem.getContract().getLocations(), null, null, null, null, contractItem); } else { return null; } } private Long matches(final boolean add, final int typeID, final Long ownerID, final Integer flagID, final MyLocation location, final MyAsset asset, final MyMarketOrder marketOrder, final MyIndustryJob industryJob, final MyTransaction transaction, final MyContractItem contractItem) { return matches(add, typeID, ownerID, flagID, Collections.singleton(location), asset, marketOrder, industryJob, transaction, contractItem); } private Long matches(final boolean add, final int typeID, final Long ownerID, final Integer flagID, final Set locations, final MyAsset asset, final MyMarketOrder marketOrder, final MyIndustryJob industryJob, final MyTransaction transaction, final MyContractItem contractItem) { if (stockpile.getFilters().isEmpty()) { return null; //All } if (this.typeID != typeID) { return null; } //Put exclude filters first List filters = new ArrayList<>(stockpile.getFilters()); Collections.sort(filters, new Comparator() { @Override public int compare(StockpileFilter o1, StockpileFilter o2) { if (o1.isExclude() && o2.isExclude()) { return 0; //Equals } else if (o1.isExclude()) { return -1; //First } else if (o2.isExclude()) { return 1; //Last } else { return 0; //Equals } } }); //Try to match one of the filters for (StockpileFilter filter : filters) { //Owner if (contractItem != null) { long issuer = contractItem.getContract().isForCorp() ? contractItem.getContract().getIssuerCorpID() : contractItem.getContract().getIssuerID(); if (filter.isBoughtContracts() || filter.isBuyingContracts() || filter.isSellingContracts() || filter.isSellingContracts()) { if (!matchOwner(filter, issuer) && (contractItem.getContract().getAcceptorID() <= 0 || !matchOwner(filter, contractItem.getContract().getAcceptorID()))) { continue; //Do not match contract owner - try next filter } } } else if (industryJob != null) { if (!matchOwner(filter, ownerID) && !matchOwner(filter, industryJob.getInstallerID())) { continue; //Do not match owner - try next filter } } else { if (!matchOwner(filter, ownerID)) { continue; //Do not match owner - try next filter } } //Container if (!matchContainer(filter, asset)) { continue; //Do not match container - try next filter } //Flags if (asset != null) { if (!matchFlag(filter, asset)) { continue; //Do not match asset flag - try next filter } } else { if (!matchFlag(filter, flagID)) { continue; //Do not match flag - try next filter } } //Singleton if (asset != null && filter.isSingleton() != null && !filter.isSingleton().equals(asset.isSingleton())) { continue; //Do not match - try next filter } //Industry Jobs: must complete in less than X days if (!matchJobsDaysLess(industryJob, filter.getJobsDaysLess())) { continue; //Do not match - try next filter } //Industry Jobs: must complete in more than X days if (!matchJobsDaysMore(industryJob, filter.getJobsDaysMore())) { continue; //Do not match - try next filter } //Location if (!matchLocation(filter, locations)) { continue; //Do not match location - try next filter } //Exclude if (filter.isExclude()) { return null; //Match exclude filter AKA do not match any following filters } long count = 0; //Assets if (asset != null) { if (runs && typeID < 0) { //BPC Runs if (filter.isAssets() && asset.isBPC()) { if (add) { //Match inventoryCountNow = inventoryCountNow + asset.getRuns(); } else { count = count + asset.getRuns(); } } } else if (filter.isAssets()) { if (add) { //Match inventoryCountNow = inventoryCountNow + asset.getCount(); } else { count = count + asset.getCount(); } } else { continue; //Do not match - try next filter } //Jobs } else if (industryJob != null) { //Note: Industry jobs are also filtered for isNotDeliveredToAssets() in StockpileData.updateStockpileItems(Stockpile, boolean) if (typeID < 0) { //Copying in progress (not delivered to assets) if (filter.isJobs() && industryJob.isCopying() && industryJob.isNotDeliveredToAssets()) { if (runs) { //BPC Runs if (add) { //Match jobsCountNow = jobsCountNow + ((long)industryJob.getRuns() * (long)industryJob.getLicensedRuns()); } else { count = count + ((long)industryJob.getRuns() * (long)industryJob.getLicensedRuns()); } } else { //BPC if (add) { //Match jobsCountNow = jobsCountNow + (long)industryJob.getRuns(); } else { count = count + (long)industryJob.getRuns(); } } } //Manufacturing in progress (not delivered to assets) //Note: Industry jobs are also filtered for isNotDeliveredToAssets() in StockpileData.updateStockpileItems(Stockpile, boolean) } else if (filter.isJobs() && industryJob.isManufacturing() && industryJob.isNotDeliveredToAssets()) { if (add) { //Match jobsCountNow = jobsCountNow + ((long)industryJob.getRuns() * (long)industryJob.getProductQuantity()); } else { count = count + ((long)industryJob.getRuns() * (long)industryJob.getProductQuantity()); } } else { continue; //Do not match - try next filter } //Orders } else if (marketOrder != null) { if (runs && typeID < 0) { continue; //Ignore BPC runs (Can't sell BPC) } //Note: Market orders are also filtered for isActive() in StockpileData.updateStockpileItems(Stockpile, boolean) if (!marketOrder.isBuyOrder() && marketOrder.isActive() && filter.isSellOrders()) { if (add) { //Open/Active sell order - match sellOrdersCountNow = sellOrdersCountNow + marketOrder.getVolumeRemain(); } else { count = count + marketOrder.getVolumeRemain(); } //Note: Market orders are also filtered for isActive() in StockpileData.updateStockpileItems(Stockpile, boolean) } else if (marketOrder.isBuyOrder() && marketOrder.isActive() && filter.isBuyOrders()) { if (add) { //Open/Active buy order - match buyOrdersCountNow = buyOrdersCountNow + marketOrder.getVolumeRemain(); } else { count = count + marketOrder.getVolumeRemain(); } } else { continue; //Do not match - try next filter } //Transactions } else if (transaction != null) { if (runs && typeID < 0) { continue; //Ignore BPC runs (Can't sell BPC) } //Note: Transactions are also filter for isAfterAssets() in StockpileData.updateStockpileItems(Stockpile, boolean) if (transaction.isAfterAssets() && transaction.isBuy() && filter.isBuyTransactions()) { if (add) { //Buy - match buyTransactionsCountNow = buyTransactionsCountNow + transaction.getQuantity(); } else { count = count + transaction.getQuantity(); } //Note: Transactions are also filter for isAfterAssets() in StockpileData.updateStockpileItems(Stockpile, boolean) } else if (transaction.isAfterAssets() && transaction.isSell() && filter.isSellTransactions()) { if (add) { //Sell - match sellTransactionsCountNow = sellTransactionsCountNow - transaction.getQuantity(); } else { count = count + -transaction.getQuantity(); } } else { continue; //Do not match - try next filter } //Contracts } else if (contractItem != null) { if (runs && typeID < 0) { continue; //Ignore BPC runs (We don't have blueprint info for contracts - yet) } boolean found = false; //Get issuer long issuer = contractItem.getContract().isForCorp() ? contractItem.getContract().getIssuerCorpID() : contractItem.getContract().getIssuerID(); //Only match owners once boolean isIssuer = matchOwner(filter, issuer); boolean isAcceptor = contractItem.getContract().getAcceptorID() > 0 && matchOwner(filter, contractItem.getContract().getAcceptorID()); //Sell: Issuer Included or Acceptor Excluded if ((isIssuer && contractItem.isIncluded()) || (isAcceptor && !contractItem.isIncluded())) { //Note: Contract items are also filter for isOpen() in StockpileData.updateStockpileItems(Stockpile, boolean) if (contractItem.getContract().isOpen() && filter.isSellingContracts()) { if (add) { //Selling sellingContractsCountNow = sellingContractsCountNow + contractItem.getQuantity(); } else { count = count + contractItem.getQuantity(); } found = true; //Note: Contract items are also filter for isCompletedSuccessful() in StockpileData.updateStockpileItems(Stockpile, boolean) } else if (contractItem.getContract().isCompletedSuccessful() && filter.isSoldContracts()) { //Sold if ((isIssuer && contractItem.getContract().isIssuerAfterAssets()) || isAcceptor && contractItem.getContract().isAcceptorAfterAssets()) { if (add) { soldContractsCountNow = soldContractsCountNow - contractItem.getQuantity(); } else { count = count + -contractItem.getQuantity(); } found = true; } } } //Buy: Issuer Excluded or Acceptor Included if ((isIssuer && !contractItem.isIncluded()) || (isAcceptor && contractItem.isIncluded())) { //Note: Contract items are also filter for isOpen() in StockpileData.updateStockpileItems(Stockpile, boolean) if (contractItem.getContract().isOpen() && filter.isBuyingContracts()) { if (add) { //Buying buyingContractsCountNow = buyingContractsCountNow + contractItem.getQuantity(); } else { count = count + contractItem.getQuantity(); } found = true; //Note: Contract items are also filter for isCompletedSuccessful() in StockpileData.updateStockpileItems(Stockpile, boolean) } else if (contractItem.getContract().isCompletedSuccessful() && filter.isBoughtContracts()) { //Bought if ((isIssuer && contractItem.getContract().isIssuerAfterAssets()) || isAcceptor && contractItem.getContract().isAcceptorAfterAssets()) { if (add) { boughtContractsCountNow = boughtContractsCountNow + contractItem.getQuantity(); } else { count = count + contractItem.getQuantity(); } found = true; } } } if (!found) { continue; //Do not match - try next filter } } return count; //Filter matched - Items added } return null; //Nothing matched, nothing added } private boolean matchOwner(final StockpileFilter filter, final Long ownerID) { if (ownerID == null) { return true; } if (filter.getOwnerIDs().isEmpty()) { return true; //All } for (Long stockpileOwnerID : filter.getOwnerIDs()) { if (stockpileOwnerID.equals(ownerID)) { //Match return true; } } return false; //No match } private boolean matchContainer(final StockpileFilter filter, final MyAsset asset) { if (asset == null) { return true; } if (filter.getContainers().isEmpty()) { return true; //All } //Build include container String String container = asset.getContainer().toLowerCase(); for (StockpileContainer stockpileContainer : filter.getContainers()) { if (container.endsWith(stockpileContainer.getCompare())) { //Match return true; } if (stockpileContainer.isIncludeSubs() && container.contains(stockpileContainer.getCompare())) { return true; } } return false; //No match } private boolean matchFlag(final StockpileFilter filter, final Integer flagID) { if (flagID == null) { return true; } if (filter.getFlags().isEmpty()) { return true; //All } for (StockpileFlag flag : filter.getFlags()) { if (flagID.equals(flag.getFlagID())) { //Match return true; } } return false; //No match } private boolean matchFlag(final StockpileFilter filter, final MyAsset asset) { if (asset == null) { return true; } if (filter.getFlags().isEmpty()) { return true; //All } for (StockpileFlag flag : filter.getFlags()) { if (asset.getFlagID() == flag.getFlagID()) { //Match self return true; } if (flag.isIncludeSubs()) { for (MyAsset parentAsset : asset.getParents()) { //Test parents if (parentAsset.getFlagID() == flag.getFlagID()) { //Match parent return true; } } } } return false; //No match } private boolean matchLocation(final StockpileFilter filter, final Collection locations) { MyLocation stockpileLocation = filter.getLocation(); for (MyLocation location : locations) { if (filter.getLocation().isEmpty()) { return true; //Nothing selected - always match (Univers/Galaxy) } if (stockpileLocation.getLocation().equals(location.getStation())) { return true; } if (stockpileLocation.getLocation().equals(location.getSystem())) { return true; } if (stockpileLocation.getLocation().equals(location.getConstellation())) { return true; } if (stockpileLocation.getLocation().equals(location.getRegion())) { return true; } } return false; } private boolean matchJobsDaysLess(final MyIndustryJob industryJob, Integer jobsDays) { if (jobsDays == null || industryJob == null || industryJob.getEndDate() == null) { return true; } CALENDAR.setTime(new Date()); CALENDAR.set(Calendar.HOUR_OF_DAY, 23); //Less than -> End of day -> OK CALENDAR.set(Calendar.MINUTE, 59); CALENDAR.set(Calendar.SECOND, 59); CALENDAR.set(Calendar.MILLISECOND, 999); CALENDAR.add(Calendar.DAY_OF_MONTH, jobsDays); return industryJob.getEndDate().before(CALENDAR.getTime()); //End before X days } private boolean matchJobsDaysMore(final MyIndustryJob industryJob, Integer jobsDays) { if (jobsDays == null || industryJob == null || industryJob.getEndDate() == null) { return true; } CALENDAR.setTime(new Date()); CALENDAR.set(Calendar.HOUR_OF_DAY, 0); //More than -> Start of day -> OK CALENDAR.set(Calendar.MINUTE, 0); CALENDAR.set(Calendar.SECOND, 0); CALENDAR.set(Calendar.MILLISECOND, 0); CALENDAR.add(Calendar.DAY_OF_MONTH, jobsDays); return industryJob.getEndDate().after(CALENDAR.getTime()); //End after X days } public void setCountMinimum(final double countMinimum) { this.countMinimum = countMinimum; this.getStockpile().updateTotal(); } public void addCountMinimum(final double countMinimum) { this.countMinimum = this.countMinimum + countMinimum; this.getStockpile().updateTotal(); } public String getSeparator() { String group = getGroup(); if (group.isEmpty() || Settings.get().getStockpileGroupSettings().isGroupExpanded(group)) { return group + "\r\n" + stockpile.getName().toLowerCase() + "\r\n" + stockpile.getName(); //Sort lower case, but unique by case } else { //Collapsed Group (everything in a single group) return group + "\r\n"; } } public boolean isGroupCollapsed(boolean expand) { String group = getGroup(); return !Settings.get().getStockpileGroupSettings().isGroupExpanded(group); } public String getGroup() { return Settings.get().getStockpileGroupSettings().getGroup(stockpile); } public Stockpile getStockpile() { return stockpile; } public void setRuns(boolean runs) { this.runs = runs; } public boolean isRuns() { return runs; } @Override public boolean isBPC() { return (typeID < 0); } @Override public boolean isBPO() { return isBlueprint() && !isBPC(); } @Override public int getRuns() { return -1; } @Override public int getMaterialEfficiency() { return 0; } @Override public int getTimeEfficiency() { return 0; } public boolean isBlueprint() { return item.isBlueprint(); } public String getName() { if (isBPC()) { //Blueprint copy if (runs) { return item.getTypeName() + " (Runs)"; } else { return item.getTypeName() + " (BPC)"; } } else if (isBPO()) { //Blueprint original return item.getTypeName() + " (BPO)"; } else { //Everything else return item.getTypeName(); } } public double getCountMinimum() { return countMinimum; } public long getCountMinimumMultiplied() { if (isIgnoreMultiplier()) { return (long) Math.ceil(countMinimum); } else { return (long) Math.ceil(stockpile.getMultiplier() * countMinimum); } } public long getCountNow() { return inventoryCountNow + buyOrdersCountNow + sellOrdersCountNow + jobsCountNow + buyTransactionsCountNow + sellTransactionsCountNow + buyingContractsCountNow + boughtContractsCountNow + sellingContractsCountNow + soldContractsCountNow ; } public double getPercentNeeded() { long countNow = getCountNow(); long countMinimumMultiplied = getCountMinimumMultiplied(); if (countMinimumMultiplied == 0) { return 100; } else if (countNow == 0) { return 0; } else { return countNow / (double) countMinimumMultiplied; } } public long getInventoryCountNow() { return inventoryCountNow; } public long getBuyOrdersCountNow() { return buyOrdersCountNow; } public long getSellOrdersCountNow() { return sellOrdersCountNow; } public long getJobsCountNow() { return jobsCountNow; } public long getBuyTransactionsCountNow() { return buyTransactionsCountNow; } public long getSellTransactionsCountNow() { return sellTransactionsCountNow; } public long getBuyingContractsCountNow() { return buyingContractsCountNow; } public long getBoughtContractsCountNow() { return boughtContractsCountNow; } public long getSellingContractsCountNow() { return sellingContractsCountNow; } public long getSoldContractsCountNow() { return soldContractsCountNow; } public long getCountNeeded() { return getCountNow() - getCountMinimumMultiplied(); } @Override public Double getDynamicPrice() { return price; } public double getPriceBuyMax() { return priceData.getBuyMax(); } public double getPriceSellMin() { return priceData.getSellMin(); } public Double getTransactionAveragePrice() { return transactionAveragePrice; } public TypeIdentifier getType() { return type; } public int getItemTypeID() { return typeID; } @Override public Integer getTypeID() { return Math.abs(typeID); } public boolean isTotal() { return typeID == 0; } public double getVolume() { if (runs) { return 0.0; } else { return volume; } } public double getValueNow() { return getCountNow() * price; } public double getValueNeeded() { return getCountNeeded() * price; } public double getVolumeNow() { return getCountNow() * getVolume(); } public double getVolumeNeeded() { return getCountNeeded() * getVolume(); } public long getID() { return id; } public Integer getMeta() { return item.getMeta(); } public static long getNewID() { long micros = System.currentTimeMillis() * 1000; for ( ; ; ) { long value = TS.get(); if (micros <= value) micros = value + 1; if (TS.compareAndSet(value, micros)) return micros; } } @Override public Tags getTags() { return tags; } @Override public void setTags(Tags tags) { this.tags = tags; } @Override public TagID getTagID() { return new TagID(StockpileTab.NAME, getID()); } @Override public Item getItem() { return item; } @Override public long getItemCount() { return getCountNeeded(); } @Override public Set getLocations() { return stockpile.getLocations(); } @Override public Set getOwners() { return stockpile.getOwners(); } @Override public String getCopyString() { StringBuilder builder = new StringBuilder(); builder.append(getStockpile().getName()); builder.append("\t"); builder.append(getStockpile().getOwnerName()); builder.append("\t"); builder.append(getStockpile().getLocationName()); return builder.toString(); } @Override public String toString() { return getName(); } @Override public int hashCode() { int hash = 5; hash = 97 * hash + Objects.hashCode(this.stockpile); hash = 97 * hash + this.typeID; hash = 97 * hash + (this.runs ? 1 : 0); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final StockpileItem other = (StockpileItem) obj; if (this.typeID != other.typeID) { return false; } if (this.runs != other.runs) { return false; } if (!Objects.equals(this.stockpile, other.stockpile)) { return false; } return true; } @Override public int compareTo(final StockpileItem item) { //Compare groups int value = getItem().getGroup().compareToIgnoreCase(item.getItem().getGroup()); if (value != 0) { //Not same group return value; } else { //Same group - compare names return this.getName().compareToIgnoreCase(item.getName()); } } } public static class StockpileTotal extends StockpileItem { private long inventoryCountNow = 0; private long sellOrdersCountNow = 0; private long buyOrdersCountNow = 0; private long jobsCountNow = 0; private long buyTransactionsCountNow = 0; private long sellTransactionsCountNow = 0; private long buyingContractsCountNow = 0; private long boughtContractsCountNow = 0; private long sellingContractsCountNow = 0; private long soldContractsCountNow = 0; private long countNeeded = 0; private double countMinimum = 0; private long countMinimumMultiplied = 0; private double totalPrice; private double totalPriceSellMin; private double totalPriceBuyMax; private double totalPriceCount; private double valueNow = 0; private double valueNeeded = 0; private double volumeNow = 0; private double volumeNeeded = 0; public StockpileTotal(final Stockpile stockpile) { super(stockpile, new Item(0), 0, 0, false, false, 0); } private void reset() { inventoryCountNow = 0; sellOrdersCountNow = 0; buyOrdersCountNow = 0; jobsCountNow = 0; countNeeded = 0; countMinimum = 0; totalPrice = 0; totalPriceSellMin = 0; totalPriceBuyMax = 0; totalPriceCount = 0; valueNow = 0; valueNeeded = 0; volumeNow = 0; volumeNeeded = 0; countMinimumMultiplied = 0; buyTransactionsCountNow = 0; sellTransactionsCountNow = 0; buyingContractsCountNow = 0; boughtContractsCountNow = 0; sellingContractsCountNow = 0; soldContractsCountNow = 0; } private void updateTotal(final StockpileItem item) { //Assets inventoryCountNow = inventoryCountNow + item.getInventoryCountNow(); //Market Orders sellOrdersCountNow = sellOrdersCountNow + item.getSellOrdersCountNow(); //Buy Order buyOrdersCountNow = buyOrdersCountNow + item.getBuyOrdersCountNow(); //Jobs jobsCountNow = jobsCountNow + item.getJobsCountNow(); //Transactions buyTransactionsCountNow = buyTransactionsCountNow + item.getBuyTransactionsCountNow(); sellTransactionsCountNow = sellTransactionsCountNow + item.getSellTransactionsCountNow(); //Contracts buyingContractsCountNow = buyingContractsCountNow + item.getBuyingContractsCountNow(); boughtContractsCountNow = boughtContractsCountNow + item.getBoughtContractsCountNow(); sellingContractsCountNow = sellingContractsCountNow + item.getSellingContractsCountNow(); soldContractsCountNow = soldContractsCountNow + item.getSoldContractsCountNow(); //Only add if negative if (item.getCountNeeded() < 0) { countNeeded = countNeeded + item.getCountNeeded(); } countMinimum = countMinimum + item.getCountMinimum(); countMinimumMultiplied = countMinimumMultiplied + item.getCountMinimumMultiplied(); totalPrice = totalPrice + item.getDynamicPrice(); totalPriceSellMin = totalPriceSellMin + item.getPriceSellMin(); totalPriceBuyMax = totalPriceBuyMax + item.getPriceBuyMax(); totalPriceCount++; valueNow = valueNow + item.getValueNow(); //Only add if negative if (item.getValueNeeded() < 0) { valueNeeded = valueNeeded + item.getValueNeeded(); } volumeNow = volumeNow + item.getVolumeNow(); //Only add if negative if (item.getVolumeNeeded() < 0) { volumeNeeded = volumeNeeded + item.getVolumeNeeded(); } } @Override public JButton getButton() { if (jButton == null) { //Soft init jButton = new JButtonNull(); } return jButton; } @Override public void setTags(Tags tags) { } @Override public Tags getTags() { return null; } @Override public String getName() { return TabsStockpile.get().totalStockpile(); } @Override public boolean isEditable() { return false; } @Override public double getCountMinimum() { return countMinimum; } @Override public long getCountMinimumMultiplied() { return countMinimumMultiplied; } @Override public long getCountNeeded() { return countNeeded; } @Override public long getCountNow() { return inventoryCountNow + buyOrdersCountNow + sellOrdersCountNow + jobsCountNow + buyTransactionsCountNow + sellTransactionsCountNow + buyingContractsCountNow + boughtContractsCountNow + sellingContractsCountNow + soldContractsCountNow ; } @Override public long getInventoryCountNow() { return inventoryCountNow; } @Override public long getBuyOrdersCountNow() { return buyOrdersCountNow; } @Override public long getJobsCountNow() { return jobsCountNow; } @Override public long getSellOrdersCountNow() { return sellOrdersCountNow; } @Override public long getSoldContractsCountNow() { return soldContractsCountNow; } @Override public long getSellingContractsCountNow() { return sellingContractsCountNow; } @Override public long getBoughtContractsCountNow() { return boughtContractsCountNow; } @Override public long getBuyingContractsCountNow() { return buyingContractsCountNow; } @Override public long getSellTransactionsCountNow() { return sellTransactionsCountNow; } @Override public long getBuyTransactionsCountNow() { return buyTransactionsCountNow; } @Override public Double getDynamicPrice() { if (totalPriceCount <= 0 || totalPrice <= 0) { return 0.0; } else { return totalPrice / totalPriceCount; } } @Override public double getPriceSellMin() { if (totalPriceCount <= 0 || totalPriceSellMin <= 0) { return 0.0; } else { return totalPriceSellMin / totalPriceCount; } } @Override public double getPriceBuyMax() { if (totalPriceCount <= 0 || totalPriceBuyMax <= 0) { return 0.0; } else { return totalPriceBuyMax / totalPriceCount; } } @Override public double getValueNeeded() { return valueNeeded; } @Override public double getValueNow() { return valueNow; } @Override public double getVolumeNeeded() { return volumeNeeded; } @Override public double getVolumeNow() { return volumeNow; } @Override public double getPercentNeeded() { return getStockpile().getPercentFull(); } @Override public Integer getMeta() { return null; } } public static class StockpileFilter { private MyLocation location; private final boolean exclude; private final List flags; private final List containers; private final List ownerIDs; private final Integer jobsDaysLess; private final Integer jobsDaysMore; private final Boolean singleton; private final boolean assets; private final boolean sellOrders; private final boolean buyOrders; private final boolean buyTransactions; private final boolean sellTransactions; private final boolean jobs; private final boolean sellingContracts; private final boolean soldContracts; private final boolean buyingContracts; private final boolean boughtContracts; public StockpileFilter(MyLocation location, boolean exclude, List flags, List containers, List ownerIDs, Integer jobsDaysLess, Integer jobsDaysMore, Boolean singleton, boolean assets, boolean sellOrders, boolean buyOrders, boolean jobs, boolean buyTransactions, boolean sellTransactions, boolean sellingContracts, boolean soldContracts, boolean buyingContracts, boolean boughtContracts) { this.location = location; this.exclude = exclude; this.flags = flags; this.containers = containers; this.ownerIDs = ownerIDs; this.jobsDaysLess = jobsDaysLess; this.jobsDaysMore = jobsDaysMore; this.singleton = singleton; this.assets = assets; this.sellOrders = sellOrders; this.buyOrders = buyOrders; this.jobs = jobs; this.buyTransactions = buyTransactions; this.sellTransactions = sellTransactions; this.sellingContracts = sellingContracts; this.soldContracts = soldContracts; this.buyingContracts = buyingContracts; this.boughtContracts = boughtContracts; } public MyLocation getLocation() { return location; } private void setLocation(MyLocation location) { this.location = location; } public boolean isExclude() { return exclude; } public List getFlags() { return flags; } public List getContainers() { return containers; } public List getOwnerIDs() { return ownerIDs; } public Integer getJobsDaysLess() { return jobsDaysLess; } public Integer getJobsDaysMore() { return jobsDaysMore; } public Boolean isSingleton() { return singleton; } public boolean isAssets() { return assets; } public boolean isSellOrders() { return sellOrders; } public boolean isBuyOrders() { return buyOrders; } public boolean isBuyTransactions() { return buyTransactions; } public boolean isSellTransactions() { return sellTransactions; } public boolean isJobs() { return jobs; } public boolean isSellingContracts() { return sellingContracts; } public boolean isSoldContracts() { return soldContracts; } public boolean isBuyingContracts() { return buyingContracts; } public boolean isBoughtContracts() { return boughtContracts; } public static class StockpileContainer { private final String container; private final String compare; private final boolean includeSubs; public StockpileContainer(String container, boolean includeSubs) { this.container = container; this.compare = container.toLowerCase(); this.includeSubs = includeSubs; } public String getContainer() { return container; } public String getCompare() { return compare; } public boolean isIncludeSubs() { return includeSubs; } @Override public int hashCode() { int hash = 7; hash = 37 * hash + Objects.hashCode(this.container); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final StockpileContainer other = (StockpileContainer) obj; if (!Objects.equals(this.container, other.container)) { return false; } return true; } } public static class StockpileFlag { private final int flagID; private final boolean includeSubs; public StockpileFlag(int flagID, boolean includeSubs) { this.flagID = flagID; this.includeSubs = includeSubs; } public int getFlagID() { return flagID; } public boolean isIncludeSubs() { return includeSubs; } @Override public int hashCode() { int hash = 7; hash = 43 * hash + this.flagID; return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final StockpileFlag other = (StockpileFlag) obj; return this.flagID == other.flagID; } } } public static class SubpileItem extends StockpileItem { private final List itemLinks = new ArrayList<>(); private String path; private String name = ""; private String space = ""; private int level; public SubpileItem(Stockpile stockpile, StockpileItem parentItem, SubpileStock subpileStock, int level, String path) { super(stockpile, parentItem.getItem(), parentItem.getItemTypeID(), parentItem.getCountMinimum(), parentItem.isRuns(), false); itemLinks.add(new SubpileItemLinks(parentItem, subpileStock)); setLevel(level); this.path = path; updateText(); } private SubpileItem(Stockpile stockpile, int level, String path) { super(stockpile, new Item(0, "!"+0, "Stockpile", "", 0, 0, 0, 0, 0, "", false, 0, 0, 1, "", "", null), 0, 0.0, false); setLevel(level); this.path = path; updateText(); } String getPath() { return path; } public void setPath(String path) { this.path = path; } public int getLevel() { return level; } public final void setLevel(int level) { this.level = level; StringBuilder spaceString = new StringBuilder(); for (int i = 0; i < level; i++) { spaceString.append(" "); } space = spaceString.toString(); } private String getSpace() { return space; } private void updateText() { if (!itemLinks.isEmpty()) { name = itemLinks.get(0).getStockpileItem().getName().trim(); } else { name = ""; } } public String getOrder() { return "1"; } public void addItemLink(StockpileItem parentItem, SubpileStock subpileStock) { itemLinks.add(new SubpileItemLinks(parentItem, subpileStock)); updateText(); } public void clearItemLinks() { itemLinks.clear(); } @Override public boolean isEditable() { return false; } @Override public String getName() { return "Total: " + name; //return getSpace() + " - " + name + " Total"; } @Override public double getCountMinimum() { double countMinimum = 0; for (SubpileItemLinks link : itemLinks) { SubpileStock stock = link.getSubpileStock(); StockpileItem item = link.getStockpileItem(); if (item.isIgnoreMultiplier() || stock == null) { countMinimum = countMinimum + item.getCountMinimum(); } else { countMinimum = countMinimum + (item.getCountMinimum() * stock.getSubMultiplier()); } } return countMinimum; } @Override public long getCountMinimumMultiplied() { double countMinimum = 0; for (SubpileItemLinks link : itemLinks) { SubpileStock stock = link.getSubpileStock(); StockpileItem item = link.getStockpileItem(); if (item.isIgnoreMultiplier()) { countMinimum = countMinimum + item.getCountMinimum(); } else if (stock != null) { countMinimum = countMinimum + (item.getCountMinimum() * stock.getSubMultiplier() * getStockpile().getMultiplier()); } else { countMinimum = countMinimum + (item.getCountMinimum() * getStockpile().getMultiplier()); } } return (long) Math.ceil(countMinimum); } private static class SubpileItemLinks { private final StockpileItem stockpileItem; private final SubpileStock subpileStock; public SubpileItemLinks(StockpileItem stockpileItem, SubpileStock subpileStock) { this.stockpileItem = stockpileItem; this.subpileStock = subpileStock; } public StockpileItem getStockpileItem() { return stockpileItem; } public SubpileStock getSubpileStock() { return subpileStock; } } } public static class SubpileStock extends SubpileItem { private final Stockpile originalStockpile; private final Stockpile originalParentStockpile; private final SubpileStock parentStock; private double subMultiplier; public SubpileStock(Stockpile stockpile, Stockpile originalStockpile, Stockpile originalParentStockpile, SubpileStock parentStock, double subMultiplier, int level, String path) { super(stockpile, level, path); this.originalStockpile = originalStockpile; this.originalParentStockpile = originalParentStockpile; this.parentStock = parentStock; this.subMultiplier = subMultiplier; } @Override public JButton getButton() { if (jButton == null) { //Soft init jButton = new JButtonNull(); } return jButton; } @Override public String getOrder() { return "0" + getPath(); } @Override public String getName() { return super.getSpace() + originalStockpile.getName(); } public double getSubMultiplier() { Double value = originalParentStockpile.getSubpiles().get(originalStockpile); if (value != null && parentStock != null) { return value * parentStock.getSubMultiplier(); } else if (value != null) { return value; } else { return subMultiplier; } } @Override public boolean isEditable() { return parentStock == null; } @Override public double getCountMinimum() { return getSubMultiplier(); } @Override public void setCountMinimum(double subMultiplier) { this.subMultiplier = subMultiplier; getStockpile().getSubpiles().put(originalStockpile, subMultiplier); getStockpile().updateTotal(); } @Override public long getCountNow() { return 0; } @Override public long getCountNeeded() { return 0; } @Override public double getValueNow() { return 0; }; @Override public double getValueNeeded() { return 0; }; @Override public double getVolumeNow() { return 0; }; @Override public double getVolumeNeeded() { return 0; }; } public static class TypeIdentifier { private final int typeID; private final boolean runs; public TypeIdentifier(StockpileItem stockpileItem) { this.typeID = stockpileItem.typeID; this.runs = stockpileItem.isRuns(); } public TypeIdentifier(int typeID, boolean runs) { this.typeID = typeID; this.runs = runs; } public boolean isEmpty() { return typeID == 0; } public boolean isBPC() { return typeID < 0; } public boolean isRuns() { return runs; } public int getTypeID() { return typeID; } @Override public int hashCode() { int hash = 7; hash = 59 * hash + this.typeID; hash = 59 * hash + (this.runs ? 1 : 0); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final TypeIdentifier other = (TypeIdentifier) obj; if (this.typeID != other.typeID) { return false; } if (this.runs != other.runs) { return false; } return true; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/stockpile/StockpileBpDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.stockpile; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import javax.swing.DefaultComboBoxModel; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingFacility; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingRigs; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingSecurity; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.i18n.TabsStockpile; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class StockpileBpDialog extends JDialogCentered { private enum StockpileBpAction { CANCEL, OK, TYPE_CHANGE } private static final int WIDTH = 200; private final JButton jOK; private final JLabel jBlueprintTypeLabel; private final JComboBox jBlueprintType; private final JComboBox jMe; private final JComboBox jFacility; private final JComboBox jRigs; private final JComboBox jSecurity; private final List manufacturingComponents = new ArrayList<>(); private BpData returnValue; public StockpileBpDialog(Program program) { super(program, "", Images.TOOL_STOCKPILE.getImage()); ListenerClass listener = new ListenerClass(); jBlueprintTypeLabel = new JLabel(); jBlueprintType = new JComboBox<>(); jBlueprintType.setActionCommand(StockpileBpAction.TYPE_CHANGE.name()); jBlueprintType.addActionListener(listener); JLabel jMeLabel = new JLabel(TabsStockpile.get().me()); manufacturingComponents.add(jMeLabel); Integer[] me = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; jMe = new JComboBox<>(me); jMe.setPrototypeDisplayValue(10); jMe.setMaximumRowCount(me.length); manufacturingComponents.add(jMe); JLabel jFacilityLabel = new JLabel(TabsStockpile.get().blueprintFacility()); manufacturingComponents.add(jFacilityLabel); jFacility = new JComboBox<>(ManufacturingFacility.values()); jFacility.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ManufacturingFacility facility = jFacility.getItemAt(jFacility.getSelectedIndex()); if (facility == ManufacturingFacility.STATION) { jRigs.setSelectedIndex(0); jRigs.setEnabled(false); } else { jRigs.setEnabled(true); } } }); manufacturingComponents.add(jFacility); JLabel jRigsLabel = new JLabel(TabsStockpile.get().blueprintRigs()); manufacturingComponents.add(jRigsLabel); jRigs = new JComboBox<>(ManufacturingRigs.values()); jRigs.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ManufacturingRigs rigs = jRigs.getItemAt(jRigs.getSelectedIndex()); if (rigs == ManufacturingRigs.NONE) { jSecurity.setSelectedIndex(0); jSecurity.setEnabled(false); } else { jSecurity.setEnabled(true); } } }); manufacturingComponents.add(jRigs); JLabel jSecurityLabel = new JLabel(TabsStockpile.get().blueprintSecurity()); manufacturingComponents.add(jSecurityLabel); jSecurity = new JComboBox<>(ManufacturingSecurity.values()); manufacturingComponents.add(jSecurity); jOK = new JButton(TabsStockpile.get().ok()); jOK.setActionCommand(StockpileBpAction.OK.name()); jOK.addActionListener(listener); JButton jCancel = new JButton(TabsStockpile.get().cancel()); jCancel.setActionCommand(StockpileBpAction.CANCEL.name()); jCancel.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addGroup(layout.createParallelGroup() .addComponent(jBlueprintTypeLabel, WIDTH, WIDTH, WIDTH) .addComponent(jBlueprintType, WIDTH, WIDTH, WIDTH) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jMeLabel) .addComponent(jFacilityLabel) .addComponent(jRigsLabel) .addComponent(jSecurityLabel) ) .addGroup(layout.createParallelGroup() .addComponent(jMe) .addComponent(jFacility) .addComponent(jRigs) .addComponent(jSecurity) ) ) ) .addGroup(layout.createSequentialGroup() .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jBlueprintTypeLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGap(0) .addComponent(jBlueprintType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup() .addComponent(jMeLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jMe, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jFacilityLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFacility, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jRigsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRigs, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jSecurityLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSecurity, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } public BpData show(String title, String msg, String[] options) { returnValue = null; jBlueprintTypeLabel.setText(msg); getDialog().setTitle(title); jBlueprintType.setModel(new DefaultComboBoxModel<>(options)); jBlueprintType.setSelectedIndex(0); jMe.setSelectedIndex(0); jFacility.setSelectedIndex(0); jRigs.setSelectedIndex(0); setVisible(true); return returnValue; } @Override protected JComponent getDefaultFocus() { return jBlueprintType; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { } @Override protected void save() { String type = jBlueprintType.getItemAt(jBlueprintType.getSelectedIndex()); if (type.equals(TabsStockpile.get().materialsManufacturing()) || type.equals(TabsStockpile.get().materialsReaction())) { int me = jMe.getItemAt(jMe.getSelectedIndex()); ManufacturingFacility facility = jFacility.getItemAt(jFacility.getSelectedIndex()); ManufacturingRigs rigs = jRigs.getItemAt(jRigs.getSelectedIndex()); ManufacturingSecurity security = jSecurity.getItemAt(jSecurity.getSelectedIndex()); returnValue = new BpData(type, me, facility, rigs, security); } else { returnValue = new BpData(type); } setVisible(false); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (StockpileBpAction.OK.name().equals(e.getActionCommand())) { save(); } else if (StockpileBpAction.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); } else if (StockpileBpAction.TYPE_CHANGE.name().equals(e.getActionCommand())) { String type = jBlueprintType.getItemAt(jBlueprintType.getSelectedIndex()); if (type.equals(TabsStockpile.get().materialsManufacturing()) || type.equals(TabsStockpile.get().materialsReaction())) { for (JComponent jComponent : manufacturingComponents) { jComponent.setVisible(true); } getDialog().pack(); } else { for (JComponent jComponent : manufacturingComponents) { jComponent.setVisible(false); } getDialog().pack(); } } } } public static class BpData { private final String type; private final Integer me; private final ManufacturingFacility facility; private final ManufacturingRigs rigs; private final ManufacturingSecurity security; public BpData(String type) { this.type = type; this.me = null; this.facility = null; this.rigs = null; this.security = null; } public BpData(String type, Integer me, ManufacturingFacility facility, ManufacturingRigs rigs, ManufacturingSecurity security) { this.type = type; this.me = me; this.facility = facility; this.rigs = rigs; this.security = security; } public boolean matches(String value) { return type.equals(value); } public double doMath(int quantity, double countMinimum) { return ApiIdConverter.getManufacturingQuantity(quantity, me, facility, rigs, security, countMinimum, false); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/stockpile/StockpileData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.stockpile; import ca.odell.glazedlists.EventList; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.profile.TableData; import net.nikr.eve.jeveasset.data.sde.ItemFlag; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.PriceData; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileFlag; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.SubpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.SubpileStock; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.TypeIdentifier; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class StockpileData extends TableData { private Map ownersName; private final Map>> contractItems = new HashMap<>(); private final Map>> assets = new HashMap<>(); private final Map> marketOrders = new HashMap<>(); private final Map> industryJobs = new HashMap<>(); private final Map> transactions = new HashMap<>(); public StockpileData(Program program) { super(program); } public StockpileData(ProfileManager profileManager, ProfileData profileData) { super(profileManager, profileData); } public EventList getData() { EventList eventList = EventListManager.create(); updateData(eventList); return eventList; } public void updateData(EventList eventList) { //Items List stockpileItems = new ArrayList<>(); updateOwners(); contractItems.clear(); assets.clear(); marketOrders.clear(); industryJobs.clear(); transactions.clear(); //Update Stockpiles (StockpileItem) for (Stockpile stockpile : StockpileTab.getShownStockpiles(profileManager)) { stockpile.updateDynamicValues(); updateStockpile(stockpile); stockpileItems.addAll(stockpile.getItems()); } //Update Subpiles (SubpileItem) stockpileItems.addAll(getUpdatedSubpiles()); //Update EventList (GUI) try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); StockpileTab.enableGroupFirstUpdate(); eventList.addAll(stockpileItems); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } public void updateOwners() { //Owners Look-Up ownersName = new HashMap<>(); for (OwnerType owner : profileManager.getOwnerTypes()) { ownersName.put(owner.getOwnerID(), owner.getOwnerName()); } } public void updateStockpile(Stockpile stockpile) { //Update owner name Set owners = new HashSet<>(); for (StockpileFilter filter : stockpile.getFilters()) { for (Long ownerID : filter.getOwnerIDs()) { String owner = ownersName.get(ownerID); if (owner != null) { owners.add(owner); } } } stockpile.setOwnerName(new ArrayList<>(owners)); //Update Item flag name Set flags = new HashSet<>(); for (StockpileFilter filter : stockpile.getFilters()) { for (StockpileFlag flag : filter.getFlags()) { ItemFlag itemFlag = StaticData.get().getItemFlags().get(flag.getFlagID()); if (itemFlag != null) { flags.add(itemFlag); } } } stockpile.setFlagName(flags); //Update Tags stockpile.updateTags(); //Update Items updateStockpileItems(stockpile, true); } private void updateStockpileItems(Stockpile stockpile, boolean updateClaims) { //Create lookup set of TypeIDs Set typeIDs = new HashSet<>(); addTypeIDs(typeIDs, stockpile); //Create lookup maps of Items if (!typeIDs.isEmpty()) { //Contract Items if (stockpile.isContracts()) { get(contractItems, stockpile).clear(); if (stockpile.isMatchAll()) { Map> foundItems = contractsMatchAll(profileData, stockpile, updateClaims); //Add for (List list : foundItems.values()) { for (MyContractItem contractItem : list) { add(get(contractItems, stockpile), get(contractItem.getTypeID(), contractItem.isBPC()), contractItem); } } } else { for (MyContractItem contractItem : profileData.getContractItemList()) { if (contractItem.getContract().isIgnoreContract()) { continue; } if (!contractItem.getContract().isOpen() && !contractItem.getContract().isCompletedSuccessful() ) { continue; //Only include open and successfully completed contracts } Integer typeID = get(contractItem.getTypeID(), contractItem.isBPC()); //Ignore null and wrong typeID if (ignore(typeIDs, typeID)) { continue; } //Add Contract Item add(get(contractItems, stockpile), typeID, contractItem); } } } //Assets if (stockpile.isAssets()) { get(assets, stockpile).clear(); if (stockpile.isMatchAll()) { Map> foundItems = assetsMatchAll(profileData, stockpile, updateClaims); //Add for (List list : foundItems.values()) { for (MyAsset asset : list) { add(get(assets, stockpile), get(asset.getTypeID(), asset.isBPC()), asset); } } } else { for (MyAsset asset : profileData.getAssetsList()) { if (asset.isGenerated()) { //Skip generated assets continue; } Integer typeID = get(asset.getTypeID(), asset.isBPC()); //Ignore null and wrong typeID if (ignore(typeIDs, typeID)) { continue; } //Add Asset add(get(assets, stockpile), typeID, asset); } } } //Market Orders if (stockpile.isBuyOrders() || stockpile.isSellOrders()) { for (MyMarketOrder marketOrder : profileData.getMarketOrdersList()) { if (!marketOrder.isActive()) { continue; //Only include active orders } Integer typeID = marketOrder.getTypeID(); //Ignore null and wrong typeID if (ignore(typeIDs, typeID)) { continue; } //Add Market Order add(marketOrders, typeID, marketOrder); } } //Industry Jobs if (stockpile.isJobs()) { for (MyIndustryJob industryJob : profileData.getIndustryJobsList()) { if (!industryJob.isNotDeliveredToAssets()) { continue; //Only include industry jobs not delivered } //Manufacturing Integer productTypeID = industryJob.getProductTypeID(); if (!ignore(typeIDs, productTypeID)) { //Ignore null and wrong typeID add(industryJobs, productTypeID, industryJob); } //Copying Integer blueprintTypeID = get(industryJob.getBlueprintTypeID(), true); //Negative - match blueprints copies if (!ignore(typeIDs, blueprintTypeID)) { //Ignore null and wrong typeID add(industryJobs, blueprintTypeID, industryJob); } } } //Transactions if (stockpile.isTransactions()) { for (MyTransaction transaction : profileData.getTransactionsList()) { if (!transaction.isAfterAssets()) { continue; //Only include transaction made after the last asset update } Integer typeID = transaction.getTypeID(); //Ignore null and wrong typeID if (typeID == null || !typeIDs.contains(typeID)) { continue; } //Add Transaction add(transactions, typeID, transaction); } } } stockpile.reset(); if (!stockpile.isEmpty()) { for (StockpileItem item : stockpile.getItems()) { if (item.isTotal()) { continue; //Ignore Total } updateItem(item, stockpile); } } stockpile.updateTotal(); } public static Map> contractsMatchAll(ProfileData profileData, Stockpile stockpile, boolean updateClaims) { Map> foundIDs = new HashMap<>(); Map> foundItems = new HashMap<>(); //Init found maps for (MyContract contract : profileData.getContractList()) { foundIDs.put(contract, new HashSet<>()); foundItems.put(contract, new ArrayList<>()); } //Update subpile claims if (updateClaims && !stockpile.getSubpiles().isEmpty()) { updateSubpileClaims(stockpile); } //StockpileItem map lookup Map stockpileItems = stockpile.getClaimsMap(); //Contract Items matching for (MyContractItem contractItem : profileData.getContractItemList()) { //Validate contract if (contractItem.getContract().isIgnoreContract()) { continue; } boolean found = false; for (TypeIdentifier type : getTypes(contractItem.getTypeID(), contractItem.isBPC())) { //Validate typeID if (ignore(stockpileItems.keySet(), type)) { continue; //Nothing left to do here } //Get items List items = foundItems.get(contractItem.getContract()); if (items == null) { continue; //Happens when one or more typeIDs from the contract isn't in the stockpile } //Get contract typeIDs Set ids = foundIDs.get(contractItem.getContract()); if (ids == null) { continue; //Should never happen, but, better safe than sorry } //Get StockpileItem StockpileItem stockpileItem = stockpileItems.get(type); if (stockpileItem == null) { continue; //Should never happen, but, better safe than sorry } if (stockpileItem.matchesContract(contractItem)) { items.add(contractItem); ids.add(type); break; //Can only match once } } if (!found) { foundItems.remove(contractItem.getContract()); //Contract have items not in the stockpile } } //Stockpile Items matching for (Map.Entry> entry : foundIDs.entrySet()) { //Only compare the size of the sets, as both sets only contains valid and unique ids. //Therefore there should be no reason to compare the actualy IDs (which is really really slow) if (entry.getValue().size() != stockpileItems.keySet().size()) { //Stockpile have items not in the contract foundItems.remove(entry.getKey()); } } return foundItems; } public static Map> assetsMatchAll(ProfileData profileData, Stockpile stockpile, boolean updateClaims) { Map> foundIDs = new HashMap<>(); Map> foundItems = new HashMap<>(); Map> parents = new HashMap<>(); //Init found maps for (MyAsset asset : profileData.getAssetsList()) { if (asset.getAssets().isEmpty()) { continue; } List children = new ArrayList<>(); addAssetChildren(children, asset); parents.put(asset, children); foundIDs.put(asset, new HashSet<>()); foundItems.put(asset, new ArrayList<>()); } //Update subpile claims if (updateClaims && !stockpile.getSubpiles().isEmpty()) { updateSubpileClaims(stockpile); } //StockpileItem map lookup Map stockpileItems = stockpile.getClaimsMap(); //Contract Items matching for (Map.Entry> entry : parents.entrySet()) { MyAsset parent = entry.getKey(); for (MyAsset child : entry.getValue()) { //Validate contract if (child.isGenerated()) { continue; } boolean found = false; for (TypeIdentifier type : getTypes(child.getTypeID(), child.isBPC())) { //Validate typeID if (ignore(stockpileItems.keySet(), type)) { continue; //Nothing left to do here } //Get items List items = foundItems.get(parent); if (items == null) { continue; //Happens when one or more typeIDs from the contract isn't in the stockpile } //Get contract typeIDs Set ids = foundIDs.get(parent); if (ids == null) { continue; //Should never happen, but, better safe than sorry } //Get StockpileItem StockpileItem stockpileItem = stockpileItems.get(type); if (stockpileItem == null) { continue; //Should never happen, but, better safe than sorry } if (stockpileItem.matchesAsset(child)) { items.add(child); ids.add(type); found = true; break; //Can only match once } } if (!found) { foundItems.remove(parent); //Contract have items not in the stockpile } } } //Stockpile Items matching for (Map.Entry> entry : foundIDs.entrySet()) { //Only compare the size of the sets, as both sets only contains valid and unique ids. //Therefore there should be no reason to compare the actualy IDs (which is really really slow) if (entry.getValue().size() != stockpileItems.keySet().size()) { //Stockpile have items not in the contract foundItems.remove(entry.getKey()); } } return foundItems; } private static void addAssetChildren(List assets, MyAsset asset) { assets.add(asset); for (MyAsset child : asset.getAssets()) { addAssetChildren(assets, child); } } public static Integer get(Integer typeID, boolean bpc) { //Ignore null if (typeID == null) { return null; } //BPC has negative value if (bpc) { typeID = -typeID; } //Return fixed TypeID return typeID; } public static List getTypes(Integer typeID, boolean bpc) { //Ignore null if (typeID == null) { return Collections.emptyList(); } //BPC has negative value if (bpc) { typeID = -typeID; List list = new ArrayList<>(); list.add(new TypeIdentifier(typeID, true)); list.add(new TypeIdentifier(typeID, false)); return list; } else { return Collections.singletonList(new TypeIdentifier(typeID, false)); } } private static boolean ignore(Set typeIDs, Integer typeID) { //Ignore null if (typeID == null) { return true; } //Ignore wrong typeID return !typeIDs.contains(typeID); } private static boolean ignore(Set typeIDs, TypeIdentifier typeID) { //Ignore null if (typeID == null) { return true; } //Ignore wrong typeID return !typeIDs.contains(typeID); } private void add(Map> map, Integer typeID, T t) { if (typeID == null) { return; //Ignore null (should never happen: better safe than sorry) } Set items = map.get(typeID); if (items == null) { items = new HashSet<>(); map.put(typeID, items); } items.add(t); } private void addTypeIDs(Set typeIDs, Stockpile stockpile) { for (StockpileItem item : stockpile.getItems()) { if (item.isTotal()) { continue; } typeIDs.add(item.getItemTypeID()); } for (Stockpile subpile : stockpile.getSubpiles().keySet()) { addTypeIDs(typeIDs, subpile); } } private void updateItem(StockpileItem item, Stockpile stockpile) { final int TYPE_ID = item.getItemTypeID(); double price = ApiIdConverter.getPrice(TYPE_ID, item.isBPC()); float volume = ApiIdConverter.getVolume(item.getItem(), true); Double transactionAveragePrice = profileData.getTransactionAveragePrice(TYPE_ID); PriceData priceData = ApiIdConverter.getPriceData(TYPE_ID, item.isBPC()); item.updateValues(price, volume, transactionAveragePrice, priceData); //Contract Items if (stockpile.isContracts()) { Set items = get(contractItems, stockpile).get(TYPE_ID); if (items != null) { for (MyContractItem contractItem : items) { item.updateContract(contractItem); } } } //Assets if (stockpile.isAssets()) { Set items = get(assets, stockpile).get(TYPE_ID); if (items != null) { for (MyAsset asset : items) { item.updateAsset(asset); } } } //Market Orders if (stockpile.isBuyOrders() || stockpile.isSellOrders()) { Set items = marketOrders.get(TYPE_ID); if (items != null) { for (MyMarketOrder marketOrder : items) { item.updateMarketOrder(marketOrder); } } } //Industry Job if (stockpile.isJobs()) { Set items = industryJobs.get(TYPE_ID); if (items != null) { for (MyIndustryJob industryJob : items) { item.updateIndustryJob(industryJob); } } } //Transactions if (stockpile.isTransactions()) { Set items = transactions.get(TYPE_ID); if (items != null) { for (MyTransaction transaction : items) { item.updateTransaction(transaction); } } } } private Map> get(Map>> map, Stockpile key) { Map> value = map.get(key); if (value == null) { value = new HashMap<>(); map.put(key, value); } return value; } /** * Update Subpiles for all stockpiles and return a list of the updated Subpiles. * This method does not change the EventList * @return */ private List getUpdatedSubpiles() { List added = new ArrayList<>(); for (Stockpile stockpile : Settings.get().getStockpiles()) { updateSubpile(added, null, stockpile); } return added; } /** * Update Subpiles for a single stockpile. * This method will update the EventList (remove old, add new) * This method is very ineffective when updating multiple Stockpiles: * Use getUpdatedSubpiles() to update all * And updateSubpile(,,) for anything > 1 * @param eventList * @param parent */ public void updateSubpile(EventList eventList, Stockpile parent) { List updated = new ArrayList<>(); List removed = new ArrayList<>(); updateSubpile(updated, removed, parent); //Update list try { eventList.getReadWriteLock().writeLock().lock(); eventList.removeAll(removed); StockpileTab.enableGroupFirstUpdate(); eventList.addAll(updated); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } /** * Internal: Don't use this. * Update subpiles for a single stockpile. Does not modify the EventList. * @param updated Updated SubpileItem's * @param removed Removed SubpileItem's * @param parent */ private void updateSubpile(List updated, List removed, Stockpile parent) { Map parentItems = new HashMap<>(); for (StockpileItem item : parent.getItems()) { parentItems.put(item.getItemTypeID(), item); } //Save old items (for them to be removed) List subpileItems = new ArrayList<>(parent.getSubpileItems()); //Clear old items parent.clearSubpileItems(); for (SubpileItem subpileItem : subpileItems) { subpileItem.clearItemLinks(); } //Update subs for (Stockpile stockpile : parent.getSubpileLinks()) { updateSubpile(updated, removed, stockpile); } //Add new items updateSubpileClaims(parent, parentItems); //Update stockpile items if (parent.isMatchAll() && (parent.isContracts() || parent.isAssets())) { updateStockpileItems(parent, false); } //Update items for (SubpileItem subpileItem : parent.getSubpileItems()) { updateItem(subpileItem, subpileItem.getStockpile()); } parent.updateTotal(); //Update lists if (removed != null) { removed.addAll(subpileItems); } updated.removeAll(subpileItems); if (profileManager.getStockpileIDs().isShown(parent.getStockpileID())) { String group = Settings.get().getStockpileGroupSettings().getGroup(parent); if (Settings.get().getStockpileGroupSettings().isGroupExpanded(group)) { //Stockpile group expanded or not in group updated.addAll(parent.getSubpileTableItems()); } } } private static void updateSubpileClaims(Stockpile topStockpile) { Map parentItems = new HashMap<>(); for (StockpileItem item : topStockpile.getItems()) { parentItems.put(item.getItemTypeID(), item); } updateSubpileClaims(topStockpile, parentItems); } private static void updateSubpileClaims(Stockpile topStockpile, Map topItems) { updateSubpileClaims(topStockpile, topStockpile, topItems, null, 0, ""); } /** * Internal: Don't use this. * Do all the subpile calculations * (this where the magic happens, 100% certified unreadable code! As required for all critical parts of this software) * @param topStockpile * @param parentStockpile * @param topItems * @param parentStock * @param parentLevel * @param parentPath */ private static void updateSubpileClaims(Stockpile topStockpile, Stockpile parentStockpile, Map topItems, SubpileStock parentStock, int parentLevel, String parentPath) { for (Map.Entry entry : parentStockpile.getSubpiles().entrySet()) { //For each subpile (stockpile) Stockpile currentStockpile = entry.getKey(); Double value = entry.getValue(); String path = parentPath + currentStockpile.getName() + "\r\n"; int level = parentLevel + 1; SubpileStock subpileStock = new SubpileStock(topStockpile, currentStockpile, parentStockpile, parentStock, value, parentLevel, path); topStockpile.addSubpileStock(subpileStock); for (StockpileItem stockpileItem : currentStockpile.getItems()) { //For each StockpileItem if (stockpileItem.isTotal()) { continue; //Ignore Total } StockpileItem parentItem = topItems.get(stockpileItem.getItemTypeID()); SubpileItem subpileItem = new SubpileItem(topStockpile, stockpileItem, subpileStock, parentLevel, path); int linkIndex = topStockpile.getSubpileItems().indexOf(subpileItem); if (parentItem != null) { //Add link (Advanced: Item + Link) subpileItem.addItemLink(parentItem, null); //Add link } if (linkIndex >= 0) { //Update item (Advanced: Link + Link = MultiLink) SubpileItem linkItem = topStockpile.getSubpileItems().get(linkIndex); linkItem.addItemLink(stockpileItem, subpileStock); if (level >= linkItem.getLevel()) { linkItem.setPath(path); linkItem.setLevel(level); } } else { //Add new item (Simple) topStockpile.addSubpileItem(subpileItem); } } updateSubpileClaims(topStockpile, currentStockpile, topItems, subpileStock, level, path); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/stockpile/StockpileDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.stockpile; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.matchers.Matcher; import ca.odell.glazedlists.matchers.TextMatcherEditor; import ca.odell.glazedlists.swing.AutoCompleteSupport; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.GroupLayout.Group; import javax.swing.GroupLayout.ParallelGroup; import javax.swing.GroupLayout.SequentialGroup; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.JTextComponent; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.sde.ItemFlag; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.DocumentFactory; import net.nikr.eve.jeveasset.gui.shared.DocumentFactory.ValueFlag; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.InstantToolTip; import net.nikr.eve.jeveasset.gui.shared.TextManager; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.shared.components.JDoubleField; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JIntegerField; import net.nikr.eve.jeveasset.gui.shared.components.ListComboBoxModel; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.EventModels.LocationFilterator; import net.nikr.eve.jeveasset.gui.shared.table.EventModels.StringFilterator; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileContainer; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileFlag; import net.nikr.eve.jeveasset.i18n.DataModelAsset; import net.nikr.eve.jeveasset.i18n.TabsStockpile; public class StockpileDialog extends JDialogCentered { private enum StockpileDialogAction { FILTER_LOCATIONS, VALIDATE, CANCEL, OK, ADD_PLANET, ADD_STATION, ADD_SYSTEM, ADD_REGION, ADD_CONSTELLATION, ADD_UNIVERSE, ADD_OWNER, ADD_FLAG, ADD_CONTAINER, ADD_SINGLETON, ADD_JOBS_DAYS, REMOVE, CLONE, CHANGE_LOCATION_TYPE } private static final int FIELD_WIDTH = 600; private final JTextField jName; private final JDoubleField jMultiplier; private final JCheckBox jMatchAll; private final JButton jOK; private final List locationPanels = new ArrayList<>(); private final JPanel jFiltersPanel; private final JLabel jWarning; private final Font font; private Stockpile stockpile; private Stockpile cloneStockpile; private boolean template; private boolean updated = false; //Data private final EventList planets; private final EventList stations; private final EventList systems; private final EventList constellations; private final EventList regions; private final Set myLocations; private final List owners; private final List itemFlags; private final List containers; private boolean initialized = false; public StockpileDialog(final Program program) { super(program, TabsStockpile.get().addStockpileTitle(), Images.TOOL_STOCKPILE.getImage()); //Data //Flags - static itemFlags = new ArrayList<>(StaticData.get().getItemFlags().values()); Collections.sort(itemFlags); //Locations - not static planets = EventListManager.create(); stations = EventListManager.create(); systems = EventListManager.create(); constellations = EventListManager.create(); regions = EventListManager.create(); //Owners - not static owners = new ArrayList<>(); //myLocations - not static myLocations = new HashSet<>(); //Containers - not static containers = new ArrayList<>(); ListenerClass listener = new ListenerClass(); //Name BorderPanel jNamePanel = new BorderPanel(TabsStockpile.get().name()); jName = new JTextField(); jName.addFocusListener(new FocusAdapter() { @Override public void focusGained(final FocusEvent e) { jName.selectAll(); } }); jName.addCaretListener(listener); jNamePanel.add(jName); font = jName.getFont(); //Multiplier BorderPanel jMultiplierPanel = new BorderPanel(TabsStockpile.get().multiplier()); jMultiplier = new JDoubleField("1", DocumentFactory.ValueFlag.POSITIVE_AND_NOT_ZERO); jMultiplier.setAutoSelectAll(true); jMultiplierPanel.add(jMultiplier); //Match All BorderPanel jMatchAllPanel = new BorderPanel(TabsStockpile.get().match()); jMatchAll = new JCheckBox(TabsStockpile.get().matchAll()); jMatchAll.setToolTipText(TabsStockpile.get().matchAllTip()); jMatchAllPanel.add(jMatchAll); jMatchAllPanel.addGab(5); //Add Filter JFixedToolBar jToolBar = new JFixedToolBar(); jToolBar.setBorder(BorderFactory.createTitledBorder(TabsStockpile.get().addFilter())); JButton jStation = new JButton(TabsStockpile.get().station(), Images.LOC_STATION.getIcon()); jStation.setHorizontalAlignment(JButton.LEFT); jStation.setActionCommand(StockpileDialogAction.ADD_STATION.name()); jStation.addActionListener(listener); jToolBar.addButton(jStation); JButton jPlanet = new JButton(TabsStockpile.get().planet(), Images.LOC_PLANET.getIcon()); jPlanet.setHorizontalAlignment(JButton.LEFT); jPlanet.setActionCommand(StockpileDialogAction.ADD_PLANET.name()); jPlanet.addActionListener(listener); jToolBar.addButton(jPlanet); JButton jSystem = new JButton(TabsStockpile.get().system(), Images.LOC_SYSTEM.getIcon()); jSystem.setHorizontalAlignment(JButton.LEFT); jSystem.setActionCommand(StockpileDialogAction.ADD_SYSTEM.name()); jSystem.addActionListener(listener); jToolBar.addButton(jSystem); JButton jConstellation = new JButton(TabsStockpile.get().constellation(), Images.LOC_CONSTELLATION.getIcon()); jConstellation.setHorizontalAlignment(JButton.LEFT); jConstellation.setActionCommand(StockpileDialogAction.ADD_CONSTELLATION.name()); jConstellation.addActionListener(listener); jToolBar.addButton(jConstellation); JButton jRegion = new JButton(TabsStockpile.get().region(), Images.LOC_REGION.getIcon()); jRegion.setHorizontalAlignment(JButton.LEFT); jRegion.setActionCommand(StockpileDialogAction.ADD_REGION.name()); jRegion.addActionListener(listener); jToolBar.addButton(jRegion); JButton jUniverse = new JButton(TabsStockpile.get().universe(), Images.LOC_LOCATIONS.getIcon()); jUniverse.setHorizontalAlignment(JButton.LEFT); jUniverse.setActionCommand(StockpileDialogAction.ADD_UNIVERSE.name()); jUniverse.addActionListener(listener); jToolBar.addButton(jUniverse); jWarning = createToolTipLabel(Images.UPDATE_DONE_ERROR.getIcon(), TabsStockpile.get().addLocation()); jToolBar.add(jWarning); //Filters jFiltersPanel = new JPanel(); JScrollPane jFiltersScroll = new JScrollPane(jFiltersPanel); jFiltersScroll.getVerticalScrollBar().setUnitIncrement(16); jFiltersScroll.setBorder(null); //OK jOK = new JButton(TabsStockpile.get().ok()); jOK.setActionCommand(StockpileDialogAction.OK.name()); jOK.addActionListener(listener); jOK.setEnabled(false); JButton jCancel = new JButton(TabsStockpile.get().cancel()); jCancel.setActionCommand(StockpileDialogAction.CANCEL.name()); jCancel.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addGroup(layout.createSequentialGroup() .addComponent(jNamePanel.getPanel(), FIELD_WIDTH - 215, FIELD_WIDTH - 215, FIELD_WIDTH - 215) .addComponent(jMultiplierPanel.getPanel()) .addComponent(jMatchAllPanel.getPanel()) ) .addComponent(jToolBar, FIELD_WIDTH, FIELD_WIDTH, FIELD_WIDTH) .addComponent(jFiltersScroll, FIELD_WIDTH, FIELD_WIDTH, FIELD_WIDTH) .addGroup(layout.createSequentialGroup() .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jNamePanel.getPanel()) .addComponent(jMultiplierPanel.getPanel()) .addComponent(jMatchAllPanel.getPanel()) ) .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jFiltersScroll, 0, GroupLayout.DEFAULT_SIZE, 500) .addGap(15) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } private Stockpile getStockpile() { //Name String name; if (jName.isEnabled()) { name = jName.getText(); } else { name = ""; } //Filters List stockpileFilters = new ArrayList<>(); for (LocationPanel locationPanel : locationPanels) { stockpileFilters.add(locationPanel.getFilter()); } //Multiplier double multiplier; try { multiplier = Double.parseDouble(jMultiplier.getText()); } catch (NumberFormatException ex) { multiplier = 1; } //Match All boolean matchAll = jMatchAll.isSelected(); //Add return new Stockpile(name, null, stockpileFilters, multiplier, matchAll); //New id } private void autoValidate() { boolean b = true; if (locationPanels.isEmpty()) { b = false; } jWarning.setVisible(locationPanels.isEmpty()); for (LocationPanel locationPanel : locationPanels) { if (!locationPanel.isValid()) { b = false; } } if (Settings.get().getStockpiles().contains(getStockpile())) { if (stockpile != null && stockpile.getName().equals(getStockpile().getName())) { ColorSettings.configReset(jName); } else { b = false; ColorSettings.config(jName, ColorEntry.GLOBAL_ENTRY_INVALID); } } else if (!jName.isEnabled()) { //Do nothing } else if (jName.getText().isEmpty()) { ColorSettings.config(jName, ColorEntry.GLOBAL_ENTRY_INVALID); b = false; } else { ColorSettings.configReset(jName); } jOK.setEnabled(b); } boolean showEdit(final Stockpile stockpile) { clear(); this.stockpile = stockpile; //Title this.getDialog().setTitle(TabsStockpile.get().editStockpileTitle()); //Load loadStockpile(stockpile, stockpile.getName()); //Show show(); return updated; } Stockpile showAdd() { clear(); this.getDialog().setTitle(TabsStockpile.get().addStockpileTitle()); show(); return stockpile; } Stockpile showAdd(final String name) { clear(); jName.setText(name); this.getDialog().setTitle(TabsStockpile.get().addStockpileTitle()); show(); return stockpile; } Stockpile showTemplate() { clear(); ColorSettings.configReset(jName); template = true; jName.setEnabled(false); jName.setText(TabsStockpile.get().importOptionsTemplate()); jName.setFont(font.deriveFont(Font.ITALIC)); this.getDialog().setTitle(TabsStockpile.get().addStockpileTitle()); show(); return stockpile; } Stockpile showRename(final Stockpile stockpile) { clear(); cloneStockpile = stockpile.deepClone(); //Title this.getDialog().setTitle(TabsStockpile.get().renameStockpileTitle()); //Load loadStockpile(cloneStockpile, cloneStockpile.getName()); //Show show(); if (updated) { return cloneStockpile; } else { return null; } } Stockpile showClone(final Stockpile stockpile) { clear(); cloneStockpile = stockpile.deepClone(); //Title this.getDialog().setTitle(TabsStockpile.get().cloneStockpileTitle()); //Load loadStockpile(cloneStockpile, stockpile.getName()); //Show show(); if (updated) { return cloneStockpile; } else { return null; } } private void loadStockpile(Stockpile loadStockpile, String name) { //Name jName.setText(name); //Multiplier jMultiplier.setText(Formatter.compareFormat(loadStockpile.getMultiplier())); //Match All jMatchAll.setSelected(loadStockpile.isMatchAll()); //Filters for (StockpileFilter filter : loadStockpile.getFilters()) { LocationPanel locationPanel = new LocationPanel(filter); locationPanels.add(locationPanel); } updatePanels(); } private void updatePanels() { jFiltersPanel.removeAll(); GroupLayout groupLayout = new GroupLayout(jFiltersPanel); jFiltersPanel.setLayout(groupLayout); groupLayout.setAutoCreateGaps(true); groupLayout.setAutoCreateContainerGaps(false); ParallelGroup horizontalGroup = groupLayout.createParallelGroup(); SequentialGroup verticalGroup = groupLayout.createSequentialGroup(); for (LocationPanel locationPanel : locationPanels) { horizontalGroup.addComponent(locationPanel.getPanel()); verticalGroup.addComponent(locationPanel.getPanel()); } jFiltersPanel.setVisible(!locationPanels.isEmpty()); groupLayout.setHorizontalGroup(horizontalGroup); groupLayout.setVerticalGroup(verticalGroup); autoValidate(); this.getDialog().pack(); } private void show() { updated = false; if (!initialized) { updateData(); } super.setVisible(true); } private void clear() { stockpile = null; cloneStockpile = null; template = false; jName.setEnabled(true); jName.setFont(font); jName.setText(""); jMultiplier.setText("1"); jMatchAll.setSelected(false); locationPanels.clear(); updatePanels(); } void updateData() { //Locations List planetList = new ArrayList<>(); List stationList = new ArrayList<>(); List systemList = new ArrayList<>(); List constellationList = new ArrayList<>(); List regionList = new ArrayList<>(); for (MyLocation location : StaticData.get().getLocations()) { if (location.isPlanet()) { planetList.add(location); } else if (location.isStation()) { //Not planet stationList.add(location); } else if (location.isSystem()) { systemList.add(location); } else if (location.isConstellation()) { constellationList.add(location); } else if (location.isRegion()) { regionList.add(location); } } Collections.sort(planetList); Collections.sort(stationList); Collections.sort(systemList); Collections.sort(constellationList); Collections.sort(regionList); try { planets.getReadWriteLock().writeLock().lock(); planets.clear(); planets.addAll(planetList); } finally { planets.getReadWriteLock().writeLock().unlock(); } try { stations.getReadWriteLock().writeLock().lock(); stations.clear(); stations.addAll(stationList); } finally { stations.getReadWriteLock().writeLock().unlock(); } try { systems.getReadWriteLock().writeLock().lock(); systems.clear(); systems.addAll(systemList); } finally { systems.getReadWriteLock().writeLock().unlock(); } try { constellations.getReadWriteLock().writeLock().lock(); constellations.clear(); constellations.addAll(constellationList); } finally { constellations.getReadWriteLock().writeLock().unlock(); } try { regions.getReadWriteLock().writeLock().lock(); regions.clear(); regions.addAll(regionList); } finally { regions.getReadWriteLock().writeLock().unlock(); } //Name jName.setText(""); //Owners Map ownersById = new HashMap<>(); for (OwnerType owner : program.getOwnerTypes()) { ownersById.put(owner.getOwnerID(), owner); } owners.clear(); owners.addAll(ownersById.values()); Collections.sort(owners); //Containers & MyLocations Loop Set containerSet = new HashSet<>(); myLocations.clear(); for (MyAsset asset : program.getAssetsList()) { if (!asset.getContainer().isEmpty()) { containerSet.add(asset.getContainer()); } myLocations.add(asset.getLocation().getLocation()); myLocations.add(asset.getLocation().getSystem()); myLocations.add(asset.getLocation().getConstellation()); myLocations.add(asset.getLocation().getRegion()); } for (MyIndustryJob industryJob : program.getIndustryJobsList()) { if (!industryJob.isNotDeliveredToAssets()) { continue; //Only open industry jobs } myLocations.add(industryJob.getLocation().getLocation()); myLocations.add(industryJob.getLocation().getSystem()); myLocations.add(industryJob.getLocation().getConstellation()); myLocations.add(industryJob.getLocation().getRegion()); } for (MyMarketOrder marketOrder : program.getMarketOrdersList()) { if (!marketOrder.isActive()) { continue; //Only include active orders } myLocations.add(marketOrder.getLocation().getLocation()); myLocations.add(marketOrder.getLocation().getSystem()); myLocations.add(marketOrder.getLocation().getConstellation()); myLocations.add(marketOrder.getLocation().getRegion()); } for (MyContract contract : program.getContractList()) { if (!contract.isOpen()) { continue; //Only include open contracts } myLocations.add(contract.getStartLocation().getLocation()); myLocations.add(contract.getStartLocation().getSystem()); myLocations.add(contract.getStartLocation().getConstellation()); myLocations.add(contract.getStartLocation().getRegion()); myLocations.add(contract.getEndLocation().getLocation()); myLocations.add(contract.getEndLocation().getSystem()); myLocations.add(contract.getEndLocation().getConstellation()); myLocations.add(contract.getEndLocation().getRegion()); } //Containers containers.clear(); containers.addAll(containerSet); Collections.sort(containers, StringComparators.CASE_INSENSITIVE); initialized = true; } @Override protected JComponent getDefaultFocus() { return jName; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { } @Override protected void save() { Settings.lock("Stockpile (Stockpile dialog)"); //Lock for Stockpile (Stockpile dialog) if (template) { //Edit stockpile = getStockpile(); //Don't save anything } else if (stockpile != null) { //Edit String group = Settings.get().getStockpileGroupSettings().getGroup(stockpile); Settings.get().getStockpileGroupSettings().removeGroup(stockpile); stockpile.update(getStockpile()); Settings.get().getStockpileGroupSettings().setGroup(stockpile, group); } else if (cloneStockpile != null) { //Clone cloneStockpile.update(getStockpile()); StockpileTab.addSettingStockpile(cloneStockpile, false); //Add Clone } else { //Add stockpile = getStockpile(); StockpileTab.addSettingStockpile(stockpile, false); //Add } StockpileTab.sortSettingStockpile(); updated = true; Settings.unlock("Stockpile (Stockpile dialog)"); //Unlock for Stockpile (Stockpile dialog) program.saveSettings("Stockpile (Stockpile dialog)"); //Save Stockpile (Stockpile dialog) this.setVisible(false); } private static JLabel createToolTipLabel(Icon icon, String toolTip) { JLabel jLabel = new JLabel(icon); jLabel.setToolTipText(toolTip); InstantToolTip.install(jLabel); return jLabel; } private class ListenerClass implements ActionListener, CaretListener { @Override public void actionPerformed(final ActionEvent e) { if (StockpileDialogAction.OK.name().equals(e.getActionCommand())) { save(); } else if (StockpileDialogAction.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); } else if (StockpileDialogAction.ADD_PLANET.name().equals(e.getActionCommand())) { locationPanels.add(new LocationPanel(LocationType.PLANET)); updatePanels(); } else if (StockpileDialogAction.ADD_STATION.name().equals(e.getActionCommand())) { locationPanels.add(new LocationPanel(LocationType.STATION)); updatePanels(); } else if (StockpileDialogAction.ADD_SYSTEM.name().equals(e.getActionCommand())) { locationPanels.add(new LocationPanel(LocationType.SYSTEM)); updatePanels(); } else if (StockpileDialogAction.ADD_CONSTELLATION.name().equals(e.getActionCommand())) { locationPanels.add(new LocationPanel(LocationType.CONSTELLATION)); updatePanels(); } else if (StockpileDialogAction.ADD_REGION.name().equals(e.getActionCommand())) { locationPanels.add(new LocationPanel(LocationType.REGION)); updatePanels(); } else if (StockpileDialogAction.ADD_UNIVERSE.name().equals(e.getActionCommand())) { locationPanels.add(new LocationPanel(LocationType.UNIVERSE)); updatePanels(); } } @Override public void caretUpdate(final CaretEvent e) { autoValidate(); } } static class LocationsMatcher implements Matcher { private Set myLocations; public LocationsMatcher(final Set myLocations) { this.myLocations = myLocations; } @Override public boolean matches(final MyLocation item) { return myLocations.contains(item.getLocation()); } } private enum FilterType { OWNER, FLAG, CONTAINER, SINGLETON, JOBS_DAYS, } private enum LocationType { PLANET, STATION, SYSTEM, CONSTELLATION, REGION, UNIVERSE, } private class FilterPanel { //GUI private final JPanel jPanel; private final GroupLayout groupLayout; private final JButton jRemove; private final JLabel jType; private final JLabel jWarning; //Owner private JComboBox jOwner; //Flag private JComboBox jFlag; private JCheckBox jFlagIncludeSubs; //Container private JComboBox jContainer; private JCheckBox jContainerIncludeSubs; //Singleton private JComboBox jSingleton; //Jobs Days private JIntegerField jJobsDays; private JComboBox jJobsMoreOrLess; private final ListenerClass listener = new ListenerClass(); private final LocationPanel locationPanel; private final FilterType filterType; public FilterPanel(final LocationPanel locationPanel, final StockpileContainer container) { this(locationPanel, FilterType.CONTAINER); jContainer.setSelectedItem(container.getContainer()); jContainerIncludeSubs.setSelected(container.isIncludeSubs()); } public FilterPanel(final LocationPanel locationPanel, final ItemFlag itemFlag, final boolean matchParents) { this(locationPanel, FilterType.FLAG); jFlag.setSelectedItem(itemFlag); jFlagIncludeSubs.setSelected(matchParents); } public FilterPanel(final LocationPanel locationPanel, final OwnerType owner) { this(locationPanel, FilterType.OWNER); jOwner.setSelectedItem(owner); } public FilterPanel(final LocationPanel locationPanel, final boolean singleton) { this(locationPanel, FilterType.SINGLETON); jSingleton.setSelectedItem(singleton ? DataModelAsset.get().unpackaged() : DataModelAsset.get().packaged()); } public FilterPanel(final LocationPanel locationPanel, final int days, boolean less) { this(locationPanel, FilterType.JOBS_DAYS); if (less) { jJobsMoreOrLess.setSelectedIndex(0); } else { jJobsMoreOrLess.setSelectedIndex(1); } jJobsDays.setText(String.valueOf(days)); } public FilterPanel(final LocationPanel locationPanel, final FilterType filterType) { this.locationPanel = locationPanel; this.filterType = filterType; jPanel = new JPanel(); groupLayout = new GroupLayout(jPanel); jPanel.setLayout(groupLayout); groupLayout.setAutoCreateGaps(true); groupLayout.setAutoCreateContainerGaps(false); jRemove = new JButton(Images.EDIT_DELETE.getIcon()); jRemove.setActionCommand(StockpileDialogAction.REMOVE.name()); jRemove.addActionListener(listener); jWarning = createToolTipLabel(Images.UPDATE_DONE_ERROR.getIcon(), TabsStockpile.get().duplicate()); jType = new JLabel(); if (filterType == FilterType.CONTAINER) { jType.setIcon(Images.LOC_CONTAINER_WHITE.getIcon()); jType.setToolTipText(TabsStockpile.get().container()); EventList containerEventList = EventListManager.create(); try { containerEventList.getReadWriteLock().writeLock().lock(); containerEventList.addAll(containers); } finally { containerEventList.getReadWriteLock().writeLock().unlock(); } jContainer = new JComboBox<>(); jContainerIncludeSubs = new JCheckBox(TabsStockpile.get().containerIncludeSubs()); jContainerIncludeSubs.setToolTipText(TabsStockpile.get().containerIncludeSubsToolTip()); TextManager.installTextComponent((JTextComponent) jContainer.getEditor().getEditorComponent()); AutoCompleteSupport containerAutoComplete = AutoCompleteSupport.install(jContainer, EventModels.createSwingThreadProxyList(containerEventList), new StringFilterator()); containerAutoComplete.setFilterMode(TextMatcherEditor.CONTAINS); ((JTextComponent) jContainer.getEditor().getEditorComponent()).getDocument().addDocumentListener(listener); jContainer.setActionCommand(StockpileDialogAction.VALIDATE.name()); jContainer.addActionListener(listener); groupLayout.setHorizontalGroup( groupLayout.createSequentialGroup() .addComponent(jType) .addComponent(jWarning) .addComponent(jContainer, 0, 0, FIELD_WIDTH) .addComponent(jContainerIncludeSubs) .addComponent(jRemove, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) ); groupLayout.setVerticalGroup( groupLayout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jWarning, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jContainer, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jContainerIncludeSubs, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRemove, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } else if (filterType == FilterType.SINGLETON) { jType.setIcon(Images.INCLUDE_PACKAGED.getIcon()); jType.setToolTipText(TabsStockpile.get().container()); String[] singleton = {DataModelAsset.get().unpackaged(), DataModelAsset.get().packaged()}; jSingleton = new JComboBox<>(new ListComboBoxModel<>(singleton)); groupLayout.setHorizontalGroup( groupLayout.createSequentialGroup() .addComponent(jType) .addComponent(jWarning) .addComponent(jSingleton, 0, 0, FIELD_WIDTH) .addComponent(jRemove, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) ); groupLayout.setVerticalGroup( groupLayout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jWarning, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSingleton, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRemove, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } else if (filterType == FilterType.FLAG) { jType.setIcon(Images.LOC_FLAG.getIcon()); jType.setToolTipText(TabsStockpile.get().flag()); jFlag = new JComboBox<>(new ListComboBoxModel<>(itemFlags)); jFlag.setActionCommand(StockpileDialogAction.VALIDATE.name()); jFlag.addActionListener(listener); jFlagIncludeSubs = new JCheckBox(TabsStockpile.get().flagIncludeSubs()); jFlagIncludeSubs.setToolTipText(TabsStockpile.get().flagIncludeSubsToolTip()); groupLayout.setHorizontalGroup( groupLayout.createSequentialGroup() .addComponent(jType) .addComponent(jWarning) .addComponent(jFlag, 0, 0, FIELD_WIDTH) .addComponent(jFlagIncludeSubs) .addComponent(jRemove, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) ); groupLayout.setVerticalGroup( groupLayout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jWarning, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFlag, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFlagIncludeSubs, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRemove, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } else if (filterType == FilterType.OWNER) { jType.setIcon(Images.LOC_OWNER.getIcon()); jType.setToolTipText(TabsStockpile.get().owner()); jOwner = new JComboBox<>(new ListComboBoxModel<>(owners)); jOwner.setActionCommand(StockpileDialogAction.VALIDATE.name()); jOwner.addActionListener(listener); jOwner.setEnabled(!owners.isEmpty()); groupLayout.setHorizontalGroup( groupLayout.createSequentialGroup() .addComponent(jType) .addComponent(jWarning) .addComponent(jOwner, 0, 0, FIELD_WIDTH) .addComponent(jRemove, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) ); groupLayout.setVerticalGroup( groupLayout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jWarning, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOwner, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRemove, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } else if (filterType == FilterType.JOBS_DAYS) { jType.setIcon(Images.INCLUDE_JOBS.getIcon()); jType.setToolTipText(TabsStockpile.get().jobsDaysTip()); String[] moreOrLess = {TabsStockpile.get().jobsDaysLess(), TabsStockpile.get().jobsDaysMore()}; jJobsMoreOrLess = new JComboBox<>(moreOrLess); jJobsMoreOrLess.setPrototypeDisplayValue(TabsStockpile.get().jobsDaysMore()); jJobsDays = new JIntegerField("1", ValueFlag.POSITIVE_AND_NOT_ZERO); jJobsDays.setHorizontalAlignment(JTextField.RIGHT); jJobsDays.addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { jJobsDays.selectAll(); } }); jWarning.setToolTipText(TabsStockpile.get().jobsDaysWarning()); groupLayout.setHorizontalGroup( groupLayout.createSequentialGroup() .addComponent(jType) .addComponent(jWarning) .addComponent(jJobsDays, 0, 0, FIELD_WIDTH) .addComponent(jJobsMoreOrLess, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jRemove, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) ); groupLayout.setVerticalGroup( groupLayout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(jType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jWarning, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jJobsDays, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jJobsMoreOrLess, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRemove, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } } private void remove() { if (filterType == FilterType.SINGLETON) { locationPanel.removeSingleton(); } else if (filterType == FilterType.JOBS_DAYS) { locationPanel.removeJobsDays(); } else if (filterType == FilterType.CONTAINER) { locationPanel.removeContainer(this); } else if (filterType == FilterType.FLAG) { locationPanel.removeFlag(this); } else if (filterType == FilterType.OWNER) { locationPanel.removeOwner(this); } updatePanels(); } public StockpileContainer getContainer() { return new StockpileContainer(((JTextComponent) jContainer.getEditor().getEditorComponent()).getText(), jContainerIncludeSubs.isSelected()); } public Integer getJobsDaysLess() { if (jJobsDays == null || !getValue(jJobsMoreOrLess, String.class).equals(TabsStockpile.get().jobsDaysLess())) { return null; } try { return Integer.valueOf(jJobsDays.getText()); } catch (NumberFormatException ex) { return null; } } public Integer getJobsDaysMore() { if (jJobsDays == null || !getValue(jJobsMoreOrLess, String.class).equals(TabsStockpile.get().jobsDaysMore())) { return null; } try { return Integer.valueOf(jJobsDays.getText()); } catch (NumberFormatException ex) { return null; } } public boolean getSingleton() { return getValue(jSingleton, String.class).equals(DataModelAsset.get().unpackaged()); } public StockpileFlag getFlag() { return new StockpileFlag(getValue(jFlag, ItemFlag.class).getFlagID(), jFlagIncludeSubs.isSelected()); } public Long getOwner() { return getValue(jOwner, OwnerType.class).getOwnerID(); } private E getValue(JComboBox jComboBox, Class clazz) { if (jComboBox != null) { Object object = jComboBox.getSelectedItem(); if (clazz.isInstance(object)) { return clazz.cast(object); } } return null; } public JPanel getPanel() { return jPanel; } private void warning(boolean b) { jWarning.setVisible(b); } private class ListenerClass implements ActionListener, DocumentListener { @Override public void actionPerformed(final ActionEvent e) { if (StockpileDialogAction.REMOVE.name().equals(e.getActionCommand())) { remove(); } else if (StockpileDialogAction.VALIDATE.name().equals(e.getActionCommand())) { autoValidate(); } } @Override public void insertUpdate(DocumentEvent e) { autoValidate(); } @Override public void removeUpdate(DocumentEvent e) { autoValidate(); } @Override public void changedUpdate(DocumentEvent e) { autoValidate(); } } } private class LocationPanel { private final List ownerPanels = new ArrayList<>(); private final List flagPanels = new ArrayList<>(); private final List containerPanels = new ArrayList<>(); private FilterPanel singletonPanel = null; private FilterPanel jobsDaysPanel = null; private final JPanel jPanel; private final JPanel jFilters; private final ListenerClass listener = new ListenerClass(); //Singleton private final JMenuItem jSingleton; //Jobs Days private final JMenuItem jJobsDays; //Location private final JLabel jLocationType; private final JComboBox jLocation; private final JDropDownButton jMatch; private final JRadioButtonMenuItem jMatchExclude; private final JCheckBoxMenuItem jMyLocations; private FilterList filterList; private AutoCompleteSupport autoComplete; //Include private final JDropDownButton jInclude; private final JCheckBoxMenuItem jAssets; private final JCheckBoxMenuItem jJobs; private final JCheckBoxMenuItem jBuyingOrders; private final JCheckBoxMenuItem jSellingOrders; private final JCheckBoxMenuItem jBoughtTransactions; private final JCheckBoxMenuItem jSoldTransactions; private final JCheckBoxMenuItem jBuyingContracts; private final JCheckBoxMenuItem jSellingContracts; private final JCheckBoxMenuItem jBoughtContracts; private final JCheckBoxMenuItem jSoldContracts; private final JLabel jErrorLabel; private final JLabel jAssetsLabel; private final JLabel jJobsLabel; private final JLabel jOrdersLabel; private final JLabel jContractsLabel; private final JLabel jLocationWarning; //Edit private final JRadioButtonMenuItem jPlanet; private final JRadioButtonMenuItem jStation; private final JRadioButtonMenuItem jSystem; private final JRadioButtonMenuItem jConstellation; private final JRadioButtonMenuItem jRegion; private final JRadioButtonMenuItem jUniverse; private LocationType locationType; public LocationPanel(StockpileFilter stockpileFilter) { this(); if (stockpileFilter.getLocation() == null || stockpileFilter.getLocation().isEmpty()) { setLocationType(LocationType.UNIVERSE); } else if (stockpileFilter.getLocation().isPlanet()) { setLocationType(LocationType.PLANET); } else if (stockpileFilter.getLocation().isStation()) { //Not planet setLocationType(LocationType.STATION); } else if (stockpileFilter.getLocation().isSystem()) { setLocationType(LocationType.SYSTEM); } else if (stockpileFilter.getLocation().isConstellation()) { setLocationType(LocationType.CONSTELLATION); } else if (stockpileFilter.getLocation().isRegion()) { setLocationType(LocationType.REGION); } else { setLocationType(LocationType.UNIVERSE); } //Location if(locationType != LocationType.UNIVERSE) { MyLocation location = stockpileFilter.getLocation(); jMyLocations.setSelected(myLocations.contains(location.getLocation())); refilter(); jLocation.setSelectedItem(location); } //Container for (StockpileContainer container : stockpileFilter.getContainers()) { containerPanels.add(new FilterPanel(this, container)); } //Owner Set ownersFound = new HashSet<>(); for (long ownerID : stockpileFilter.getOwnerIDs()) { for (OwnerType owner : owners) { if (owner.getOwnerID() == ownerID) { ownersFound.add(owner); break; } } } for (OwnerType owner : ownersFound) { ownerPanels.add(new FilterPanel(this, owner)); } //Flag for (StockpileFlag flag : stockpileFilter.getFlags()) { ItemFlag itemFlag = StaticData.get().getItemFlags().get(flag.getFlagID()); if (itemFlag != null) { flagPanels.add(new FilterPanel(this, itemFlag, flag.isIncludeSubs())); } } Boolean singleton = stockpileFilter.isSingleton(); if (singleton != null) { singletonPanel = new FilterPanel(this, singleton); jSingleton.setEnabled(false); } else { jSingleton.setEnabled(true); } Integer jobsDaysLess = stockpileFilter.getJobsDaysLess(); Integer jobsDaysMore = stockpileFilter.getJobsDaysMore(); if (jobsDaysLess != null) { jobsDaysPanel = new FilterPanel(this, jobsDaysLess, true); jJobsDays.setEnabled(false); //One instance only } else if (jobsDaysMore != null) { jobsDaysPanel = new FilterPanel(this, jobsDaysMore, false); jJobsDays.setEnabled(false); //One instance only } else { jJobsDays.setEnabled(stockpileFilter.isJobs()); //Only enabled if industry jobs are active } //Exclude jMatchExclude.setSelected(stockpileFilter.isExclude()); //Includes jAssets.setSelected(stockpileFilter.isAssets()); jJobs.setSelected(stockpileFilter.isJobs()); jBuyingOrders.setSelected(stockpileFilter.isBuyOrders()); jSellingOrders.setSelected(stockpileFilter.isSellOrders()); jBoughtTransactions.setSelected(stockpileFilter.isBuyTransactions()); jSoldTransactions.setSelected(stockpileFilter.isSellTransactions()); jBuyingContracts.setSelected(stockpileFilter.isBuyingContracts()); jSellingContracts.setSelected(stockpileFilter.isSellingContracts()); jBoughtContracts.setSelected(stockpileFilter.isBoughtContracts()); jSoldContracts.setSelected(stockpileFilter.isSoldContracts()); doLayout(); } public LocationPanel(LocationType type) { this(); setLocationType(type); refilter(); doLayout(); } private LocationPanel() { jFilters = new JPanel(); jPanel = new JPanel(); GroupLayout groupLayout = new GroupLayout(jPanel); jPanel.setLayout(groupLayout); groupLayout.setAutoCreateGaps(true); groupLayout.setAutoCreateContainerGaps(false); JFixedToolBar jToolBar = new JFixedToolBar(); //MATCH jMatch = new JDropDownButton(Images.EDIT_ADD_WHITE.getIcon()); jToolBar.addButtonIcon(jMatch); JRadioButtonMenuItem jMatchInclude = new JRadioButtonMenuItem(TabsStockpile.get().matchInclude(), Images.EDIT_ADD_WHITE.getIcon()); jMatchInclude.setHorizontalAlignment(JButton.LEFT); jMatchInclude.setActionCommand(StockpileDialogAction.VALIDATE.name()); jMatchInclude.addActionListener(listener); jMatchInclude.setSelected(true); jMatch.add(jMatchInclude); jMatchExclude = new JRadioButtonMenuItem(TabsStockpile.get().matchExclude(), Images.EDIT_DELETE_WHITE.getIcon()); jMatchExclude.setHorizontalAlignment(JButton.LEFT); jMatchExclude.setActionCommand(StockpileDialogAction.VALIDATE.name()); jMatchExclude.addActionListener(listener); jMatch.add(jMatchExclude); ButtonGroup matchButtonGroup = new ButtonGroup(); matchButtonGroup.add(jMatchInclude); matchButtonGroup.add(jMatchExclude); //ADD JDropDownButton jAdd = new JDropDownButton(TabsStockpile.get().filters(), Images.INCLUDE_ADD_FILTER.getIcon()); jAdd.setToolTipText(TabsStockpile.get().include()); jToolBar.addButton(jAdd); JMenuItem jOwner = new JMenuItem(TabsStockpile.get().owner(), Images.LOC_OWNER.getIcon()); jOwner.setActionCommand(StockpileDialogAction.ADD_OWNER.name()); jOwner.addActionListener(listener); jOwner.setEnabled(!owners.isEmpty()); jAdd.add(jOwner); JMenuItem jFlag = new JMenuItem(TabsStockpile.get().flag(), Images.LOC_FLAG.getIcon()); jFlag.setActionCommand(StockpileDialogAction.ADD_FLAG.name()); jFlag.addActionListener(listener); jAdd.add(jFlag); JMenuItem jContainer = new JMenuItem(TabsStockpile.get().container(), Images.LOC_CONTAINER_WHITE.getIcon()); jContainer.setActionCommand(StockpileDialogAction.ADD_CONTAINER.name()); jContainer.addActionListener(listener); jAdd.add(jContainer); jSingleton = new JMenuItem(TabsStockpile.get().singleton(), Images.INCLUDE_PACKAGED.getIcon()); jSingleton.setActionCommand(StockpileDialogAction.ADD_SINGLETON.name()); jSingleton.addActionListener(listener); jAdd.add(jSingleton); jJobsDays = new JMenuItem(TabsStockpile.get().jobsDays(), Images.INCLUDE_JOBS.getIcon()); jJobsDays.setEnabled(false); //No include selected by default, so defaults to disabled jJobsDays.setToolTipText(TabsStockpile.get().jobsDaysTip()); jJobsDays.setActionCommand(StockpileDialogAction.ADD_JOBS_DAYS.name()); jJobsDays.addActionListener(listener); jAdd.add(jJobsDays); //INCLUDE jInclude = new JDropDownButton(TabsStockpile.get().include(), Images.LOC_INCLUDE.getIcon()); jInclude.setToolTipText(TabsStockpile.get().include()); jToolBar.addButton(jInclude); jAssets = new JCheckBoxMenuItem(TabsStockpile.get().includeAssets()); jAssets.setToolTipText(TabsStockpile.get().includeAssetsTip()); jAssets.setHorizontalAlignment(JButton.LEFT); jAssets.setActionCommand(StockpileDialogAction.VALIDATE.name()); jAssets.addActionListener(listener); jInclude.add(jAssets, true); jJobs = new JCheckBoxMenuItem(TabsStockpile.get().includeJobs()); jJobs.setToolTipText(TabsStockpile.get().includeJobsTip()); jJobs.setHorizontalAlignment(JButton.LEFT); jJobs.setActionCommand(StockpileDialogAction.VALIDATE.name()); jJobs.addActionListener(listener); jInclude.add(jJobs, true); jBuyingOrders = new JCheckBoxMenuItem(TabsStockpile.get().includeBuyOrders()); jBuyingOrders.setToolTipText(TabsStockpile.get().includeBuyOrdersTip()); jBuyingOrders.setHorizontalAlignment(JButton.LEFT); jBuyingOrders.setActionCommand(StockpileDialogAction.VALIDATE.name()); jBuyingOrders.addActionListener(listener); jInclude.add(jBuyingOrders, true); jSellingOrders = new JCheckBoxMenuItem(TabsStockpile.get().includeSellOrders()); jSellingOrders.setToolTipText(TabsStockpile.get().includeSellOrdersTip()); jSellingOrders.setHorizontalAlignment(JButton.LEFT); jSellingOrders.setActionCommand(StockpileDialogAction.VALIDATE.name()); jSellingOrders.addActionListener(listener); jInclude.add(jSellingOrders, true); jBoughtTransactions = new JCheckBoxMenuItem(TabsStockpile.get().includeBuyTransactions()); jBoughtTransactions.setToolTipText(TabsStockpile.get().includeBuyTransactionsTip()); jBoughtTransactions.setHorizontalAlignment(JButton.LEFT); jBoughtTransactions.setActionCommand(StockpileDialogAction.VALIDATE.name()); jBoughtTransactions.addActionListener(listener); jInclude.add(jBoughtTransactions, true); jSoldTransactions = new JCheckBoxMenuItem(TabsStockpile.get().includeSellTransactions()); jSoldTransactions.setToolTipText(TabsStockpile.get().includeSellTransactionsTip()); jSoldTransactions.setHorizontalAlignment(JButton.LEFT); jSoldTransactions.setActionCommand(StockpileDialogAction.VALIDATE.name()); jSoldTransactions.addActionListener(listener); jInclude.add(jSoldTransactions, true); jBuyingContracts = new JCheckBoxMenuItem(TabsStockpile.get().includeBuyingContracts()); jBuyingContracts.setToolTipText(TabsStockpile.get().includeBuyingContractsTip()); jBuyingContracts.setHorizontalAlignment(JButton.LEFT); jBuyingContracts.setActionCommand(StockpileDialogAction.VALIDATE.name()); jBuyingContracts.addActionListener(listener); jInclude.add(jBuyingContracts, true); jSellingContracts = new JCheckBoxMenuItem(TabsStockpile.get().includeSellingContracts()); jSellingContracts.setToolTipText(TabsStockpile.get().includeSellingContractsTip()); jSellingContracts.setHorizontalAlignment(JButton.LEFT); jSellingContracts.setActionCommand(StockpileDialogAction.VALIDATE.name()); jSellingContracts.addActionListener(listener); jInclude.add(jSellingContracts, true); jBoughtContracts = new JCheckBoxMenuItem(TabsStockpile.get().includeBoughtContracts()); jBoughtContracts.setToolTipText(TabsStockpile.get().includeBoughtContractsTip()); jBoughtContracts.setHorizontalAlignment(JButton.LEFT); jBoughtContracts.setActionCommand(StockpileDialogAction.VALIDATE.name()); jBoughtContracts.addActionListener(listener); jInclude.add(jBoughtContracts, true); jSoldContracts = new JCheckBoxMenuItem(TabsStockpile.get().includeSoldContracts()); jSoldContracts.setToolTipText(TabsStockpile.get().includeSoldContractsTip()); jSoldContracts.setHorizontalAlignment(JButton.LEFT); jSoldContracts.setActionCommand(StockpileDialogAction.VALIDATE.name()); jSoldContracts.addActionListener(listener); jInclude.add(jSoldContracts, true); //INCLIDE LABELS jErrorLabel = new JLabel(TabsStockpile.get().includeHelp()); jErrorLabel.setIcon(Images.UPDATE_DONE_ERROR.getIcon()); jAssetsLabel = new JLabel(); jAssetsLabel.setDisabledIcon(Images.INCLUDE_ASSETS.getIcon()); jAssetsLabel.setEnabled(false); jJobsLabel = new JLabel(); jJobsLabel.setDisabledIcon(Images.INCLUDE_JOBS.getIcon()); jJobsLabel.setEnabled(false); jOrdersLabel = new JLabel(); jOrdersLabel.setDisabledIcon(Images.INCLUDE_ORDERS.getIcon()); jOrdersLabel.setEnabled(false); jContractsLabel = new JLabel(); jContractsLabel.setDisabledIcon(Images.INCLUDE_CONTRACTS.getIcon()); jContractsLabel.setEnabled(false); //EDIT JDropDownButton jEdit = new JDropDownButton(TabsStockpile.get().editStockpileFilter(), Images.EDIT_EDIT_WHITE.getIcon()); jToolBar.addButton(jEdit); JMenuItem jRemove = new JMenuItem(TabsStockpile.get().remove(), Images.EDIT_DELETE.getIcon()); jRemove.setHorizontalAlignment(JButton.LEFT); jRemove.setActionCommand(StockpileDialogAction.REMOVE.name()); jRemove.addActionListener(listener); jEdit.add(jRemove); JMenuItem jClone = new JMenuItem(TabsStockpile.get().cloneStockpileFilter(), Images.EDIT_COPY.getIcon()); jClone.setHorizontalAlignment(JButton.LEFT); jClone.setActionCommand(StockpileDialogAction.CLONE.name()); jClone.addActionListener(listener); jEdit.add(jClone); //LOCATION OPTIONS JDropDownButton jOptions = new JDropDownButton(Images.DIALOG_SETTINGS.getIcon()); jOptions.setEnabled(locationType != LocationType.UNIVERSE); jMyLocations = new JCheckBoxMenuItem(TabsStockpile.get().myLocations()); jMyLocations.setActionCommand(StockpileDialogAction.FILTER_LOCATIONS.name()); jMyLocations.addActionListener(listener); jMyLocations.setSelected(!myLocations.isEmpty()); jMyLocations.setEnabled(!myLocations.isEmpty()); jOptions.add(jMyLocations); jOptions.addSeparator(); jStation = new JRadioButtonMenuItem(TabsStockpile.get().station(), Images.LOC_STATION.getIcon()); jStation.setHorizontalAlignment(JButton.LEFT); jStation.setActionCommand(StockpileDialogAction.CHANGE_LOCATION_TYPE.name()); jStation.addActionListener(listener); jOptions.add(jStation); jPlanet = new JRadioButtonMenuItem(TabsStockpile.get().planet(), Images.LOC_PLANET.getIcon()); jPlanet.setHorizontalAlignment(JButton.LEFT); jPlanet.setActionCommand(StockpileDialogAction.CHANGE_LOCATION_TYPE.name()); jPlanet.addActionListener(listener); jOptions.add(jPlanet); jSystem = new JRadioButtonMenuItem(TabsStockpile.get().system(), Images.LOC_SYSTEM.getIcon()); jSystem.setHorizontalAlignment(JButton.LEFT); jSystem.setActionCommand(StockpileDialogAction.CHANGE_LOCATION_TYPE.name()); jSystem.addActionListener(listener); jOptions.add(jSystem); jConstellation = new JRadioButtonMenuItem(TabsStockpile.get().constellation(), Images.LOC_CONSTELLATION.getIcon()); jConstellation.setHorizontalAlignment(JButton.LEFT); jConstellation.setActionCommand(StockpileDialogAction.CHANGE_LOCATION_TYPE.name()); jConstellation.addActionListener(listener); jOptions.add(jConstellation); jRegion = new JRadioButtonMenuItem(TabsStockpile.get().region(), Images.LOC_REGION.getIcon()); jRegion.setHorizontalAlignment(JButton.LEFT); jRegion.setActionCommand(StockpileDialogAction.CHANGE_LOCATION_TYPE.name()); jRegion.addActionListener(listener); jOptions.add(jRegion); jUniverse = new JRadioButtonMenuItem(TabsStockpile.get().universe(), Images.LOC_LOCATIONS.getIcon()); jUniverse.setHorizontalAlignment(JButton.LEFT); jUniverse.setActionCommand(StockpileDialogAction.CHANGE_LOCATION_TYPE.name()); jUniverse.addActionListener(listener); jOptions.add(jUniverse); ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(jPlanet); buttonGroup.add(jStation); buttonGroup.add(jSystem); buttonGroup.add(jConstellation); buttonGroup.add(jRegion); buttonGroup.add(jUniverse); jLocationType = new JLabel(); jLocationWarning = createToolTipLabel(Images.UPDATE_DONE_ERROR.getIcon(), TabsStockpile.get().noLocationsFound()); jLocationWarning.setVisible(false); jLocation = new JComboBox<>(); groupLayout.setHorizontalGroup( groupLayout.createParallelGroup() .addComponent(jToolBar, 0, 0, FIELD_WIDTH) .addGroup(groupLayout.createSequentialGroup() .addComponent(jLocationType) .addComponent(jLocationWarning) .addComponent(jLocation, 0, 0, FIELD_WIDTH) .addComponent(jOptions, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) ) .addComponent(jFilters) .addGroup(groupLayout.createSequentialGroup() .addComponent(jErrorLabel) .addComponent(jAssetsLabel) .addComponent(jJobsLabel) .addComponent(jOrdersLabel) .addComponent(jContractsLabel) ) ); groupLayout.setVerticalGroup( groupLayout.createSequentialGroup() .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addGroup(groupLayout.createParallelGroup() .addComponent(jLocationType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jLocationWarning, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jLocation, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOptions, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jFilters) .addGroup(groupLayout.createParallelGroup() .addComponent(jErrorLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jAssetsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jJobsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOrdersLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jContractsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } private void doLayout() { autoValidate(); jFilters.removeAll(); GroupLayout layout = new GroupLayout(jFilters); jFilters.setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(false); ParallelGroup horizontalGroup = layout.createParallelGroup(); SequentialGroup verticalGroup = layout.createSequentialGroup(); for (FilterPanel ownerPanel : ownerPanels) { horizontalGroup.addComponent(ownerPanel.getPanel()); verticalGroup.addComponent(ownerPanel.getPanel()); } for (FilterPanel flagPanel : flagPanels) { horizontalGroup.addComponent(flagPanel.getPanel()); verticalGroup.addComponent(flagPanel.getPanel()); } for (FilterPanel containerPanel : containerPanels) { horizontalGroup.addComponent(containerPanel.getPanel()); verticalGroup.addComponent(containerPanel.getPanel()); } if (singletonPanel != null) { horizontalGroup.addComponent(singletonPanel.getPanel()); verticalGroup.addComponent(singletonPanel.getPanel()); } if (jobsDaysPanel != null) { horizontalGroup.addComponent(jobsDaysPanel.getPanel()); verticalGroup.addComponent(jobsDaysPanel.getPanel()); } layout.setVerticalGroup(verticalGroup); layout.setHorizontalGroup(horizontalGroup); getDialog().pack(); } private void setLocationType(LocationType locationType) { this.locationType = locationType; boolean empty = false; if (locationType == LocationType.PLANET) { jLocationType.setIcon(Images.LOC_PLANET.getIcon()); jLocationType.setToolTipText(TabsStockpile.get().planet()); jPanel.setBorder(BorderFactory.createTitledBorder(TabsStockpile.get().planet())); try { planets.getReadWriteLock().readLock().lock(); empty = planets.isEmpty(); filterList = new FilterList<>(planets); } finally { planets.getReadWriteLock().readLock().unlock(); } jPlanet.setSelected(true); } else if (locationType == LocationType.STATION) { jLocationType.setIcon(Images.LOC_STATION.getIcon()); jLocationType.setToolTipText(TabsStockpile.get().station()); jPanel.setBorder(BorderFactory.createTitledBorder(TabsStockpile.get().station())); try { stations.getReadWriteLock().readLock().lock(); empty = stations.isEmpty(); filterList = new FilterList<>(stations); } finally { stations.getReadWriteLock().readLock().unlock(); } jStation.setSelected(true); } else if (locationType == LocationType.SYSTEM) { jLocationType.setIcon(Images.LOC_SYSTEM.getIcon()); jLocationType.setToolTipText(TabsStockpile.get().system()); jPanel.setBorder(BorderFactory.createTitledBorder(TabsStockpile.get().system())); try { systems.getReadWriteLock().readLock().lock(); empty = systems.isEmpty(); filterList = new FilterList<>(systems); } finally { systems.getReadWriteLock().readLock().unlock(); } jSystem.setSelected(true); } else if (locationType == LocationType.CONSTELLATION) { jLocationType.setIcon(Images.LOC_CONSTELLATION.getIcon()); jLocationType.setToolTipText(TabsStockpile.get().constellation()); jPanel.setBorder(BorderFactory.createTitledBorder(TabsStockpile.get().constellation())); try { constellations.getReadWriteLock().readLock().lock(); empty = constellations.isEmpty(); filterList = new FilterList<>(constellations); } finally { constellations.getReadWriteLock().readLock().unlock(); } jConstellation.setSelected(true); } else if (locationType == LocationType.REGION) { jLocationType.setIcon(Images.LOC_REGION.getIcon()); jLocationType.setToolTipText(TabsStockpile.get().region()); jPanel.setBorder(BorderFactory.createTitledBorder(TabsStockpile.get().region())); try { regions.getReadWriteLock().readLock().lock(); empty = regions.isEmpty(); filterList = new FilterList<>(regions); } finally { regions.getReadWriteLock().readLock().unlock(); } jRegion.setSelected(true); } else { jLocationType.setIcon(Images.LOC_LOCATIONS.getIcon()); jLocationType.setToolTipText(TabsStockpile.get().universe()); jPanel.setBorder(BorderFactory.createTitledBorder(TabsStockpile.get().universe())); EventList eventList = EventListManager.create(); try { eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(eventList); } finally { eventList.getReadWriteLock().readLock().unlock(); } jUniverse.setSelected(true); } if (autoComplete != null) { //Remove old jLocation.removeItemListener(listener); autoComplete.uninstall(); autoComplete = null; } if (locationType != LocationType.UNIVERSE) { if (empty) { jLocation.setEnabled(false); jLocation.getModel().setSelectedItem(TabsStockpile.get().noLocationsFound()); } else { jLocation.setEnabled(true); autoComplete = AutoCompleteSupport.install(jLocation, EventModels.createSwingThreadProxyList(filterList), new LocationFilterator()); autoComplete.setStrict(true); jLocation.addItemListener(listener); //Must be added after AutoCompleteSupport } } else { jLocation.setEnabled(false); jLocation.getModel().setSelectedItem(TabsStockpile.get().universe()); } } public JPanel getPanel() { return jPanel; } public StockpileFilter getFilter () { List ownerIDs = new ArrayList<>(); for (FilterPanel ownerPanel : ownerPanels) { ownerIDs.add(ownerPanel.getOwner()); } List flags = new ArrayList<>(); for (FilterPanel flagPanel : flagPanels) { flags.add(flagPanel.getFlag()); } List containers = new ArrayList<>(); for (FilterPanel containerPanel : containerPanels) { containers.add(containerPanel.getContainer()); } Object object = jLocation.getSelectedItem(); MyLocation location; if (object instanceof MyLocation) { location = (MyLocation) object; } else { location = MyLocation.create(0); } Boolean singleton; if (singletonPanel != null) { singleton = singletonPanel.getSingleton(); } else { singleton = null; } Integer jobsDaysLess = null; Integer jobsDaysMore = null; if (jobsDaysPanel != null) { jobsDaysLess = jobsDaysPanel.getJobsDaysLess(); jobsDaysMore = jobsDaysPanel.getJobsDaysMore(); } return new StockpileFilter(location, jMatchExclude.isSelected(), flags, containers, ownerIDs ,jobsDaysLess ,jobsDaysMore ,singleton ,jAssets.isSelected() ,jSellingOrders.isSelected() ,jBuyingOrders.isSelected() ,jJobs.isSelected() ,jBoughtTransactions.isSelected() ,jSoldTransactions.isSelected() ,jSellingContracts.isSelected() ,jSoldContracts.isSelected() ,jBuyingContracts.isSelected() ,jBoughtContracts.isSelected() ); } public boolean isValid() { boolean ok = true; Set owners = new HashSet<>(); for (FilterPanel ownerPanel : ownerPanels) { long owner = ownerPanel.getOwner(); boolean add = owners.add(owner); ownerPanel.warning(!add); if (!add) { ok = false; } } Set flags = new HashSet<>(); for (FilterPanel flagPanel : flagPanels) { StockpileFlag flag = flagPanel.getFlag(); boolean add = flags.add(flag); flagPanel.warning(!add); if (!add) { ok = false; } } Set containers = new HashSet<>(); for (FilterPanel containerPanel : containerPanels) { StockpileContainer container = containerPanel.getContainer(); boolean add = containers.add(container); containerPanel.warning(!add); if (!add) { ok = false; } } Object object = jLocation.getSelectedItem(); if (TabsStockpile.get().noLocationsFound().equals(object)) { ok = false; jLocationWarning.setVisible(true); } else { jLocationWarning.setVisible(false); } if (singletonPanel != null) { singletonPanel.warning(false); } if (jobsDaysPanel != null) { if (!jJobs.isSelected()) { jobsDaysPanel.warning(true); ok = false; } else { jobsDaysPanel.warning(false); } } else { jJobsDays.setEnabled(jJobs.isSelected()); } if (!jAssets.isSelected() && !jJobs.isSelected() && !jBuyingOrders.isSelected() && !jSellingOrders.isSelected() && !jBoughtTransactions.isSelected() && !jSoldTransactions.isSelected() && !jSellingContracts.isSelected() && !jBuyingContracts.isSelected() && !jSoldContracts.isSelected() && !jBoughtContracts.isSelected() ) { ok = false; jInclude.setIcon(Images.UPDATE_DONE_ERROR.getIcon()); ColorSettings.config(jInclude, ColorEntry.GLOBAL_ENTRY_INVALID); jErrorLabel.setVisible(true); } else { jInclude.setIcon(Images.LOC_INCLUDE.getIcon()); ColorSettings.configReset(jInclude); jErrorLabel.setVisible(false); } jAssetsLabel.setVisible(jAssets.isSelected()); jJobsLabel.setVisible(jJobs.isSelected()); int orders = 0; if (jBuyingOrders.isSelected()) { orders++; } if (jSellingOrders.isSelected()) { orders++; } if (jBoughtTransactions.isSelected()) { orders++; } if (jSoldTransactions.isSelected()) { orders++; } jOrdersLabel.setVisible(orders > 0); jOrdersLabel.setText(TabsStockpile.get().includeCount(orders)); int contracts = 0; if (jBuyingContracts.isSelected()) { contracts++; } if (jSellingContracts.isSelected()) { contracts++; } if (jBoughtContracts.isSelected()) { contracts++; } if (jSoldContracts.isSelected()) { contracts++; } jContractsLabel.setText(TabsStockpile.get().includeCount(contracts)); jContractsLabel.setVisible(contracts > 0); jMatch.setIcon(jMatchExclude.isSelected() ? Images.EDIT_DELETE_WHITE.getIcon() : Images.EDIT_ADD_WHITE.getIcon()); jAssets.setIcon(jAssets.isSelected() ? Images.INCLUDE_ASSETS_SELECTED.getIcon() : Images.INCLUDE_ASSETS.getIcon()); jJobs.setIcon(jJobs.isSelected() ? Images.INCLUDE_JOBS_SELECTED.getIcon() : Images.INCLUDE_JOBS.getIcon()); jBuyingOrders.setIcon(jBuyingOrders.isSelected() ? Images.INCLUDE_ORDERS_SELECTED.getIcon() : Images.INCLUDE_ORDERS.getIcon()); jSellingOrders.setIcon(jSellingOrders.isSelected() ? Images.INCLUDE_ORDERS_SELECTED.getIcon() : Images.INCLUDE_ORDERS.getIcon()); jBoughtTransactions.setIcon(jBoughtTransactions.isSelected() ? Images.INCLUDE_ORDERS_SELECTED.getIcon() : Images.INCLUDE_ORDERS.getIcon()); jSoldTransactions.setIcon(jSoldTransactions.isSelected() ? Images.INCLUDE_ORDERS_SELECTED.getIcon() : Images.INCLUDE_ORDERS.getIcon()); jSellingContracts.setIcon(jSellingContracts.isSelected() ? Images.INCLUDE_CONTRACTS_SELECTED.getIcon() : Images.INCLUDE_CONTRACTS.getIcon()); jBuyingContracts.setIcon(jBuyingContracts.isSelected() ? Images.INCLUDE_CONTRACTS_SELECTED.getIcon() : Images.INCLUDE_CONTRACTS.getIcon()); jBoughtContracts.setIcon(jBoughtContracts.isSelected() ? Images.INCLUDE_CONTRACTS_SELECTED.getIcon() : Images.INCLUDE_CONTRACTS.getIcon()); jSoldContracts.setIcon(jSoldContracts.isSelected() ? Images.INCLUDE_CONTRACTS_SELECTED.getIcon() : Images.INCLUDE_CONTRACTS.getIcon()); getDialog().pack(); return ok; } private void refilter() { Object object = jLocation.getSelectedItem(); MyLocation location; if (object instanceof MyLocation) { location = (MyLocation) object; } else { return; } if (jMyLocations.isSelected()) { filterList.setMatcher(new LocationsMatcher(myLocations)); } else { filterList.setMatcher(null); } if (EventListManager.contains(filterList, location)) { jLocation.setSelectedItem(location); } else if (!filterList.isEmpty()) { jLocation.setSelectedIndex(0); } } public void removeOwner(FilterPanel ownerPanel) { ownerPanels.remove(ownerPanel); doLayout(); } public void removeFlag(FilterPanel flagPanel) { flagPanels.remove(flagPanel); doLayout(); } public void removeContainer(FilterPanel containerPanel) { containerPanels.remove(containerPanel); doLayout(); } public void removeSingleton() { singletonPanel = null; jSingleton.setEnabled(true); doLayout(); } public void removeJobsDays() { jobsDaysPanel = null; jJobsDays.setEnabled(jJobs.isSelected()); doLayout(); } private void remove() { locationPanels.remove(this); updatePanels(); } private void newClone() { LocationPanel locationPanel = new LocationPanel(getFilter()); locationPanels.add(locationPanel); updatePanels(); } private void addOwner() { ownerPanels.add(new FilterPanel(this, FilterType.OWNER)); doLayout(); } private void addFlag() { flagPanels.add(new FilterPanel(this, FilterType.FLAG)); doLayout(); } private void addContainer() { containerPanels.add(new FilterPanel(this, FilterType.CONTAINER)); doLayout(); } private void addSingleton() { singletonPanel = new FilterPanel(this, FilterType.SINGLETON); doLayout(); jSingleton.setEnabled(false); singletonPanel.jSingleton.requestFocusInWindow(); } private void addJobsDays() { jobsDaysPanel = new FilterPanel(this, FilterType.JOBS_DAYS); doLayout(); jJobsDays.setEnabled(false); jobsDaysPanel.jJobsDays.requestFocusInWindow(); } private void changeLocationType() { if (jPlanet.isSelected()) { setLocationType(LocationType.PLANET); } else if (jStation.isSelected()) { setLocationType(LocationType.STATION); } else if (jSystem.isSelected()) { setLocationType(LocationType.SYSTEM); } else if (jConstellation.isSelected()) { setLocationType(LocationType.CONSTELLATION); } else if (jRegion.isSelected()) { setLocationType(LocationType.REGION); } else { setLocationType(LocationType.UNIVERSE); } refilter(); autoValidate(); } private class ListenerClass implements ActionListener, ItemListener { @Override public void actionPerformed(final ActionEvent e) { if (StockpileDialogAction.ADD_OWNER.name().equals(e.getActionCommand())) { addOwner(); } else if (StockpileDialogAction.ADD_FLAG.name().equals(e.getActionCommand())) { addFlag(); } else if (StockpileDialogAction.ADD_CONTAINER.name().equals(e.getActionCommand())) { addContainer(); } else if (StockpileDialogAction.ADD_SINGLETON.name().equals(e.getActionCommand())) { addSingleton(); } else if (StockpileDialogAction.ADD_JOBS_DAYS.name().equals(e.getActionCommand())) { addJobsDays(); } else if (StockpileDialogAction.FILTER_LOCATIONS.name().equals(e.getActionCommand())) { refilter(); } else if (StockpileDialogAction.VALIDATE.name().equals(e.getActionCommand())) { autoValidate(); } else if (StockpileDialogAction.REMOVE.name().equals(e.getActionCommand())) { remove(); } else if (StockpileDialogAction.CLONE.name().equals(e.getActionCommand())) { newClone(); } else if (StockpileDialogAction.CHANGE_LOCATION_TYPE.name().equals(e.getActionCommand())) { changeLocationType(); } } @Override public void itemStateChanged(final ItemEvent e) { autoValidate(); } } } private static class BorderPanel { private enum Alignment { HORIZONTAL, VERTICAL } private final GroupLayout layout; private final JPanel jPanel; private final List components = new ArrayList<>(); private final Alignment alignment; public BorderPanel(String title) { this(title, Alignment.HORIZONTAL); } public BorderPanel(String title, Alignment alignment) { this.alignment = alignment; jPanel = new JPanel(); layout = new GroupLayout(jPanel); jPanel.setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(false); jPanel.setBorder(BorderFactory.createTitledBorder(title)); } public void addGab(int size) { components.add(new BorderPanelGab(size)); doLayout(); } public void addGab(int min, int pref, int max) { components.add(new BorderPanelGab(min, pref, max)); doLayout(); } public void add(JComponent jComponent) { components.add(jComponent); doLayout(); } private void doLayout() { jPanel.removeAll(); Group horizontalGroup; Group verticalGroup; if (alignment == Alignment.HORIZONTAL) { horizontalGroup = layout.createSequentialGroup(); verticalGroup = layout.createParallelGroup(); } else { horizontalGroup = layout.createParallelGroup(); verticalGroup = layout.createSequentialGroup(); } for (JComponent component : components) { if (component instanceof BorderPanelGab) { BorderPanelGab gab = (BorderPanelGab) component; if (alignment == Alignment.HORIZONTAL) { gab.addGab(horizontalGroup); } else { gab.addGab(verticalGroup); } } else { horizontalGroup.addComponent(component); if (alignment == Alignment.HORIZONTAL) { verticalGroup.addComponent(component, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()); } else { verticalGroup.addComponent(component); } } } layout.setHorizontalGroup(horizontalGroup); layout.setVerticalGroup(verticalGroup); } public void setVisible(boolean aFlag) { jPanel.setVisible(aFlag); } public JPanel getPanel() { return jPanel; } } private static class BorderPanelGab extends JComponent { private final int min; private final int pref; private final int max; public BorderPanelGab(int size) { this(size, size, size); } public BorderPanelGab(int min, int pref, int max) { this.min = min; this.pref = pref; this.max = max; } public void addGab(Group group) { group.addGap(min, pref, max); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/stockpile/StockpileExtendedTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.stockpile; import java.util.Comparator; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.i18n.TabsStockpile; public enum StockpileExtendedTableFormat implements EnumTableColumn { STOCKPILE_NAME(String.class) { @Override public String getColumnName() { return TabsStockpile.get().getFilterStockpileName(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getStockpile().getName(); } }, STOCKPILE_OWNER(String.class) { @Override public String getColumnName() { return TabsStockpile.get().getFilterStockpileOwner(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getStockpile().getOwnerName(); } }, STOCKPILE_LOCATION(String.class) { @Override public String getColumnName() { return TabsStockpile.get().getFilterStockpileLocation(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getStockpile().getLocationName(); } }, STOCKPILE_FLAG(String.class) { @Override public String getColumnName() { return TabsStockpile.get().getFilterStockpileFlag(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getStockpile().getFlagName(); } }, STOCKPILE_CONTAINER(String.class) { @Override public String getColumnName() { return TabsStockpile.get().getFilterStockpileContainer(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getStockpile().getContainerName(); } }; private final Class type; private final Comparator comparator; private StockpileExtendedTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/stockpile/StockpileItemDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.stockpile; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.swing.AutoCompleteSupport; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.DefaultComboBoxModel; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.IndustryMaterial; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingFacility; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingRigs; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ReactionRigs; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingSecurity; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ReactionSecurity; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.EventModels.ItemFilterator; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.SubpileStock; import net.nikr.eve.jeveasset.i18n.TabsStockpile; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class StockpileItemDialog extends JDialogCentered { private enum StockpileItemAction { CANCEL, OK, TYPE_CHANGE } public static enum BlueprintAddType { NONE(TabsStockpile.get().none()), BPO(TabsStockpile.get().original()), BPC(TabsStockpile.get().copy()), RUNS(TabsStockpile.get().runs()), MANUFACTURING_MATERIALS(TabsStockpile.get().materialsManufacturing()), REACTION_MATERIALS(TabsStockpile.get().materialsReaction()), ; final String name; public static BlueprintAddType[] EMPTY = {NONE}; public static BlueprintAddType[] EDIT_BLUEPRINT = {BPO, BPC, RUNS}; public static BlueprintAddType[] EDIT_FORMULA = {BPO}; public static BlueprintAddType[] ADD_BLUEPRINT = {BPO, BPC, RUNS, MANUFACTURING_MATERIALS}; public static BlueprintAddType[] ADD_FORMULA = {BPO, REACTION_MATERIALS}; private BlueprintAddType(String name) { this.name = name; } @Override public String toString() { return name; } } private final JButton jOK; private final JComboBox jItems; private final JLabel jSubpile; private JTextField jCountMinimum; private final JLabel jBlueprintTypeLabel; private final JComboBox jBlueprintType; private final JComboBox jMe; private final JComboBox jFacility; private final JComboBox jRigs; private final JComboBox jRigsReactions; private final JComboBox jSecurity; private final JComboBox jSecurityReactions; private final JLabel jIgnoreMultiplierLabel; private final JCheckBox jIgnoreMultiplier; private final StockpileTab stockpileTab; private final List manufacturingComponents = new ArrayList<>(); private final List reactionComponents = new ArrayList<>(); private final EventList items = EventListManager.create(); private Stockpile stockpile; private StockpileItem stockpileItem; private List stockpileItems; private BlueprintAddType lastBlueprintAddType = null; private boolean updating = false; public StockpileItemDialog(final StockpileTab stockpileTab, final Program program) { super(program, TabsStockpile.get().addStockpileItem(), Images.TOOL_STOCKPILE.getImage()); this.stockpileTab = stockpileTab; ListenerClass listener = new ListenerClass(); JLabel jItemsLabel = new JLabel(TabsStockpile.get().item()); jItems = new JComboBox<>(); AutoCompleteSupport itemAutoComplete = AutoCompleteSupport.install(jItems, EventModels.createSwingThreadProxyList(items), new ItemFilterator()); itemAutoComplete.setStrict(true); jItems.addItemListener(listener); //Must be added after AutoCompleteSupport jSubpile = new JLabel(); JLabel jCountMinimumLabel = new JLabel(TabsStockpile.get().countMinimum()); jCountMinimum = new JTextField(); jCountMinimum.addFocusListener(new FocusAdapter() { @Override public void focusGained(final FocusEvent e) { jCountMinimum.selectAll(); } }); jCountMinimum.addCaretListener(listener); jIgnoreMultiplierLabel = new JLabel(TabsStockpile.get().multiplier()); jIgnoreMultiplier = new JCheckBox(TabsStockpile.get().multiplierIgnore()); jBlueprintTypeLabel = new JLabel(TabsStockpile.get().blueprintType()); jBlueprintType = new JComboBox<>(BlueprintAddType.values()); jBlueprintType.setActionCommand(StockpileItemAction.TYPE_CHANGE.name()); jBlueprintType.addActionListener(listener); JLabel jMeLabel = new JLabel(TabsStockpile.get().blueprintMe()); manufacturingComponents.add(jMeLabel); Integer[] me = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; jMe = new JComboBox<>(me); jMe.setPrototypeDisplayValue(10); jMe.setMaximumRowCount(me.length); manufacturingComponents.add(jMe); JLabel jFacilityLabel = new JLabel(TabsStockpile.get().blueprintFacility()); manufacturingComponents.add(jFacilityLabel); jFacility = new JComboBox<>(ManufacturingSettings.ManufacturingFacility.values()); jFacility.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ManufacturingFacility facility = jFacility.getItemAt(jFacility.getSelectedIndex()); if (facility == ManufacturingFacility.STATION) { jRigs.setSelectedIndex(0); jRigs.setEnabled(false); } else { jRigs.setEnabled(true); } } }); manufacturingComponents.add(jFacility); JLabel jRigsLabel = new JLabel(TabsStockpile.get().blueprintRigs()); manufacturingComponents.add(jRigsLabel); jRigs = new JComboBox<>(ManufacturingRigs.values()); jRigs.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ManufacturingRigs rigs = jRigs.getItemAt(jRigs.getSelectedIndex()); if (rigs == ManufacturingRigs.NONE) { jSecurity.setSelectedIndex(0); jSecurity.setEnabled(false); } else { jSecurity.setEnabled(true); } } }); manufacturingComponents.add(jRigs); JLabel jRigsReactionsLabel = new JLabel(TabsStockpile.get().blueprintRigs()); reactionComponents.add(jRigsReactionsLabel); jRigsReactions = new JComboBox<>(ReactionRigs.values()); jRigsReactions.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ReactionRigs rigs = jRigsReactions.getItemAt(jRigsReactions.getSelectedIndex()); if (rigs == ReactionRigs.NONE) { jSecurityReactions.setSelectedIndex(0); jSecurityReactions.setEnabled(false); } else { jSecurityReactions.setEnabled(true); } } }); reactionComponents.add(jRigsReactions); JLabel jSecurityLabel = new JLabel(TabsStockpile.get().blueprintSecurity()); manufacturingComponents.add(jSecurityLabel); jSecurity = new JComboBox<>(ManufacturingSecurity.values()); manufacturingComponents.add(jSecurity); JLabel jSecurityReactionsLabel = new JLabel(TabsStockpile.get().blueprintSecurity()); reactionComponents.add(jSecurityReactionsLabel); jSecurityReactions = new JComboBox<>(ReactionSecurity.values()); reactionComponents.add(jSecurityReactions); jOK = new JButton(TabsStockpile.get().ok()); jOK.setActionCommand(StockpileItemAction.OK.name()); jOK.addActionListener(listener); jOK.setEnabled(false); JButton jCancel = new JButton(TabsStockpile.get().cancel()); jCancel.setActionCommand(StockpileItemAction.CANCEL.name()); jCancel.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jItemsLabel) .addComponent(jBlueprintTypeLabel) .addComponent(jMeLabel) .addComponent(jFacilityLabel) .addComponent(jRigsLabel) .addComponent(jRigsReactionsLabel) .addComponent(jSecurityLabel) .addComponent(jSecurityReactionsLabel) .addComponent(jIgnoreMultiplierLabel) .addComponent(jCountMinimumLabel) ) .addGroup(layout.createParallelGroup() .addComponent(jItems, 300, 300, 300) .addComponent(jSubpile, 300, 300, 300) .addComponent(jBlueprintType, 300, 300, 300) .addComponent(jMe, 300, 300, 300) .addComponent(jFacility, 300, 300, 300) .addComponent(jRigs, 300, 300, 300) .addComponent(jRigsReactions, 300, 300, 300) .addComponent(jSecurity, 300, 300, 300) .addComponent(jSecurityReactions, 300, 300, 300) .addComponent(jIgnoreMultiplier, 300, 300, 300) .addComponent(jCountMinimum, 300, 300, 300) ) ) .addGroup(layout.createSequentialGroup() .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jItemsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jItems, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSubpile, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jBlueprintTypeLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jBlueprintType, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jMeLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jMe, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jFacilityLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFacility, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jRigsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRigs, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jRigsReactionsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRigsReactions, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jSecurityLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSecurity, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jSecurityReactionsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSecurityReactions, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jIgnoreMultiplierLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jIgnoreMultiplier, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jCountMinimumLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCountMinimum, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } protected StockpileItem showEdit(final StockpileItem editStockpileItem) { updateData(); this.stockpileItem = editStockpileItem; this.getDialog().setTitle(TabsStockpile.get().editStockpileItem()); Item item = ApiIdConverter.getItem(editStockpileItem.getTypeID()); if (editStockpileItem instanceof SubpileStock) { jSubpile.setText(editStockpileItem.getName()); jSubpile.setVisible(true); jBlueprintTypeLabel.setVisible(false); jBlueprintType.setVisible(false); jIgnoreMultiplierLabel.setVisible(false); jIgnoreMultiplier.setVisible(false); jItems.setVisible(false); } else { jItems.setSelectedItem(item); jSubpile.setVisible(false); jBlueprintTypeLabel.setVisible(true); jBlueprintType.setVisible(true); jIgnoreMultiplierLabel.setVisible(true); jIgnoreMultiplier.setVisible(true); jItems.setVisible(true); } if (item.isBlueprint()) { jBlueprintType.setModel(new DefaultComboBoxModel<>(BlueprintAddType.EDIT_BLUEPRINT)); } else if (item.isFormula()) { jBlueprintType.setModel(new DefaultComboBoxModel<>(BlueprintAddType.EDIT_FORMULA)); } else { jBlueprintType.setModel(new DefaultComboBoxModel<>(BlueprintAddType.EMPTY)); } if (editStockpileItem.isBPO()) { jBlueprintType.setSelectedItem(BlueprintAddType.BPO); } else if (editStockpileItem.isBPC()) { jBlueprintType.setSelectedItem(BlueprintAddType.BPC); } else if (editStockpileItem.isRuns()) { jBlueprintType.setSelectedItem(BlueprintAddType.RUNS); } jBlueprintType.setEnabled(item.isBlueprint()); jCountMinimum.setText(String.valueOf(editStockpileItem.getCountMinimum())); show(); return stockpileItem; } protected List showAdd(final Stockpile addStockpile) { updateData(); this.stockpile = addStockpile; this.getDialog().setTitle(TabsStockpile.get().addStockpileItem()); jBlueprintType.setModel(new DefaultComboBoxModel<>(BlueprintAddType.EMPTY)); show(); if (stockpileItems != null) { return stockpileItems; } else if (stockpileItem != null) { return Collections.singletonList(stockpileItem); } else { return null; } } private void updateData() { stockpile = null; stockpileItem = null; this.stockpileItems = null; List itemsList = new ArrayList<>(StaticData.get().getItems().values()); Collections.sort(itemsList); try { items.getReadWriteLock().writeLock().lock(); items.clear(); items.addAll(itemsList); } finally { items.getReadWriteLock().writeLock().unlock(); } jSubpile.setVisible(false); jItems.setVisible(true); jItems.setSelectedIndex(0); jCountMinimum.setText(""); jIgnoreMultiplier.setSelected(false); } private void show() { autoValidate(); autoSet(); super.setVisible(true); } private Stockpile getStockpile() { if (stockpile != null) { return stockpile; } else if (stockpileItem != null) { return stockpileItem.getStockpile(); } else { return null; } } private StockpileItem getStockpileItem() { Item item = (Item) jItems.getSelectedItem(); double countMinimum; try { countMinimum = Double.parseDouble(jCountMinimum.getText()); } catch (NumberFormatException ex) { countMinimum = 0; } boolean runs = jBlueprintType.isEnabled() && jBlueprintType.getItemAt(jBlueprintType.getSelectedIndex()) == BlueprintAddType.RUNS; boolean copy = runs || (jBlueprintType.isEnabled() && jBlueprintType.getItemAt(jBlueprintType.getSelectedIndex()) == BlueprintAddType.BPC); int typeID; if (copy) { typeID = -item.getTypeID(); } else { typeID = item.getTypeID(); } boolean ignoreMultiplier = jIgnoreMultiplier.isSelected(); return new StockpileItem(getStockpile(), item, typeID, countMinimum, runs, ignoreMultiplier); } private List getStockpileItems() { List itemsMaterial = new ArrayList<>(); Item item = (Item) jItems.getSelectedItem(); double countMinimum; try { countMinimum = Double.parseDouble(jCountMinimum.getText()); } catch (NumberFormatException ex) { countMinimum = 0; } boolean ignoreMultiplier = jIgnoreMultiplier.isSelected(); Integer me = jMe.getItemAt(jMe.getSelectedIndex()); ManufacturingFacility facility = jFacility.getItemAt(jFacility.getSelectedIndex()); ManufacturingRigs rigs = jRigs.getItemAt(jRigs.getSelectedIndex()); ReactionRigs rigsReactions = jRigsReactions.getItemAt(jRigsReactions.getSelectedIndex()); ManufacturingSecurity security = jSecurity.getItemAt(jSecurity.getSelectedIndex()); ReactionSecurity securityReactions = jSecurityReactions.getItemAt(jSecurityReactions.getSelectedIndex()); if (jBlueprintType.isEnabled() && jBlueprintType.getItemAt(jBlueprintType.getSelectedIndex()) == BlueprintAddType.MANUFACTURING_MATERIALS) { //Manufacturing Materials for (IndustryMaterial material : item.getManufacturingMaterials()) { Item materialItem = ApiIdConverter.getItem(material.getTypeID()); double count = ApiIdConverter.getManufacturingQuantity(material.getQuantity(), me, facility, rigs, security, countMinimum, false); itemsMaterial.add(new StockpileItem(getStockpile(), materialItem, material.getTypeID(), count, false, ignoreMultiplier)); } } else if (jBlueprintType.isEnabled() && jBlueprintType.getItemAt(jBlueprintType.getSelectedIndex()) == BlueprintAddType.REACTION_MATERIALS) { //Reaction Materials for (IndustryMaterial material : item.getReactionMaterials()) { Item materialItem = ApiIdConverter.getItem(material.getTypeID()); double count = ApiIdConverter.getReactionQuantity(material.getQuantity(), rigsReactions, securityReactions, countMinimum, false); itemsMaterial.add(new StockpileItem(getStockpile(), materialItem, material.getTypeID(), count, false, ignoreMultiplier)); } } else { return null; } return itemsMaterial; } private boolean itemExist() { return getExistingItem() != null; } private StockpileItem getExistingItem() { Object object = jItems.getSelectedItem(); if (object == null) { return null; } if (!(object instanceof Item)) { return null; } Item typeItem = (Item) object; Stockpile existing = getStockpile(); if (existing == null) { return null; } boolean materials = jBlueprintType.isEnabled() && (jBlueprintType.getItemAt(jBlueprintType.getSelectedIndex()) == BlueprintAddType.MANUFACTURING_MATERIALS || jBlueprintType.getItemAt(jBlueprintType.getSelectedIndex()) == BlueprintAddType.REACTION_MATERIALS); if (materials) { //Never exists return null; } boolean runs = jBlueprintType.isEnabled() && jBlueprintType.getItemAt(jBlueprintType.getSelectedIndex()) == BlueprintAddType.RUNS; boolean copy = runs || (jBlueprintType.isEnabled() && jBlueprintType.getItemAt(jBlueprintType.getSelectedIndex()) == BlueprintAddType.BPC); for (StockpileItem item : existing.getItems()) { if (item.getTypeID() == typeItem.getTypeID() && copy == item.isBPC() && runs == item.isRuns()) { return item; } } return null; } private void autoValidate() { if (updating) { return; } boolean oldUpdateValue = updating; updating = true; boolean valid = true; boolean colorIsSet = false; Object object = jItems.getSelectedItem(); if (object == null || !(object instanceof Item)) { valid = false; //No item selected } if (itemExist()) { //Editing existing item colorIsSet = true; ColorSettings.config(jCountMinimum, ColorEntry.GLOBAL_ENTRY_WARNING); } try { double d = Double.parseDouble(jCountMinimum.getText()); if (d <= 0) { valid = false; //Negative and zero is not valid colorIsSet = true; ColorSettings.config(jCountMinimum, ColorEntry.GLOBAL_ENTRY_INVALID); } } catch (NumberFormatException ex) { valid = false; //Empty and NaN is not valid if (!jCountMinimum.getText().isEmpty()) { colorIsSet = true; ColorSettings.config(jCountMinimum, ColorEntry.GLOBAL_ENTRY_INVALID); } } if (!colorIsSet) { ColorSettings.configReset(jCountMinimum); } jOK.setEnabled(valid); updating = oldUpdateValue; } private void autoSet() { if (jItems.getSelectedItem() == null || !(jItems.getSelectedItem() instanceof Item)) { jBlueprintType.setEnabled(false); jBlueprintType.setModel(new DefaultComboBoxModel<>(BlueprintAddType.EMPTY)); } else { Item item = (Item) jItems.getSelectedItem(); BlueprintAddType oldValue = jBlueprintType.getItemAt(jBlueprintType.getSelectedIndex()); if (stockpileItem != null) { //Can not add Materials if (item.isBlueprint()) { jBlueprintType.setModel(new DefaultComboBoxModel<>(BlueprintAddType.EDIT_BLUEPRINT)); jBlueprintType.setEnabled(true); } else if (item.isFormula()) { jBlueprintType.setModel(new DefaultComboBoxModel<>(BlueprintAddType.EDIT_FORMULA)); jBlueprintType.setEnabled(false); } else { jBlueprintType.setModel(new DefaultComboBoxModel<>(BlueprintAddType.EMPTY)); jBlueprintType.setEnabled(false); } } else if (!item.getManufacturingMaterials().isEmpty()) { jBlueprintType.setModel(new DefaultComboBoxModel<>(BlueprintAddType.ADD_BLUEPRINT)); jBlueprintType.setEnabled(true); } else if (!item.getReactionMaterials().isEmpty()) { jBlueprintType.setModel(new DefaultComboBoxModel<>(BlueprintAddType.ADD_FORMULA)); jBlueprintType.setEnabled(true); } else if (item.isBlueprint()) { jBlueprintType.setModel(new DefaultComboBoxModel<>(BlueprintAddType.EDIT_BLUEPRINT)); jBlueprintType.setEnabled(true); } else if (item.isFormula()) { jBlueprintType.setModel(new DefaultComboBoxModel<>(BlueprintAddType.EDIT_FORMULA)); jBlueprintType.setEnabled(true); } else { jBlueprintType.setModel(new DefaultComboBoxModel<>(BlueprintAddType.EMPTY)); jBlueprintType.setEnabled(false); } jBlueprintType.setSelectedItem(oldValue); } final StockpileItem item = getExistingItem(); if (item != null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (updating) { return; } boolean oldUpdateValue = updating; updating = true; jCountMinimum.setText(String.valueOf(item.getCountMinimum())); jIgnoreMultiplier.setSelected(item.isIgnoreMultiplier()); updating = oldUpdateValue; } }); } } @Override protected JComponent getDefaultFocus() { if (jItems.isEnabled()) { return jItems; } else { return jCountMinimum; } } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { } @Override protected void save() { Settings.lock("Stockpile (Items Dialog)"); //Lock for Stockpile (Items Dialog) if (stockpileItem instanceof SubpileStock) { //Edit SubpileStock SubpileStock subpileStock = (SubpileStock) stockpileItem; StockpileItem editItem = getStockpileItem(); subpileStock.setCountMinimum(editItem.getCountMinimum()); } else if (stockpileItem != null) { //EDIT if (itemExist()) { //EDIT + UPDATING (Editing to an existing item) StockpileItem existingItem = getExistingItem(); existingItem.getStockpile().remove(existingItem); stockpileTab.removeItem(existingItem); } stockpileItem.update(getStockpileItem()); } else if (itemExist()) { //UPDATING (Adding an existing item) stockpileItem = getExistingItem(); stockpileItem.update(getStockpileItem()); } else { //ADD stockpileItems = getStockpileItems(); if (stockpileItems != null) { for (StockpileItem item : stockpileItems) { if (!stockpile.add(item)) { //ADD MERGE (Only used by manufacturing materials) for (StockpileItem current : stockpile.getItems()) { if (!current.getTypeID().equals(item.getTypeID())) { continue; } current.setCountMinimum(item.getCountMinimum() + current.getCountMinimum()); break; } } } } else { stockpileItem = getStockpileItem(); stockpile.add(stockpileItem); } } Settings.unlock("Stockpile (Items Dialog)"); //Unlock for Stockpile (Items Dialog) program.saveSettings("Stockpile (Items Dialog)"); super.setVisible(false); } private class ListenerClass implements ActionListener, CaretListener, ItemListener { @Override public void actionPerformed(final ActionEvent e) { if (StockpileItemAction.OK.name().equals(e.getActionCommand())) { save(); } else if (StockpileItemAction.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); } else if (StockpileItemAction.TYPE_CHANGE.name().equals(e.getActionCommand())) { autoSet(); autoValidate(); BlueprintAddType currentBlueprintAddType = jBlueprintType.getItemAt(jBlueprintType.getSelectedIndex()); if (lastBlueprintAddType != currentBlueprintAddType) { if (lastBlueprintAddType == null) { for (JComponent jComponent : manufacturingComponents) { jComponent.setVisible(false); } for (JComponent jComponent : reactionComponents) { jComponent.setVisible(false); } } else { switch (lastBlueprintAddType) { case MANUFACTURING_MATERIALS: for (JComponent jComponent : manufacturingComponents) { jComponent.setVisible(false); } break; case REACTION_MATERIALS: for (JComponent jComponent : reactionComponents) { jComponent.setVisible(false); } break; } } if (jBlueprintType.isEnabled()) { switch (currentBlueprintAddType) { case MANUFACTURING_MATERIALS: for (JComponent jComponent : manufacturingComponents) { jComponent.setVisible(true); } jMe.setSelectedIndex(0); jFacility.setSelectedIndex(0); jRigs.setSelectedIndex(0); break; case REACTION_MATERIALS: for (JComponent jComponent : reactionComponents) { jComponent.setVisible(true); jComponent.setEnabled(true); } jRigsReactions.setSelectedIndex(0); jRigsReactions.setEnabled(true); break; } } getDialog().pack(); } lastBlueprintAddType = currentBlueprintAddType; } } @Override public void caretUpdate(final CaretEvent e) { autoValidate(); } @Override public void itemStateChanged(final ItemEvent e) { autoValidate(); autoSet(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/stockpile/StockpileSeparatorTableCell.java ================================================ /* Glazed Lists (c) 2003-2006 */ /* http://publicobject.com/glazedlists/ publicobject.com,*/ /* O'Dell Engineering Ltd.*/ package net.nikr.eve.jeveasset.gui.tabs.stockpile; import ca.odell.glazedlists.SeparatorList; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.JViewport; import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.DocumentFactory; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.components.JDoubleField; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.table.SeparatorTableCell; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.i18n.TabsStockpile; /** * * @author Jesse Wilson */ public class StockpileSeparatorTableCell extends SeparatorTableCell { public enum StockpileCellAction { GROUP_NEW, GROUP_CHANGE_ADD, GROUP_TOGGLE_COLLAPSE, GROUP_EXPAND, GROUP_RENAME, GROUP_SHOPPING_LIST, GROUP_COLLAPSE, DELETE_STOCKPILE, EDIT_STOCKPILE, CLONE_STOCKPILE, HIDE_STOCKPILE, SHOPPING_LIST_SINGLE, ADD_ITEM, SUBPILES, UPDATE_MULTIPLIER } private final static List jGroupMenuItems = new ArrayList<>(); private final JPanel jGroupPanel; private final JLabel jGroup; private final JMenu jGroupMenu; private final JMenuItem jGroupNew; private final JButton jExpandGroup; private final JButton jCollapseGroupStockpiles; private final JButton jExpandGroupStockpiles; private final JButton jRenameGroup; private final JButton jGroupShoppingList; private final JPanel jInfoPanel; private final JLabel jStartSpaceGroup; private final JLabel jStartSpace; private final JLabel jColor; private final JLabel jColorDisabled; private final JDropDownButton jStockpile; private final JDoubleField jMultiplier; private final JLabel jMultiplierLabel; private final JLabel jName; private final JLabel jAvailableLabel; private final JLabel jAvailable; private final JLabel jOwnerLabel; private final JLabel jOwner; private final JLabel jLocation; private final JLabel jLocationLabel; private final Program program; private final StockpileTab stockpileTab; private Component focusOwner; public StockpileSeparatorTableCell(final StockpileTab stockpileTab, final Program program, final JTable jTable, final SeparatorList separatorList, final ActionListener actionListener) { super(jTable, separatorList); this.program = program; this.stockpileTab = stockpileTab; ListenerClass listener = new ListenerClass(); addCellEditorListener(listener); jTable.addHierarchyListener(listener); jGroupPanel = new JPanel(); jGroupPanel.setBackground(Color.BLACK); GroupLayout groupLayout = new GroupLayout(jGroupPanel); jGroupPanel.setLayout(groupLayout); groupLayout.setAutoCreateGaps(false); groupLayout.setAutoCreateContainerGaps(false); jStartSpaceGroup = new JLabel(); jExpandGroup = new JButton(Images.MISC_COLLAPSED_WHITE.getIcon()); jExpandGroup.setOpaque(true); jExpandGroup.setContentAreaFilled(false); jExpandGroup.setBorder(EMPTY_TWO_PIXEL_BORDER); jExpandGroup.setBackground(Color.BLACK); jExpandGroup.setActionCommand(StockpileCellAction.GROUP_TOGGLE_COLLAPSE.name()); jExpandGroup.addActionListener(actionListener); jCollapseGroupStockpiles = new JButton(Images.MISC_COLLAPSED.getIcon()); jCollapseGroupStockpiles.setOpaque(false); jCollapseGroupStockpiles.setActionCommand(StockpileCellAction.GROUP_COLLAPSE.name()); jCollapseGroupStockpiles.addActionListener(actionListener); jExpandGroupStockpiles = new JButton(Images.MISC_EXPANDED.getIcon()); jExpandGroupStockpiles.setOpaque(false); jExpandGroupStockpiles.setActionCommand(StockpileCellAction.GROUP_EXPAND.name()); jExpandGroupStockpiles.addActionListener(actionListener); jRenameGroup = new JButton(Images.EDIT_EDIT_WHITE.getIcon()); jRenameGroup.setOpaque(false); jRenameGroup.setActionCommand(StockpileCellAction.GROUP_RENAME.name()); jRenameGroup.addActionListener(actionListener); jGroupShoppingList = new JButton(Images.STOCKPILE_SHOPPING_LIST.getIcon()); jGroupShoppingList.setOpaque(false); jGroupShoppingList.setActionCommand(StockpileCellAction.GROUP_SHOPPING_LIST.name()); jGroupShoppingList.addActionListener(actionListener); jGroup = new JLabel(); jGroup.setBorder(null); jGroup.setForeground(Color.WHITE); Font font = jGroup.getFont(); jGroup.setFont(new Font(font.getName(), Font.BOLD, font.getSize() + 1)); jGroup.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(final MouseEvent e) { if (e.getClickCount() >= 2) { actionListener.actionPerformed(new ActionEvent(jGroup, MouseEvent.MOUSE_RELEASED, StockpileCellAction.GROUP_TOGGLE_COLLAPSE.name())); } } }); groupLayout.setHorizontalGroup( groupLayout.createParallelGroup() .addGroup(groupLayout.createSequentialGroup() .addComponent(jStartSpaceGroup) .addComponent(jExpandGroup) .addGap(5) .addComponent(jCollapseGroupStockpiles, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) .addGap(5) .addComponent(jExpandGroupStockpiles, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) .addGap(5) .addComponent(jRenameGroup, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) .addGap(5) .addComponent(jGroupShoppingList, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) .addGap(10) .addComponent(jGroup, 0, 0, Integer.MAX_VALUE) ) ); groupLayout.setVerticalGroup( groupLayout.createSequentialGroup() .addGap(2) .addGroup(groupLayout.createParallelGroup() .addComponent(jStartSpaceGroup, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jExpandGroup, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCollapseGroupStockpiles, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jExpandGroupStockpiles, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jRenameGroup, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jGroupShoppingList, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jGroup, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGap(2) ); jInfoPanel = new JPanel(); jInfoPanel.setOpaque(false); GroupLayout infoLayout = new GroupLayout(jInfoPanel); jInfoPanel.setLayout(infoLayout); infoLayout.setAutoCreateGaps(false); infoLayout.setAutoCreateContainerGaps(false); jStartSpace = new JLabel(); jColor = new JLabel(); jColor.setOpaque(true); jColor.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); jColorDisabled = new JLabel(); jColorDisabled.setOpaque(false); jColorDisabled.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1)); jColorDisabled.setVisible(false); jMultiplier = new JDoubleField("1", DocumentFactory.ValueFlag.POSITIVE_AND_NOT_ZERO); jMultiplier.setAutoSelectAll(true); jMultiplier.setHorizontalAlignment(JTextField.RIGHT); jMultiplier.setActionCommand(StockpileCellAction.UPDATE_MULTIPLIER.name()); jMultiplier.addActionListener(listener); jMultiplier.addKeyListener(listener); jMultiplierLabel = new JLabel(TabsStockpile.get().multiplierSign()); jName = createLabel(""); //Available jAvailableLabel = createLabel(TabsStockpile.get().stockpileAvailable()); jAvailable = createLabel(); //Owner jOwnerLabel = createLabel(TabsStockpile.get().stockpileOwner()); jOwner = createLabel(); //Location jLocationLabel = createLabel(TabsStockpile.get().stockpileLocation()); jLocation = createLabel(); //Stockpile Edit/Add/etc. jStockpile = new JDropDownButton(TabsStockpile.get().stockpile()); jStockpile.setOpaque(false); jStockpile.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //Update when shown //Group Menu jGroupMenu.removeAll(); jGroupMenu.add(jGroupNew); if (!jGroupMenuItems.isEmpty()) { jGroupMenu.addSeparator(); } StockpileItem stockpileItem = (StockpileItem) currentSeparator.first(); if (stockpileItem == null) { // handle 'late' rendering calls after this separator is invalid return; } String group = stockpileItem.getGroup(); for (JCheckBoxMenuItem jMenuItem : jGroupMenuItems) { jMenuItem.setSelected(group.equals(jMenuItem.getText())); jGroupMenu.add(jMenuItem); } } }); JMenuItem jMenuItem; JMenuItem jAdd = new JMenuItem(TabsStockpile.get().addItem(), Images.EDIT_ADD.getIcon()); jAdd.setActionCommand(StockpileCellAction.ADD_ITEM.name()); jAdd.addActionListener(actionListener); jStockpile.add(jAdd); jStockpile.addSeparator(); jMenuItem = new JMenuItem(TabsStockpile.get().editStockpile(), Images.EDIT_EDIT.getIcon()); jMenuItem.setActionCommand(StockpileCellAction.EDIT_STOCKPILE.name()); jMenuItem.addActionListener(actionListener); jStockpile.add(jMenuItem); jMenuItem = new JMenuItem(TabsStockpile.get().cloneStockpile(), Images.EDIT_COPY.getIcon()); jMenuItem.setActionCommand(StockpileCellAction.CLONE_STOCKPILE.name()); jMenuItem.addActionListener(actionListener); jStockpile.add(jMenuItem); jMenuItem = new JMenuItem(TabsStockpile.get().hideStockpile(), Images.EDIT_SHOW.getIcon()); jMenuItem.setActionCommand(StockpileCellAction.HIDE_STOCKPILE.name()); jMenuItem.addActionListener(actionListener); jStockpile.add(jMenuItem); jMenuItem = new JMenuItem(TabsStockpile.get().deleteStockpile(), Images.EDIT_DELETE.getIcon()); jMenuItem.setActionCommand(StockpileCellAction.DELETE_STOCKPILE.name()); jMenuItem.addActionListener(actionListener); jStockpile.add(jMenuItem); jStockpile.addSeparator(); jGroupMenu = new JMenu(TabsStockpile.get().groupMenu()); jGroupMenu.setIcon(Images.FILTER_LOAD.getIcon()); jStockpile.add(jGroupMenu); jGroupNew = new JMenuItem(TabsStockpile.get().groupAddNew(), Images.EDIT_ADD.getIcon()); jGroupNew.setActionCommand(StockpileCellAction.GROUP_NEW.name()); jGroupNew.addActionListener(actionListener); jGroupMenu.add(jGroupNew); jStockpile.addSeparator(); JMenuItem jSubStockpile = new JMenuItem(TabsStockpile.get().subpiles(), Images.TOOL_STOCKPILE.getIcon()); jSubStockpile.setActionCommand(StockpileCellAction.SUBPILES.name()); jSubStockpile.addActionListener(actionListener); jStockpile.add(jSubStockpile); jStockpile.addSeparator(); jMenuItem = new JMenuItem(TabsStockpile.get().getShoppingList(), Images.STOCKPILE_SHOPPING_LIST.getIcon()); jMenuItem.setActionCommand(StockpileCellAction.SHOPPING_LIST_SINGLE.name()); jMenuItem.addActionListener(actionListener); jStockpile.add(jMenuItem); infoLayout.setHorizontalGroup( infoLayout.createParallelGroup() .addGroup(infoLayout.createSequentialGroup() .addComponent(jStartSpace) .addComponent(jExpand) .addGap(5) .addComponent(jColor, Program.getButtonsHeight() - 6, Program.getButtonsHeight() - 6, Program.getButtonsHeight() - 6) .addComponent(jColorDisabled, Program.getButtonsHeight() - 6, Program.getButtonsHeight() - 6, Program.getButtonsHeight() - 6) .addGap(10) .addComponent(jStockpile, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addGap(5) .addComponent(jMultiplier, 50, 50, 50) .addComponent(jMultiplierLabel) .addGap(10) .addComponent(jName, 150, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addGap(10) .addComponent(jAvailableLabel) .addGap(5) .addComponent(jAvailable, 30, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addGap(10) .addComponent(jOwnerLabel) .addGap(5) .addComponent(jOwner, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addGap(10) .addComponent(jLocationLabel) .addGap(5) .addComponent(jLocation, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ) ); infoLayout.setVerticalGroup( infoLayout.createSequentialGroup() .addGap(2) .addGroup(infoLayout.createParallelGroup() .addComponent(jStartSpace, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jExpand, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(infoLayout.createSequentialGroup() .addGap(3) .addComponent(jColor, Program.getButtonsHeight() - 6, Program.getButtonsHeight() - 6, Program.getButtonsHeight() - 6) .addComponent(jColorDisabled, Program.getButtonsHeight() - 6, Program.getButtonsHeight() - 6, Program.getButtonsHeight() - 6) ) .addComponent(jStockpile, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jMultiplier, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jMultiplierLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jName, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(infoLayout.createSequentialGroup() .addGap(4) .addGroup(infoLayout.createParallelGroup() .addComponent(jAvailableLabel) .addComponent(jAvailable) .addComponent(jOwnerLabel) .addComponent(jOwner) .addComponent(jLocationLabel) .addComponent(jLocation) ) ) ) .addGap(2) ); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(jGroupPanel) .addComponent(jInfoPanel) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jGroupPanel) .addComponent(jInfoPanel) ); updateGroups(actionListener); } public static void updateGroups(ActionListener actionListener) { Set groups = Settings.get().getStockpileGroupSettings().getGroups(); jGroupMenuItems.clear(); for (String g : groups) { if (g.isEmpty()) { continue; } JCheckBoxMenuItem jMenuItem = new JCheckBoxMenuItem(g); jMenuItem.setActionCommand(StockpileCellAction.GROUP_CHANGE_ADD.name()); jMenuItem.addActionListener(actionListener); jGroupMenuItems.add(jMenuItem); } } private JLabel createLabel() { return createLabel(null); } private JLabel createLabel(String text) { JLabel jLabel = new JLabel(); jLabel.setBorder(null); jLabel.setOpaque(false); //jLabel.setVerticalAlignment(SwingConstants.BOTTOM); if (text != null) { jLabel.setText(text); jLabel.setFont(new Font(jLabel.getFont().getName(), Font.BOLD, jLabel.getFont().getSize() + 1)); } return jLabel; } private void setEnabled(final boolean enabled) { if (!enabled) { //Save focus owner focusOwner = program.getMainWindow().getFrame().getFocusOwner(); } jExpandGroup.setEnabled(enabled); jCollapseGroupStockpiles.setEnabled(enabled); jExpandGroupStockpiles.setEnabled(enabled); jExpand.setEnabled(enabled); jColor.setVisible(enabled); jColorDisabled.setVisible(!enabled); jStockpile.setEnabled(enabled); jMultiplier.setEnabled(enabled); jMultiplierLabel.setEnabled(enabled); jName.setEnabled(enabled); jAvailableLabel.setEnabled(enabled); jAvailable.setEnabled(enabled); jOwnerLabel.setEnabled(enabled); jOwner.setEnabled(enabled); jLocation.setEnabled(enabled); jLocationLabel.setEnabled(enabled); if (enabled && focusOwner != null) { //Load focus owner focusOwner.requestFocusInWindow(); } } @Override protected void configure(final SeparatorList.Separator separator) { StockpileItem stockpileItem = (StockpileItem) separator.first(); if (stockpileItem == null) { // handle 'late' rendering calls after this separator is invalid return; } //Color if (Settings.get().isStockpileHalfColors()) { if (stockpileItem.getStockpile().getPercentFull() >= (Settings.get().getStockpileColorGroup3() / 100.0) ) { ColorSettings.config(jColor, ColorEntry.STOCKPILE_ICON_OVER_THRESHOLD); } else if (stockpileItem.getStockpile().getPercentFull() >= (Settings.get().getStockpileColorGroup2() / 100.0)) { ColorSettings.config(jColor, ColorEntry.STOCKPILE_ICON_BELOW_THRESHOLD_2ND); } else { ColorSettings.config(jColor, ColorEntry.STOCKPILE_ICON_BELOW_THRESHOLD); } } else { if (stockpileItem.getStockpile().getPercentFull() >= (Settings.get().getStockpileColorGroup2() / 100.0)) { ColorSettings.config(jColor, ColorEntry.STOCKPILE_ICON_OVER_THRESHOLD); } else { ColorSettings.config(jColor, ColorEntry.STOCKPILE_ICON_BELOW_THRESHOLD); } } //Group String group = stockpileItem.getGroup(); jGroup.setText(group); if (Settings.get().getStockpileGroupSettings().isGroupExpanded(group)) { jInfoPanel.setVisible(true); jExpandGroup.setIcon(Images.MISC_COLLAPSED_WHITE.getIcon()); } else { jInfoPanel.setVisible(false); jExpandGroup.setIcon(Images.MISC_EXPANDED_WHITE.getIcon()); } if (Settings.get().getStockpileGroupSettings().isGroupFirst(stockpileItem.getStockpile())) { jGroupPanel.setVisible(true); } else { jGroupPanel.setVisible(false); } //Multiplier jMultiplier.setText(Formatter.compareFormat(stockpileItem.getStockpile().getMultiplier())); //Name jName.setText(stockpileItem.getStockpile().getName()); //Available String available = Formatter.doubleFormat(stockpileItem.getStockpile().getPercentFull()); jAvailable.setText(available); //Owner String owner = stockpileItem.getStockpile().getOwnerName(); jOwner.setText(owner); //Location String location = stockpileItem.getStockpile().getLocationName(); jLocation.setText(location); } protected JViewport getParentViewport() { Container container = jTable.getParent(); if (container instanceof JViewport) { return (JViewport) container; } else { return null; } } @Override protected void expandSeparator(final boolean expand) { super.expandSeparator(expand); StockpileItem currentItem = (StockpileItem) currentSeparator.first(); if (currentItem == null) { // handle 'late' rendering calls after this separator is invalid return; } Settings.get().getStockpileGroupSettings().setStockpileExpanded(currentItem.getStockpile(), expand); } private class ListenerClass implements HierarchyListener, AdjustmentListener, ActionListener, CellEditorListener, KeyListener { private boolean update = true; @Override public void hierarchyChanged(final HierarchyEvent e) { if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) == HierarchyEvent.PARENT_CHANGED) { JViewport jViewport = getParentViewport(); if (jViewport != null) { Container container = getParentViewport().getParent(); if (container instanceof JScrollPane) { JScrollPane jScroll = (JScrollPane) container; //jScroll.getVerticalScrollBar().removeAdjustmentListener(this); jScroll.getHorizontalScrollBar().removeAdjustmentListener(this); //jScroll.getVerticalScrollBar().addAdjustmentListener(this); jScroll.getHorizontalScrollBar().addAdjustmentListener(this); } } } } @Override public void adjustmentValueChanged(final AdjustmentEvent e) { if (!e.getValueIsAdjusting()) { int position = getParentViewport().getViewPosition().x; jStartSpace.setMinimumSize(new Dimension(position, Program.getButtonsHeight())); jStartSpaceGroup.setMinimumSize(new Dimension(position, Program.getButtonsHeight())); setEnabled(true); jTable.repaint(); } else { if (jExpand.isEnabled()) { //Only do once setEnabled(false); jTable.repaint(); } } } @Override public void actionPerformed(ActionEvent e) { if (StockpileCellAction.UPDATE_MULTIPLIER.name().equals(e.getActionCommand())) { //Multiplier stopCellEditing(); } } @Override public void editingStopped(ChangeEvent e) { saveCount(); } @Override public void editingCanceled(ChangeEvent e) { saveCount(); } @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { update = false; stopCellEditing(); } } @Override public void keyReleased(KeyEvent e) { } private void saveCount() { if (!update) { update = true; return; } StockpileItem stockpileItem = (StockpileItem) currentSeparator.first(); if (stockpileItem == null) { // handle 'late' rendering calls after this separator is invalid return; } stockpileTab.setMultiplyer(stockpileItem.getStockpile(), jMultiplier); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/stockpile/StockpileShoppingListDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.stockpile; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.TreeSet; import javax.swing.DefaultListCellRenderer; import javax.swing.GroupLayout; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.ListCellRenderer; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.CopyHandler; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.shared.components.JIntegerField; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.SubpileStock; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.TypeIdentifier; import net.nikr.eve.jeveasset.i18n.TabsStockpile; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; class StockpileShoppingListDialog extends JDialogCentered { private static final Logger LOG = LoggerFactory.getLogger(StockpileShoppingListDialog.class); private enum StockpileShoppingListAction { CLIPBOARD_STOCKPILE, CLOSE, FORMAT_CHANGED } private static final DecimalFormat NUMBER = new DecimalFormat("0"); private final JTextArea jText; private final JButton jClose; private final JTextField jPercentFull; private final JTextField jPercentIgnore; private final JComboBox jFormat; private final JComboBox jOutput; private final Map outputData = new EnumMap<>(ShoppingListType.class); private List stockpiles; private boolean updating = false; StockpileShoppingListDialog(final Program program) { super(program, TabsStockpile.get().shoppingList(), Images.TOOL_STOCKPILE.getImage()); this.getDialog().setResizable(true); ListenerClass listener = new ListenerClass(); JButton jCopyToClipboard = new JButton(TabsStockpile.get().clipboardStockpile(), Images.EDIT_COPY.getIcon()); jCopyToClipboard.setActionCommand(StockpileShoppingListAction.CLIPBOARD_STOCKPILE.name()); jCopyToClipboard.addActionListener(listener); jFormat = new JComboBox<>(ShoppingListType.values()); jFormat.setRenderer(new IconListCellRendererRenderer()); jFormat.setActionCommand(StockpileShoppingListAction.FORMAT_CHANGED.name()); jFormat.addActionListener(listener); String[] types = {TabsStockpile.get().itemsMissing(), TabsStockpile.get().itemsRequired(), TabsStockpile.get().itemsOwned()}; jOutput = new JComboBox<>(types); jOutput.setActionCommand(StockpileShoppingListAction.FORMAT_CHANGED.name()); jOutput.addActionListener(listener); JLabel jFullLabel = new JLabel(TabsStockpile.get().percentFull()); JLabel jFullPercentLabel = new JLabel(TabsStockpile.get().percent()); jPercentFull = new JIntegerField(""); jPercentFull.addCaretListener(listener); JLabel jIgnoreLabel = new JLabel(TabsStockpile.get().percentIgnore()); JLabel jIgnorePercentLabel = new JLabel(TabsStockpile.get().percent()); jPercentIgnore = new JIntegerField(""); jPercentIgnore.addCaretListener(listener); jClose = new JButton(TabsStockpile.get().close()); jClose.setActionCommand(StockpileShoppingListAction.CLOSE.name()); jClose.addActionListener(listener); jText = new JTextArea(); jText.setEditable(false); jText.setFont(jPanel.getFont()); jText.setBackground(jPanel.getBackground()); JScrollPane jTextScroll = new JScrollPane(jText); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, false) .addComponent(jCopyToClipboard) .addComponent(jFormat) ) .addComponent(jOutput) .addGap(0, 0, Integer.MAX_VALUE) .addGroup(layout.createParallelGroup() .addComponent(jFullLabel) .addComponent(jIgnoreLabel) ) .addGroup(layout.createParallelGroup() .addComponent(jPercentFull, 100, 100, 100) .addComponent(jPercentIgnore, 100, 100, 100) ) .addGroup(layout.createParallelGroup() .addComponent(jFullPercentLabel) .addComponent(jIgnorePercentLabel) ) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(jTextScroll, 500, 500, Integer.MAX_VALUE) .addComponent(jClose) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jCopyToClipboard, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFullLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jPercentFull, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFullPercentLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jFormat, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOutput, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jIgnoreLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jPercentIgnore, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jIgnorePercentLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jTextScroll, 400, 400, Integer.MAX_VALUE) .addComponent(jClose, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ); } void show(final Stockpile stockpile) { show(Collections.singletonList(stockpile)); } void show(final List addStockpiles) { updating = true; this.stockpiles = addStockpiles; jPercentFull.setText("100"); jPercentIgnore.setText("100"); jFormat.setSelectedIndex(0); updateList(); updating = false; super.setVisible(true); } private void updateList() { //Multiplier long percent; try { percent = Long.parseLong(jPercentFull.getText()); if (percent <= 0) { percent = 100; } } catch (NumberFormatException e) { percent = 100; } long hide; try { hide = Long.parseLong(jPercentIgnore.getText()); if (hide <= 0) { hide = 100; } else if (hide > 100) { hide = 100; } } catch (NumberFormatException e) { hide = 100; } outputData.clear(); for (ShoppingListType type : ShoppingListType.values()) { outputData.put(type, new ShoppingListData(type)); } //All claims Map> claims = new HashMap<>(); Map subpiles = new HashMap<>(); StringBuilder stockpileNamesBuilder = new StringBuilder(); for (Stockpile stockpile : stockpiles) { stockpileNamesBuilder.append(Formatter.copyFormat(stockpile.getMultiplier())); stockpileNamesBuilder.append("x "); stockpileNamesBuilder.append(stockpile.getName()); stockpileNamesBuilder.append("\r\n"); Set contractIDs = null; Set assetsIDs = null; if (stockpile.isMatchAll()) { if (stockpile.isContracts()) { contractIDs = new HashSet<>(); Map> foundItems = StockpileData.contractsMatchAll(program.getProfileData(), stockpile, false); //Add for (MyContract contract : foundItems.keySet()) { contractIDs.add(contract.getContractID()); } } if (stockpile.isAssets()) { assetsIDs = new HashSet<>(); Map> foundItems = StockpileData.assetsMatchAll(program.getProfileData(), stockpile, false); //Add for (Map.Entry> entry : foundItems.entrySet()) { assetsIDs.add(entry.getKey().getItemID()); for (MyAsset asset : entry.getValue()) { assetsIDs.add(asset.getItemID()); } } } } for (SubpileStock stockpileItem : stockpile.getSubpileStocks()) { String key = stockpileItem.getName().trim(); double value = subpiles.getOrDefault(key, 0.0); subpiles.put(key, value + stockpileItem.getSubMultiplier()); } for (StockpileItem stockpileItem : stockpile.getClaims()) { TypeIdentifier type = stockpileItem.getType(); if (!type.isEmpty()) { //Ignore Total List claimList = claims.get(type); if (claimList == null) { claimList = new ArrayList<>(); claims.put(type, claimList); } claimList.add(new StockClaim(stockpileItem, contractIDs, assetsIDs, percent)); } } } StringBuilder subpileNamesBuilder = new StringBuilder(); for (Map.Entry entry : subpiles.entrySet()) { subpileNamesBuilder.append(Formatter.copyFormat(entry.getValue())); subpileNamesBuilder.append("x "); subpileNamesBuilder.append(entry.getKey()); subpileNamesBuilder.append("\r\n"); } for (ShoppingListData data : outputData.values()) { data.printHeader(stockpileNamesBuilder, subpileNamesBuilder, subpiles, percent); } //All items Map> items = new HashMap<>(); //Assets for (MyAsset asset : program.getAssetsList()) { if (asset.isGenerated()) { //Skip generated assets continue; } Integer typeID = StockpileData.get(asset.getTypeID(), asset.isBPC()); add(new TypeIdentifier(typeID, false), asset, claims, items); add(new TypeIdentifier(typeID, true), asset, claims, items); } //Market Orders for (MyMarketOrder marketOrder : program.getMarketOrdersList()) { add(new TypeIdentifier(marketOrder.getTypeID(), false), marketOrder, claims, items); } //Industry Jobs for (MyIndustryJob industryJob : program.getIndustryJobsList()) { //Manufacturing Integer productTypeID = industryJob.getProductTypeID(); if (productTypeID != null) { add(new TypeIdentifier(productTypeID, false), industryJob, claims, items); } //Copying add(new TypeIdentifier(-industryJob.getBlueprintTypeID(), true), industryJob, claims, items); } //Transactions for (MyTransaction transaction : program.getTransactionsList()) { add(new TypeIdentifier(transaction.getTypeID(), false), transaction, claims, items); } //ContractItems for (MyContractItem contractItem : program.getContractItemList()) { if (contractItem.getContract().isIgnoreContract()) { continue; } Integer typeID = StockpileData.get(contractItem.getTypeID(), contractItem.isBPC()); add(new TypeIdentifier(typeID, false), contractItem, claims, items); } //Owned before claming double ownedVolume = 0; double ownedValue = 0; for (Map.Entry> entry : items.entrySet()) { boolean bpc = false; boolean bpo = false; boolean runs = false; Item item; if (entry.getKey().isBPC()) { item = ApiIdConverter.getItem(Math.abs(entry.getKey().getTypeID())); bpc = true; runs = entry.getKey().isRuns(); } else { item = ApiIdConverter.getItem(entry.getKey().getTypeID()); bpo = item.isBlueprint(); } float volume = ApiIdConverter.getVolume(item, true); double price = ApiIdConverter.getPrice(entry.getKey().getTypeID(), bpc); long ownedCount = 0; for (StockItem stockItem : entry.getValue()) { Set counts = stockItem.getCounts(); if (counts.size() != 1) { LOG.error("StockpileShoppingListDialog counts size was: " + counts.size() + " expected: 1", new Exception()); } if (counts.isEmpty()) { continue; } Count count = counts.iterator().next(); //Required count ownedCount = ownedCount + count.getCount(); //Required volume ownedVolume = ownedVolume + (count.getCount() * volume); //Required value ownedValue = ownedValue + (count.getCount() * price); } for (ShoppingListData data : outputData.values()) { data.printOwned(ownedCount, item, bpc, bpo, runs); } } //Claim items for (Map.Entry> entry : items.entrySet()) { for (StockItem stockItem : entry.getValue()) { stockItem.claim(); } } //Show missing double missingVolume = 0; double missingValue = 0; double requiredVolume = 0; double requiredValue = 0; for (Map.Entry> entry : claims.entrySet()) { boolean bpc = false; boolean bpo = false; boolean runs = false; Item item; if (entry.getKey().isBPC()) { item = ApiIdConverter.getItem(Math.abs(entry.getKey().getTypeID())); bpc = true; runs = entry.getKey().isRuns(); } else { item = ApiIdConverter.getItem(entry.getKey().getTypeID()); bpo = item.isBlueprint(); } long missingCount = 0; long requiredCount = 0; for (StockClaim stockClaim : entry.getValue()) { if (stockClaim.getPercentFull() > hide) { continue; //Ignore everything above x% percent } //Missing count missingCount = missingCount + stockClaim.getCountMinimum(); //Missing volume (will add zero if nothing is needed) missingVolume = missingVolume + (stockClaim.getCountMinimum() * stockClaim.getVolume()); //Missing value (will add zero if nothing is needed) missingValue = missingValue + (stockClaim.getCountMinimum() * stockClaim.getDynamicPrice()); //Required count requiredCount = requiredCount + stockClaim.getTotalNeed(); //Required volume requiredVolume = requiredVolume + (stockClaim.getTotalNeed() * stockClaim.getVolume()); //Required value requiredValue = requiredValue + (stockClaim.getTotalNeed() * stockClaim.getDynamicPrice()); } for (ShoppingListData data : outputData.values()) { data.printMissing(missingCount, item, bpc, bpo, runs); data.printRequired(requiredCount, item, bpc, bpo, runs); } } for (ShoppingListData data : outputData.values()) { //Print sorted items data.printItems(); //Print footer data.printFooterMissing(missingVolume, missingValue); data.printFooterRequired(requiredVolume, requiredValue); data.printFooterOwned(ownedVolume, ownedValue); } setText(); } //Add claims to item private void add(final TypeIdentifier typeID, final Object object, final Map> claims, final Map> items) { //Get claims by typeID List minimumList = claims.get(typeID); if (minimumList == null) { //if no claims for typeID: return return; } //Get item list by typeID List itemList = items.get(typeID); if (itemList == null) { itemList = new ArrayList<>(); items.put(typeID, itemList); } StockItem stockItem = null; for (StockClaim stockMinimum : minimumList) { if (stockMinimum.isContractMatchAll() && object instanceof MyContractItem) { MyContractItem contractItem = (MyContractItem) object; if (!stockMinimum.getContractIDs().contains(contractItem.getContract().getContractID())) { continue; //Ignore none matching contracts } } if (stockMinimum.isAssetMatchAll() && object instanceof MyAsset) { MyAsset asset = (MyAsset) object; if (!stockMinimum.getAssetIDs().contains(asset.getItemID())) { continue; //Ignore none matching assets } } Long count = stockMinimum.matches(object); if (count != null && count != 0) { //if match (have claim) if (stockItem == null) { //if item not added already - add to items list stockItem = new StockItem(); itemList.add(stockItem); } stockItem.addClaim(stockMinimum, count); //Add claim } } } private void setText() { ShoppingListType type = jFormat.getItemAt(jFormat.getSelectedIndex()); Object output = jOutput.getSelectedItem(); ShoppingListData shoppingListData = outputData.get(type); if (shoppingListData != null) { jText.setText(shoppingListData.get(output)); } } @Override protected JComponent getDefaultFocus() { return jClose; } @Override protected JButton getDefaultButton() { return null; } @Override protected void windowShown() { } @Override protected void save() { } private class ListenerClass implements ActionListener, CaretListener { @Override public void actionPerformed(final ActionEvent e) { if (StockpileShoppingListAction.CLIPBOARD_STOCKPILE.name().equals(e.getActionCommand())) { CopyHandler.toClipboard(jText.getText()); } if (StockpileShoppingListAction.CLOSE.name().equals(e.getActionCommand())) { setVisible(false); } if (StockpileShoppingListAction.FORMAT_CHANGED.name().equals(e.getActionCommand())) { setText(); } } @Override public void caretUpdate(final CaretEvent e) { if (!updating) { updateList(); } } } private static class StockClaim implements Comparable{ private final StockpileItem stockpileItem; private final Set contractIDs; private final Set assetIDs; private final long totalNeed; private long countMinimum; private long available = 0; public StockClaim(StockpileItem stockpileItem, Set contractIDs, Set assetIDs, long percent) { this.stockpileItem = stockpileItem; this.contractIDs = contractIDs; this.assetIDs = assetIDs; this.totalNeed = (long)(stockpileItem.getCountMinimumMultiplied() * percent / 100.0); this.countMinimum = this.totalNeed; } public double getPercentFull() { return (totalNeed - countMinimum) * 100.0 / totalNeed ; } public double getVolume() { return stockpileItem.getVolume(); } public Double getDynamicPrice() { return stockpileItem.getDynamicPrice(); } private Long matches(Object object) { return stockpileItem.matches(object); } public long getTotalNeed() { return totalNeed; } public long getCountMinimum() { return countMinimum; } public void addCount(long count) { countMinimum = countMinimum - count; } public void addAvailable(long available) { this.available = this.available + available; } private long getNeed() { //Claim optimization return available - countMinimum; } public Set getContractIDs() { return contractIDs; } public Set getAssetIDs() { return assetIDs; } public boolean isContractMatchAll() { return contractIDs != null; } public boolean isAssetMatchAll() { return assetIDs != null; } public boolean isMatchAll() { return assetIDs != null || contractIDs != null; } @Override public int compareTo(StockClaim o) { if (this.isMatchAll() && !o.isMatchAll()) { return 1; } else if (!this.isMatchAll() && o.isMatchAll()) { return -1; } else if (this.getNeed() > o.getNeed()) { return 1; } else if (this.getNeed() < o.getNeed()) { return -1; } else { return 0; } } } private static class StockItem { private final Map> claims = new HashMap<>(); public StockItem() { } public void addClaim(StockClaim stockMinimum, long count) { List claimList = claims.get(new Count(count)); if (claimList == null) { claimList = new ArrayList<>(); claims.put(new Count(count), claimList); } claimList.add(stockMinimum); stockMinimum.addAvailable(count); } public Set getCounts() { return claims.keySet(); } public void claim() { for (Map.Entry> entry : claims.entrySet()) { List claimList = entry.getValue(); Count count = entry.getKey(); Collections.sort(claimList); //Sort by need for (StockClaim stockMinimum : claimList) { if (stockMinimum.getCountMinimum() >= count.getCount()) { //Add all stockMinimum.addCount(count.getCount()); count.takeAll(); break; } else { //Add part of the count long missing = stockMinimum.getCountMinimum(); stockMinimum.addCount(missing); count.take(missing); } } } } } private static class Count { private final long id; private long count; public Count(long count) { this.count = count; this.id = count; } public void takeAll() { count = 0; } public void take(long missing) { count = count - missing; } public long getCount() { return count; } @Override public int hashCode() { int hash = 5; hash = 67 * hash + (int) (this.id ^ (this.id >>> 32)); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Count other = (Count) obj; if (this.id != other.id) { return false; } return true; } } private static enum ShoppingListType { SHOPPING_LIST(TabsStockpile.get().shoppingList(), Images.STOCKPILE_SHOPPING_LIST.getIcon()){ @Override public void printHeader(StringBuilder stockpileNames, StringBuilder subpileNames, StringBuilder builder, Map subpiles, long percent) { //Add stockpile builder.append(TabsStockpile.get().stockpileShoppingList()); if (percent != 100) { //adds percent if it's not 100% builder.append(" ("); builder.append(percent); builder.append(TabsStockpile.get().percent()); builder.append(")"); } builder.append(":\r\n"); builder.append(stockpileNames.toString()); builder.append("\r\n"); //Add subpiles if (!subpiles.isEmpty()) { builder.append(TabsStockpile.get().subpileShoppingList()); builder.append("\r\n"); builder.append(subpileNames.toString()); builder.append("\r\n"); } builder.append(TabsStockpile.get().itemsShoppingList()); builder.append("\r\n"); } @Override public void printItem(StringBuilder builder, long count, Item item, boolean bpc, boolean bpo, boolean runs) { //Shopping List builder.append(Formatter.longFormat(count)); builder.append("x "); builder.append(item.getTypeName()); if (bpc) { if (runs) { builder.append(" (Runs)"); } else { builder.append(" (BPC)"); } } else if (bpo) { builder.append(" (BPO)"); } builder.append("\r\n"); } @Override public void printFooter(StringBuilder builder, double volume, double value, boolean empty) { if (empty) { //if string is empty, nothing is needed builder.append(TabsStockpile.get().nothingNeeded()); } else { //Add total volume and value builder.append("\r\n"); builder.append(TabsStockpile.get().totalToHaul()); builder.append(Formatter.doubleFormat(Math.abs(volume))); builder.append("\r\n"); builder.append(TabsStockpile.get().estimatedMarketValue()); builder.append(Formatter.iskFormat(Math.abs(value))); } } }, EVE_MULTIBUY(TabsStockpile.get().eveMultibuy(), Images.MISC_EVE.getIcon()){ @Override public void printItem(StringBuilder builder, long count, Item item, boolean bpc, boolean bpo, boolean runs) { //Multibuy builder.append(item.getTypeName()); builder.append(" "); builder.append(NUMBER.format(count)); builder.append("\r\n"); } }, CSV(TabsStockpile.get().csv(), Images.TABLE_COLUMN_RESIZE.getIcon()){ @Override public void printItem(StringBuilder builder, long count, Item item, boolean bpc, boolean bpo, boolean runs) { //CSV if (item.getTypeName().contains("\"") || item.getTypeName().contains(",")) { builder.append("\""); builder.append(item.getTypeName().replace("\"", "\"\"")); builder.append("\""); } else { builder.append(item.getTypeName()); } builder.append(","); builder.append(NUMBER.format(count)); builder.append("\r\n"); } }, SPREADSHEET(TabsStockpile.get().spreadsheet(), Images.TABLE_COLUMN_SHOW.getIcon()){ @Override public void printItem(StringBuilder builder, long count, Item item, boolean bpc, boolean bpo, boolean runs) { //CSV builder.append(item.getTypeName()); builder.append("\t"); builder.append(NUMBER.format(count)); builder.append("\r\n"); } }; private final String name; private final Icon icon; private ShoppingListType(String name, Icon icon) { this.name = name; this.icon = icon; } public Icon getIcon() { return icon; } @Override public String toString() { return name; } public void printHeader(StringBuilder stockpileNames, StringBuilder subpileNames, StringBuilder builder, Map subpiles, long percent) { } public abstract void printItem(StringBuilder builder, long count, Item item, boolean bpc, boolean bpo, boolean runs); public void printFooter(StringBuilder builder, double volume, double value, boolean empty) { } } private static class ShoppingListData { private final ShoppingListType type; private final Set missing = new TreeSet<>(); private final Set required = new TreeSet<>(); private final Set owned = new TreeSet<>(); private final StringBuilder missingBuilder = new StringBuilder(); private final StringBuilder requiredBuilder = new StringBuilder(); private final StringBuilder ownedBuilder = new StringBuilder(); private boolean missingEmpty = true; private boolean requiredEmpty = true; private boolean ownedEmpty = true; public ShoppingListData(ShoppingListType type) { this.type = type; } public String get(Object output) { if (TabsStockpile.get().itemsMissing().equals(output)) { return missingBuilder.toString(); } else if (TabsStockpile.get().itemsOwned().equals(output)) { return ownedBuilder.toString(); } else { return requiredBuilder.toString(); } } private void printOwned(long count, Item item, boolean bpc, boolean bpo, boolean runs) { if (count > 0) { ownedEmpty = false; owned.add(new ShoppingListDataEntry(count, item, bpc, bpo, runs)); } } private void printRequired(long count, Item item, boolean bpc, boolean bpo, boolean runs) { if (count > 0) { requiredEmpty = false; required.add(new ShoppingListDataEntry(count, item, bpc, bpo, runs)); } } private void printMissing(long count, Item item, boolean bpc, boolean bpo, boolean runs) { if (count > 0) { missingEmpty = false; missing.add(new ShoppingListDataEntry(count, item, bpc, bpo, runs)); } } private void printItems() { for (ShoppingListDataEntry entry : missing) { entry.print(type, missingBuilder); } for (ShoppingListDataEntry entry : required) { entry.print(type, requiredBuilder); } for (ShoppingListDataEntry entry : owned) { entry.print(type, ownedBuilder); } } private void printFooterOwned(double volume, double value) { type.printFooter(ownedBuilder, volume, value, ownedEmpty); } private void printFooterRequired(double volume, double value) { type.printFooter(requiredBuilder, volume, value, requiredEmpty); } private void printFooterMissing(double volume, double value) { type.printFooter(missingBuilder, volume, value, missingEmpty); } private void printHeader(StringBuilder stockpileNamesBuilder, StringBuilder subpileNamesBuilder, Map subpiles, long percent) { type.printHeader(stockpileNamesBuilder, subpileNamesBuilder, ownedBuilder, subpiles, percent); type.printHeader(stockpileNamesBuilder, subpileNamesBuilder, requiredBuilder, subpiles, percent); type.printHeader(stockpileNamesBuilder, subpileNamesBuilder, missingBuilder, subpiles, percent); } } private static class ShoppingListDataEntry implements Comparable { private final long count; private final Item item; private final boolean bpc; private final boolean bpo; private final boolean runs; public ShoppingListDataEntry(long count, Item item, boolean bpc, boolean bpo, boolean runs) { this.count = count; this.item = item; this.bpc = bpc; this.bpo = bpo; this.runs = runs; } public void print(ShoppingListType type, StringBuilder builder) { type.printItem(builder, count, item, bpc, bpo, runs); } @Override public int compareTo(ShoppingListDataEntry o) { int compared; /* //Sort by group first (defualt in the table) compared = item.getGroup().compareTo(o.item.getGroup()); if (compared != 0) { return compared; } */ compared = this.item.getTypeName().compareTo(o.item.getTypeName()); if (compared != 0) { return compared; } compared = Boolean.compare(this.bpc, o.bpc); if (compared != 0) { return compared; } compared = Boolean.compare(this.bpo, o.bpo); if (compared != 0) { return compared; } compared = Boolean.compare(this.runs, o.runs); if (compared != 0) { return compared; } return 0; } @Override public int hashCode() { int hash = 5; hash = 41 * hash + (int) (this.count ^ (this.count >>> 32)); hash = 41 * hash + Objects.hashCode(this.item); hash = 41 * hash + (this.bpc ? 1 : 0); hash = 41 * hash + (this.bpo ? 1 : 0); hash = 41 * hash + (this.runs ? 1 : 0); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ShoppingListDataEntry other = (ShoppingListDataEntry) obj; if (this.count != other.count) { return false; } if (this.bpc != other.bpc) { return false; } if (this.bpo != other.bpo) { return false; } if (this.runs != other.runs) { return false; } return Objects.equals(this.item, other.item); } } private static class IconListCellRendererRenderer implements ListCellRenderer { DefaultListCellRenderer renderer = new DefaultListCellRenderer(); @Override public Component getListCellRendererComponent(JList list, ShoppingListType value, int index, boolean isSelected, boolean cellHasFocus) { Component component = renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (component instanceof JLabel) { JLabel jLabel = (JLabel) component; jLabel.setIcon(value.getIcon()); } return component; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/stockpile/StockpileTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.stockpile; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.GlazedLists; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.DefaultComboBoxModel; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.SwingUtilities; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.tag.TagUpdate; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.JStatusLabel; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.InstantToolTip; import net.nikr.eve.jeveasset.gui.shared.JOptionInput; import net.nikr.eve.jeveasset.gui.shared.MarketDetailsColumn; import net.nikr.eve.jeveasset.gui.shared.MarketDetailsColumn.MarketDetailsActionListener; import net.nikr.eve.jeveasset.gui.shared.TextImport; import net.nikr.eve.jeveasset.gui.shared.TextImport.TextImportHandler; import net.nikr.eve.jeveasset.gui.shared.components.JAutoCompleteDialog; import net.nikr.eve.jeveasset.gui.shared.components.JCustomFileChooser; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.components.JMultiSelectionDialog; import net.nikr.eve.jeveasset.gui.shared.components.JOptionsDialog; import net.nikr.eve.jeveasset.gui.shared.components.JOptionsDialog.OptionEnum; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog.TextReturn; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.AutoNumberFormat; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuStockpile; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuStockpile.BpOptions; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuUI; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.ColumnValueChangeListener; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JSeparatorTable; import net.nikr.eve.jeveasset.gui.shared.table.PaddingTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileTotal; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.SubpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.SubpileStock; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileSeparatorTableCell.StockpileCellAction; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.i18n.TabsStockpile; import net.nikr.eve.jeveasset.io.local.EveFittingReader; import net.nikr.eve.jeveasset.io.local.SettingsReader; import net.nikr.eve.jeveasset.io.local.SettingsWriter; import net.nikr.eve.jeveasset.io.local.StockpileReader; import net.nikr.eve.jeveasset.io.local.StockpileWriter; import net.nikr.eve.jeveasset.io.local.text.TextImportType; import net.nikr.eve.jeveasset.io.shared.DesktopUtil.HelpLink; public class StockpileTab extends JMainTabSecondary implements TagUpdate { private enum StockpileAction { ADD_STOCKPILE, DELETE_STOCKPILE_MULTI, EDIT_GROUPS, SHOPPING_LIST_MULTI, SHOW_HIDE, IMPORT_TEXT, IMPORT_XML_TEXT, IMPORT_XML, IMPORT_EVE_XML_FIT, EXPORT_TEXT, EXPORT_XML, COLLAPSE, EXPAND, COLLAPSE_GROUPS, EXPAND_GROUPS, SUBPILE_TREE } public enum ImportOptions implements OptionEnum { KEEP() { @Override public String getText() { return TabsStockpile.get().importOptionsKeep(); } @Override public String getHelp() { return TabsStockpile.get().importOptionsKeepHelp(); } }, TEMPLATE() { @Override public String getText() { return TabsStockpile.get().importOptionsTemplate(); } @Override public String getHelp() { return TabsStockpile.get().importOptionsTemplateHelp(); } }, NEW() { @Override public String getText() { return TabsStockpile.get().importOptionsNew(); } @Override public String getHelp() { return TabsStockpile.get().importOptionsNewHelp(); } }, RENAME() { @Override public String getText() { return TabsStockpile.get().importOptionsRename(); } @Override public String getHelp() { return TabsStockpile.get().importOptionsRenameHelp(); } }, MERGE() { @Override public String getText() { return TabsStockpile.get().importOptionsMerge(); } @Override public String getHelp() { return TabsStockpile.get().importOptionsMergeHelp(); } }, OVERWRITE() { @Override public String getText() { return TabsStockpile.get().importOptionsOverwrite(); } @Override public String getHelp() { return TabsStockpile.get().importOptionsOverwriteHelp(); } }, ADD() { @Override public String getText() { return TabsStockpile.get().importOptionsAdd(); } @Override public String getHelp() { return TabsStockpile.get().importOptionsAddHelp(); } }, SKIP() { @Override public String getText() { return TabsStockpile.get().importOptionsSkip(); } @Override public String getHelp() { return TabsStockpile.get().importOptionsSkipHelp(); } }; private boolean all = false; @Override public boolean isAll() { return all; } @Override public void setAll(boolean all) { this.all = all; } } private static final MatchAllGroups MATCH_ALL_GROUPS = new MatchAllGroups(); //StatusBar private final JStatusLabel jVolumeNow; private final JStatusLabel jVolumeNeeded; private final JStatusLabel jValueNow; private final JStatusLabel jValueNeeded; //Dialogs private final JCustomFileChooser jFileChooser; private final StockpileDialog stockpileDialog; private final StockpileItemDialog stockpileItemDialog; private final StockpileShoppingListDialog stockpileShoppingListDialog; private final JMultiSelectionDialog stockpileSelectionDialog; private final JMultiSelectionDialog fitsSelectionDialog; private final JOptionsDialog stockpileImportDialog; private final JTextDialog jTextDialog; private final TextImport textImport; //Table private final JSeparatorTable jTable; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventTableModel tableModel; private final EventList eventList; private final FilterList filterList; private final SeparatorList separatorList; private final DefaultEventSelectionModel selectionModel; private final StockpileFilterControl filterControl; //Toolbar private final JFixedToolBar jToolBar; private final JCheckBoxMenuItem jShowSubpileTree; private final JDropDownButton jCollapse; private final JButton jCollapseGroup; private final JButton jExpandGroup; private final JButton jCollapseStockpile; private final JButton jExpandStockpile; private final JComboBox jOwners; private final DefaultComboBoxModel ownerModel; private final JAutoCompleteDialog jAutoCompleteDialog; //Data private final StockpileData stockpileData; private int toolBarMinWidth; private Stockpile template = null; private boolean collapsed = false; private static boolean updateFirstStockpileGroup = false; public static final String NAME = "stockpile"; //Not to be changed! public StockpileTab(final Program program) { super(program, NAME, TabsStockpile.get().stockpile(), Images.TOOL_STOCKPILE.getIcon(), true); stockpileData = new StockpileData(program); final ListenerClass listener = new ListenerClass(); jAutoCompleteDialog = new JAutoCompleteDialog<>(program, TabsStockpile.get().editGroup(), Images.EDIT_EDIT.getImage(), TabsStockpile.get().selectGroup(), false, false, JAutoCompleteDialog.STRING_OPTIONS); jFileChooser = new JCustomFileChooser("xml"); jFileChooser.setMultiSelectionEnabled(false); jFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); stockpileDialog = new StockpileDialog(program); stockpileItemDialog = new StockpileItemDialog(this, program); stockpileShoppingListDialog = new StockpileShoppingListDialog(program); stockpileSelectionDialog = new JMultiSelectionDialog<>(program, TabsStockpile.get().selectStockpiles()); fitsSelectionDialog = new JMultiSelectionDialog<>(program, TabsStockpile.get().selectFits()); stockpileImportDialog = new JOptionsDialog(program); jTextDialog = new JTextDialog(program.getMainWindow().getFrame()); textImport = new TextImport<>(program, NAME); jToolBar = new JFixedToolBar(); program.getMainWindow().getFrame().addComponentListener(new ComponentListener() { @Override public void componentResized(ComponentEvent e) { updateToolbar(); } @Override public void componentMoved(ComponentEvent e) { } @Override public void componentShown(ComponentEvent e) { updateToolbar(); } @Override public void componentHidden(ComponentEvent e) { } }); JButton jAdd = new JButton(TabsStockpile.get().newStockpile(), Images.LOC_GROUPS.getIcon()); jAdd.setActionCommand(StockpileAction.ADD_STOCKPILE.name()); jAdd.addActionListener(listener); jToolBar.addButton(jAdd); JDropDownButton jEdit = new JDropDownButton(TabsStockpile.get().edit(), Images.EDIT_EDIT.getIcon()); jToolBar.addButton(jEdit); JMenuItem jDelete = new JMenuItem(TabsStockpile.get().delete(), Images.EDIT_DELETE.getIcon()); jDelete.setActionCommand(StockpileAction.DELETE_STOCKPILE_MULTI.name()); jDelete.addActionListener(listener); jEdit.add(jDelete); JMenuItem jGroups = new JMenuItem(TabsStockpile.get().groups(), Images.FILTER_LOAD.getIcon()); jGroups.setActionCommand(StockpileAction.EDIT_GROUPS.name()); jGroups.addActionListener(listener); jEdit.add(jGroups); jToolBar.addSeparator(); JDropDownButton jShow = new JDropDownButton(TabsStockpile.get().showHide(), Images.EDIT_SHOW.getIcon()); jToolBar.addButton(jShow); JMenuItem jShowStockpiles = new JMenuItem(TabsStockpile.get().showStockpiles(), Images.TOOL_STOCKPILE.getIcon()); jShowStockpiles.setActionCommand(StockpileAction.SHOW_HIDE.name()); jShowStockpiles.addActionListener(listener); jShow.add(jShowStockpiles); jShowSubpileTree = new JCheckBoxMenuItem(TabsStockpile.get().showSubpileTree()); jShowSubpileTree.setSelected(Settings.get().isShowSubpileTree()); jShowSubpileTree.setActionCommand(StockpileAction.SUBPILE_TREE.name()); jShowSubpileTree.addActionListener(listener); jShow.add(jShowSubpileTree); jToolBar.addSeparator(); JButton jShoppingList = new JButton(TabsStockpile.get().getShoppingList(), Images.STOCKPILE_SHOPPING_LIST.getIcon()); jShoppingList.setActionCommand(StockpileAction.SHOPPING_LIST_MULTI.name()); jShoppingList.addActionListener(listener); jToolBar.addButton(jShoppingList); JDropDownButton jImport = new JDropDownButton(TabsStockpile.get().importButton(), Images.EDIT_IMPORT.getIcon()); jToolBar.addButton(jImport); JMenuItem jImportTextFormats = new JMenuItem(TabsStockpile.get().importText(), Images.STOCKPILE_SHOPPING_LIST.getIcon()); jImportTextFormats.setActionCommand(StockpileAction.IMPORT_TEXT.name()); jImportTextFormats.addActionListener(listener); jImport.add(jImportTextFormats); JMenuItem jImportEveXmlFit = new JMenuItem(TabsStockpile.get().importEveXml(), Images.MISC_XML.getIcon()); jImportEveXmlFit.setActionCommand(StockpileAction.IMPORT_EVE_XML_FIT.name()); jImportEveXmlFit.addActionListener(listener); jImport.add(jImportEveXmlFit); JMenuItem jImportXml = new JMenuItem(TabsStockpile.get().importStockpilesXml(), Images.TOOL_STOCKPILE.getIcon()); jImportXml.setActionCommand(StockpileAction.IMPORT_XML.name()); jImportXml.addActionListener(listener); jImport.add(jImportXml); JMenuItem jImportText = new JMenuItem(TabsStockpile.get().importStockpilesText(), Images.EDIT_COPY.getIcon()); jImportText.setActionCommand(StockpileAction.IMPORT_XML_TEXT.name()); jImportText.addActionListener(listener); jImport.add(jImportText); JMenuItem jExportXml = new JMenuItem(TabsStockpile.get().exportStockpilesXml(), Images.TOOL_STOCKPILE.getIcon()); jExportXml.setActionCommand(StockpileAction.EXPORT_XML.name()); jExportXml.addActionListener(listener); JMenuItem jExportText = new JMenuItem(TabsStockpile.get().exportStockpilesText(), Images.EDIT_COPY.getIcon()); jExportText.setActionCommand(StockpileAction.EXPORT_TEXT.name()); jExportText.addActionListener(listener); jToolBar.addSeparator(); jToolBar.addSpace(5); ownerModel = new DefaultComboBoxModel<>(); jOwners = new JComboBox<>(ownerModel); jToolBar.add(jOwners, 150); jToolBar.addSpace(1); JLabel jOwnerLabel = new JLabel(Images.MISC_HELP.getIcon()); jOwnerLabel.setToolTipText(TabsStockpile.get().marketDetailsOwnerToolTip()); InstantToolTip.install(jOwnerLabel); jToolBar.addLabelIcon(jOwnerLabel); jToolBar.addSeparator(); jToolBar.addGlue(); jCollapse = new JDropDownButton(TabsStockpile.get().collapse(), Images.MISC_COLLAPSE.getIcon()); jToolBar.addButton(jCollapse); JMenuItem jCollapseStockpileMenuItem = new JMenuItem(TabsStockpile.get().collapse(), Images.MISC_COLLAPSED.getIcon()); jCollapseStockpileMenuItem.setActionCommand(StockpileAction.COLLAPSE.name()); jCollapseStockpileMenuItem.addActionListener(listener); jCollapse.add(jCollapseStockpileMenuItem); JMenuItem jExpandStockpileMenuItem = new JMenuItem(TabsStockpile.get().expand(), Images.MISC_EXPANDED.getIcon()); jExpandStockpileMenuItem.setActionCommand(StockpileAction.EXPAND.name()); jExpandStockpileMenuItem.addActionListener(listener); jCollapse.add(jExpandStockpileMenuItem); JMenuItem jCollapseGroupMenuItem = new JMenuItem(TabsStockpile.get().groupCollapse(), Images.MISC_COLLAPSED.getIcon()); jCollapseGroupMenuItem.setActionCommand(StockpileAction.COLLAPSE_GROUPS.name()); jCollapseGroupMenuItem.addActionListener(listener); jCollapse.add(jCollapseGroupMenuItem); JMenuItem jExpandGroupMenuItem = new JMenuItem(TabsStockpile.get().groupExpand(), Images.MISC_EXPANDED.getIcon()); jExpandGroupMenuItem.setActionCommand(StockpileAction.EXPAND_GROUPS.name()); jExpandGroupMenuItem.addActionListener(listener); jCollapse.add(jExpandGroupMenuItem); jCollapseGroup = new JButton(TabsStockpile.get().groupCollapse(), Images.MISC_COLLAPSED.getIcon()); jCollapseGroup.setActionCommand(StockpileAction.COLLAPSE_GROUPS.name()); jCollapseGroup.addActionListener(listener); jExpandGroup = new JButton(TabsStockpile.get().groupExpand(), Images.MISC_EXPANDED.getIcon()); jExpandGroup.setActionCommand(StockpileAction.EXPAND_GROUPS.name()); jExpandGroup.addActionListener(listener); jCollapseStockpile = new JButton(TabsStockpile.get().collapse(), Images.MISC_COLLAPSED.getIcon()); jCollapseStockpile.setActionCommand(StockpileAction.COLLAPSE.name()); jCollapseStockpile.addActionListener(listener); jExpandStockpile = new JButton(TabsStockpile.get().expand(), Images.MISC_EXPANDED.getIcon()); jExpandStockpile.setActionCommand(StockpileAction.EXPAND.name()); jExpandStockpile.addActionListener(listener); //Table Format tableFormat = TableFormatFactory.stockpileTableFormat(); tableFormat.addListener(listener); //Backend eventList = EventListManager.create(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedListColumn = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Sorting Total (Ensure that total is always last) eventList.getReadWriteLock().readLock().lock(); SortedList sortedListTotal = new SortedList<>(sortedListColumn, new TotalComparator()); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedListTotal); eventList.getReadWriteLock().readLock().unlock(); filterList.addListEventListener(listener); //Separator separatorList = new SeparatorList<>(filterList, new StockpileSeparatorComparator(), 1, Integer.MAX_VALUE); separatorList.addListEventListener(new ListEventListener() { @Override public void listChanged(ListEvent listChanges) { updateGroupFirst(); } }); //Table Model tableModel = EventModels.createTableModel(separatorList, tableFormat); //Table jTable = new JStockpileTable(program, tableModel, separatorList); jTable.setSeparatorRenderer(new StockpileSeparatorTableCell(this, program, jTable, separatorList, listener)); jTable.setSeparatorEditor(new StockpileSeparatorTableCell(this, program, jTable, separatorList, listener)); jTable.setCellSelectionEnabled(true); //Padding PaddingTableCellRenderer.install(jTable, 3); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedListColumn, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(separatorList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Market Details MarketDetailsColumn.install(eventList, new MarketDetailsActionListener() { @Override public void openMarketDetails(StockpileItem stockpileItem) { if (!jOwners.isEnabled()) { return; } EsiOwner esiOwner = jOwners.getItemAt(jOwners.getSelectedIndex()); JMenuUI.openMarketDetails(program, esiOwner, stockpileItem.getTypeID(), false); } }); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Filter GUI filterControl = new StockpileFilterControl(sortedListTotal); filterControl.addExportOption(jExportXml); filterControl.addExportOption(jExportText); filterControl.setManualLink(new HelpLink("https://wiki.jeveassets.org/manual/stockpile", GuiShared.get().helpStockpile()), getIcon()); //Menu installTableTool(new StockpileTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, StockpileItem.class); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(filterControl.getPanel()) .addComponent(jToolBar, jToolBar.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); jVolumeNow = StatusPanel.createLabel(TabsStockpile.get().shownVolumeNow(), Images.ASSETS_VOLUME.getIcon(), AutoNumberFormat.DOUBLE); this.addStatusbarLabel(jVolumeNow); jValueNow = StatusPanel.createLabel(TabsStockpile.get().shownValueNow(), Images.TOOL_VALUES.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jValueNow); jVolumeNeeded = StatusPanel.createLabel(TabsStockpile.get().shownVolumeNeeded(), Images.ASSETS_VOLUME.getIcon(), AutoNumberFormat.DOUBLE); this.addStatusbarLabel(jVolumeNeeded); jValueNeeded = StatusPanel.createLabel(TabsStockpile.get().shownValueNeeded(), Images.TOOL_VALUES.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jValueNeeded); } @Override public void updateData() { //Save separator expanded/collapsed state jTable.saveExpandedState(); //Update Data stockpileData.updateData(eventList); //Restore separator expanded/collapsed state jTable.loadExpandedState(); //Update owner combobox ownerModel.removeAllElements(); for (EsiOwner owner : program.getProfileManager().getEsiOwners()) { if (owner.isOpenWindows()) { ownerModel.addElement(owner); } } jOwners.setEnabled(ownerModel.getSize() > 0); } private void updateOwners() { //Update Owners stockpileData.updateOwners(); } private void updateSubpile(Stockpile stockpile) { //Save separator expanded/collapsed state jTable.saveExpandedState(); //Update Data stockpileData.updateSubpile(eventList, stockpile); //Restore separator expanded/collapsed state jTable.loadExpandedState(); } private void updateStockpile(Stockpile stockpile) { //Update Data stockpileData.updateStockpile(stockpile); } @Override public void clearData() { try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); } finally { eventList.getReadWriteLock().writeLock().unlock(); } filterControl.clearCache(); } @Override public void updateCache() { filterControl.createCache(); } @Override public Collection getLocations() { return new ArrayList<>(); //LocationsType } /** * Needs to be updated before the stockpile tab is shown (for TableMenu > Add */ public void updateStockpileDialog() { stockpileDialog.updateData(); } /** * @param stockpile Stockpile to add item to * @param item Item to add to stockpile * @param merge True: Add new and old item count. False: Skip the new item if it exist * @param saveOnChange Save settings when done * @return */ public Stockpile addToStockpile(Stockpile stockpile, StockpileItem item, boolean merge, boolean saveOnChange) { return addToStockpile(stockpile, Collections.singletonList(item), merge, saveOnChange); } /** * * @param stockpile Stockpile to add item to * @param items Items to add to stockpile * @param merge True: Add new and old item count. False: Skip new items if they exist * @param saveOnChange Save settings when done * @return */ public Stockpile addToStockpile(Stockpile stockpile, Collection items, boolean merge, boolean saveOnChange) { updateOwners(); if (stockpile == null) { //new stockpile stockpile = stockpileDialog.showAdd(); } if (stockpile != null) { //Add items removeStockpile(stockpile); boolean save = false; for (StockpileItem fromItem : items) { //Clone item StockpileItem toItem = null; //Search for existing for (StockpileItem item : stockpile.getItems()) { if (item.getItemTypeID() == fromItem.getItemTypeID() && item.isRuns() == fromItem.isRuns()) { toItem = item; break; } } if (toItem != null) { //Update existing (add counts) if (merge) { save = true; Settings.lock("Stockpile (addTo - Merge)"); //Lock for Stockpile (addTo - Merge) toItem.addCountMinimum(fromItem.getCountMinimum()); Settings.unlock("Stockpile (addTo - Merge)"); //Unlock for Stockpile (addTo - Merge) } } else { //Add new save = true; Settings.lock("Stockpile (addTo - New)"); //Lock for Stockpile (addTo - New) StockpileItem item = new StockpileItem(stockpile, fromItem); stockpile.add(item); Settings.unlock("Stockpile (addTo - New)"); //Unlock for Stockpile (addTo - New) } } if (save && saveOnChange) { program.saveSettings("Stockpile (addTo)"); //Save Stockpile (Merge); } addStockpile(stockpile); } return stockpile; } private void updateToolbar() { if (toolBarMinWidth == 0) { jToolBar.remove(jCollapse); jToolBar.addButton(jCollapseGroup); jToolBar.addButton(jExpandGroup); jToolBar.addButton(jCollapseStockpile); jToolBar.addButton(jExpandStockpile); toolBarMinWidth = jToolBar.getPreferredSize().width; collapsed = false; } int width = jToolBar.getVisibleRect().width; if (collapsed && width >= toolBarMinWidth) { collapsed = false; jToolBar.remove(jCollapse); jToolBar.addButton(jCollapseGroup); jToolBar.addButton(jExpandGroup); jToolBar.addButton(jCollapseStockpile); jToolBar.addButton(jExpandStockpile); } else if (!collapsed && width < toolBarMinWidth){ collapsed = true; jToolBar.remove(jCollapseGroup); jToolBar.remove(jExpandGroup); jToolBar.remove(jCollapseStockpile); jToolBar.remove(jExpandStockpile); jToolBar.addButton(jCollapse); } } private SeparatorList.Separator getSeparator(final Stockpile stockpile) { try { separatorList.getReadWriteLock().readLock().lock(); for (int i = 0; i < separatorList.size(); i++) { Object object = separatorList.get(i); if (object instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) object; Object first = separator.first(); if (first instanceof StockpileItem) { StockpileItem firstItem = (StockpileItem) first; if (firstItem.getStockpile().equals(stockpile)) { return separator; } } } } } finally { separatorList.getReadWriteLock().readLock().unlock(); } return null; } public void scrollToSctockpile(final Stockpile stockpile) { SeparatorList.Separator separator = getSeparator(stockpile); if (separator == null) { return; } if (separator.getLimit() > 0) { //Expanded: Scroll int row = EventListManager.indexOf(separatorList, separator.first()) - 1; Rectangle rect = jTable.getCellRect(row, 0, true); rect.setSize(jTable.getVisibleRect().getSize()); jTable.scrollRectToVisible(rect); } else { //Collapsed: Expand and run again... try { separatorList.getReadWriteLock().writeLock().lock(); separator.setLimit(Integer.MAX_VALUE); } finally { separatorList.getReadWriteLock().writeLock().unlock(); } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { scrollToSctockpile(stockpile); } }); } } @Override public void updateTags() { beforeUpdateData(); tableModel.fireTableDataChanged(); filterControl.refilter(); afterUpdateData(); } protected void setMultiplyer(Stockpile stockpile, JTextField jMultiplier) { if (stockpile == null) { return; } double multiplier; try { multiplier = Double.parseDouble(jMultiplier.getText()); } catch (NumberFormatException ex) { multiplier = 1; } if (multiplier != stockpile.getMultiplier()) { stockpile.setMultiplier(multiplier); stockpile.updateTotal(); program.saveSettings("Stockpile: Multiplier changed"); tableModel.fireTableDataChanged(); } } protected void editItem(StockpileItem item) { StockpileItem editItem = stockpileItemDialog.showEdit(item); if (editItem != null) { addToStockpile(editItem.getStockpile(), editItem, false, true); } } protected void removeItem(StockpileItem item) { removeItems(Collections.singletonList(item)); } protected void removeItems(Collection items) { Set stockpiles = new HashSet<>(); for (StockpileItem item : items) { item.getStockpile().updateTotal(); stockpiles.add(item.getStockpile()); } if (!items.isEmpty()) { updateSubpile(items.iterator().next().getStockpile()); } for (Stockpile stockpile : stockpiles) { if (stockpile.isMatchAll()) { //Less items == may match now... updateStockpile(stockpile); } } //Lock Table beforeUpdateData(); //Update list try { eventList.getReadWriteLock().writeLock().lock(); enableGroupFirstUpdate(); eventList.removeAll(items); } finally { eventList.getReadWriteLock().writeLock().unlock(); } //Unlcok Table afterUpdateData(); } public void addStockpile(Stockpile stockpile) { if (stockpile == null) { return; } updateStockpile(stockpile); updateSubpile(stockpile); //Lock Table beforeUpdateData(); //Update list try { eventList.getReadWriteLock().writeLock().lock(); enableGroupFirstUpdate(); eventList.addAll(stockpile.getItems()); } finally { eventList.getReadWriteLock().writeLock().unlock(); } //Unlcok Table afterUpdateData(); //Load groups states String group = Settings.get().getStockpileGroupSettings().getGroup(stockpile); boolean expand = Settings.get().getStockpileGroupSettings().isGroupExpanded(group); if (!group.isEmpty()) { if (expand) { //Expanse - Load stockpiles expanded state try { separatorList.getReadWriteLock().writeLock().lock(); for (int i = 0; i < separatorList.size(); i++) { Object object = separatorList.get(i); if (object instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) object; StockpileItem currentItem = (StockpileItem) separator.first(); if (currentItem.getGroup().equals(group)) { if (Settings.get().getStockpileGroupSettings().isStockpileExpanded(currentItem.getStockpile())) { separator.setLimit(Integer.MAX_VALUE); } else { separator.setLimit(0); } } } } } finally { separatorList.getReadWriteLock().writeLock().unlock(); } } else { //Collapse group try { separatorList.getReadWriteLock().writeLock().lock(); for (int i = 0; i < separatorList.size(); i++) { Object object = separatorList.get(i); if (object instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) object; StockpileItem currentItem = (StockpileItem) separator.first(); if (currentItem.getGroup().equals(group)) { separator.setLimit(0); } } } } finally { separatorList.getReadWriteLock().writeLock().unlock(); } } } } private void expandGroups(boolean expand, GroupMatching match) { //Changed groups List stockpileItems = new ArrayList<>(); for (Stockpile stockpile : getShownStockpiles()) { String group = Settings.get().getStockpileGroupSettings().getGroup(stockpile); if (match.matches(group) && Settings.get().getStockpileGroupSettings().isGroupExpanded(group) != expand) { //Match group + is changed stockpileItems.addAll(stockpile.getItems()); stockpileItems.addAll(stockpile.getSubpileTableItems()); } } //Groups affected List groups = new ArrayList<>(); for (Stockpile stockpile : Settings.get().getStockpiles()) { String group = Settings.get().getStockpileGroupSettings().getGroup(stockpile); if (match.matches(group)) { //Match group groups.add(group); } } //Update group settings (must be done after the ShownStockpiles loop) for (String group : groups) { Settings.get().getStockpileGroupSettings().setGroupExpanded(group, expand); } if (!expand) { //Collapse - Save stockpile expanded state try { separatorList.getReadWriteLock().writeLock().lock(); for (int i = 0; i < separatorList.size(); i++) { Object object = separatorList.get(i); if (object instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) object; StockpileItem currentItem = (StockpileItem) separator.first(); if (match.matches(currentItem.getGroup())) { Settings.get().getStockpileGroupSettings().setStockpileExpanded(currentItem.getStockpile(), separator.getLimit() != 0); } } } } finally { separatorList.getReadWriteLock().writeLock().unlock(); } } //Lock Table beforeUpdateData(); try { eventList.getReadWriteLock().writeLock().lock(); eventList.removeAll(stockpileItems); if (expand) { enableGroupFirstUpdate(); } eventList.addAll(stockpileItems); } finally { eventList.getReadWriteLock().writeLock().unlock(); } //Unlcok Table afterUpdateData(); if (expand) { //Expanse - Load stockpiles(s) expanded state try { separatorList.getReadWriteLock().writeLock().lock(); for (int i = 0; i < separatorList.size(); i++) { Object object = separatorList.get(i); if (object instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) object; StockpileItem currentItem = (StockpileItem) separator.first(); if (match.matches(currentItem.getGroup())) { if (Settings.get().getStockpileGroupSettings().isStockpileExpanded(currentItem.getStockpile())) { separator.setLimit(Integer.MAX_VALUE); } else { separator.setLimit(0); } } } } } finally { separatorList.getReadWriteLock().writeLock().unlock(); } } else { //Collapse group(s) try { separatorList.getReadWriteLock().writeLock().lock(); for (int i = 0; i < separatorList.size(); i++) { Object object = separatorList.get(i); if (object instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) object; StockpileItem currentItem = (StockpileItem) separator.first(); //if (match.matches(currentItem.getGroup()) && changed.contains(currentItem.getStockpile())) { if (match.matches(currentItem.getGroup())) { separator.setLimit(0); } } } } finally { separatorList.getReadWriteLock().writeLock().unlock(); } } } private void expandGroupStockpiles(boolean expand) { Stockpile stockpile = getSelectedStockpile(); if (stockpile == null) { return; } String group = Settings.get().getStockpileGroupSettings().getGroup(stockpile); //Save state List stockpiles = Settings.get().getStockpileGroupSettings().getStockpiles(group); Settings.get().getStockpileGroupSettings().setStockpileExpanded(stockpiles, expand); //Expand/Collapse shown stockpiles in group if (Settings.get().getStockpileGroupSettings().isGroupExpanded(group)) { try { separatorList.getReadWriteLock().writeLock().lock(); for (int i = 0; i < separatorList.size(); i++) { Object object = separatorList.get(i); if (object instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) object; StockpileItem currentItem = (StockpileItem) separator.first(); if (currentItem == null) { continue; } if (group.equals(currentItem.getGroup())) { if (expand) { separator.setLimit(Integer.MAX_VALUE); } else { separator.setLimit(0); } } } } } finally { separatorList.getReadWriteLock().writeLock().unlock(); } } } private void removeGroupNoUpdate(List removeStockpiles) { updateGroups(null, removeStockpiles, Collections.emptyList(), false); } private void removeGroup(Stockpile stockpile) { removeGroup(Collections.singletonList(stockpile)); } private void removeGroup(List removeStockpiles) { updateGroups(null, removeStockpiles, Collections.emptyList()); } private void setGroup(String group, Stockpile stockpile) { setGroup(group, Collections.singletonList(stockpile)); } private void setGroup(String group, List addStockiples) { updateGroups(group, Collections.emptyList(), addStockiples); } private void updateGroups(String group, List removeStockpiles, List addStockiples) { updateGroups(group, removeStockpiles, addStockiples, true); } private void updateGroups(String group, List removeStockpiles, List addStockiples, boolean updateTable) { //Add StockpileItems List stockpileItems = new ArrayList<>(); //Updated Settings.lock("Stockpile (Stockpile Group)"); //Add for (Stockpile stockpile : addStockiples) { Settings.get().getStockpileGroupSettings().setGroup(stockpile, group); stockpileItems.addAll(stockpile.getItems()); stockpileItems.addAll(stockpile.getSubpileTableItems()); } //Remove for (Stockpile stockpile : removeStockpiles) { Settings.get().getStockpileGroupSettings().removeGroup(stockpile); stockpileItems.addAll(stockpile.getItems()); stockpileItems.addAll(stockpile.getSubpileTableItems()); } Settings.unlock("Stockpile (Stockpile Group)"); if (updateTable) { //Lock Table beforeUpdateData(); try { eventList.getReadWriteLock().writeLock().lock(); eventList.removeAll(stockpileItems); enableGroupFirstUpdate(); eventList.addAll(stockpileItems); } finally { eventList.getReadWriteLock().writeLock().unlock(); } //Unlcok Table afterUpdateData(); } } private void loadGroupStockpileExpandedState() { try { separatorList.getReadWriteLock().writeLock().lock(); for (int i = 0; i < separatorList.size(); i++) { Object object = separatorList.get(i); if (object instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) object; StockpileItem currentItem = (StockpileItem) separator.first(); if (Settings.get().getStockpileGroupSettings().isGroupExpanded(currentItem.getGroup()) && Settings.get().getStockpileGroupSettings().isStockpileExpanded(currentItem.getStockpile())) { separator.setLimit(Integer.MAX_VALUE); } else { separator.setLimit(0); } } } } finally { separatorList.getReadWriteLock().writeLock().unlock(); } } protected static void enableGroupFirstUpdate() { updateFirstStockpileGroup = true; } private void updateGroupFirst() { if (!updateFirstStockpileGroup) { return; } try { Map groups = new HashMap<>(); separatorList.getReadWriteLock().writeLock().lock(); for (int i = 0; i < separatorList.size(); i++) { Object object = separatorList.get(i); if (object instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) object; StockpileItem stockpileItem = (StockpileItem) separator.first(); if (stockpileItem == null) { // handle 'late' rendering calls after this separator is invalid continue; } String group = stockpileItem.getGroup(); //if (Settings.get().getStockpileGroupSettings().isGroupExpanded(group) // && !group.isEmpty() && !groups.containsKey(group)) { if(!group.isEmpty() && !groups.containsKey(group)) { groups.put(group, stockpileItem.getStockpile()); } } } Settings.get().getStockpileGroupSettings().setGroupFirst(groups); } finally { updateFirstStockpileGroup = false; separatorList.getReadWriteLock().writeLock().unlock(); } } private String getGroupName(String title, boolean canOverwrite, String original, String last) { String group = (String)JOptionInput.showInputDialog(program.getMainWindow().getFrame(), TabsStockpile.get().groupAddName(), title, JOptionPane.PLAIN_MESSAGE, null, null, last); if (group == null) { return null; } if (group.isEmpty()) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsStockpile.get().groupAddEmpty(), title, JOptionPane.WARNING_MESSAGE); return getGroupName(title, canOverwrite, original, null); } Set groups = Settings.get().getStockpileGroupSettings().getGroups(); if (groups.contains(group)) { if (canOverwrite) { int returnValue = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), TabsStockpile.get().groupAddExist(), title, JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if (returnValue == JOptionPane.OK_OPTION) { return group; } else { return getGroupName(title, canOverwrite, original, group); } } else if (original != null && !original.equals(group)) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsStockpile.get().groupRenameExist(), title, JOptionPane.PLAIN_MESSAGE); return getGroupName(title, canOverwrite, original, group); } } return group; } private void removeStockpile(Stockpile stockpile) { removeStockpiles(Collections.singletonList(stockpile)); } private void removeStockpiles(List stockpiles) { List stockpileItems = new ArrayList<>(); for (Stockpile stockpile : stockpiles) { stockpileItems.addAll(stockpile.getItems()); } //Lock Table beforeUpdateData(); //Update list try { eventList.getReadWriteLock().writeLock().lock(); eventList.removeAll(stockpileItems); } finally { eventList.getReadWriteLock().writeLock().unlock(); } //Unlcok Table afterUpdateData(); } private void importEveXml() { jFileChooser.setSelectedFile(new File("")); int value = jFileChooser.showOpenDialog(program.getMainWindow().getFrame()); if (value != JCustomFileChooser.APPROVE_OPTION) { return; //Cancel } Map> fits = EveFittingReader.load(jFileChooser.getSelectedFile().getAbsolutePath()); if (fits == null || fits.isEmpty()) { return; } List selectedFits; if (fits.size() > 1) { //Select fits to import selectedFits = fitsSelectionDialog.show(fits.keySet(), false); } else { //one or less, no reason to show selection dialog selectedFits = new ArrayList<>(fits.keySet()); } if (selectedFits == null || selectedFits.isEmpty()) { return; } Set stockpiles = new HashSet<>(); for (Stockpile stockpile : Settings.get().getStockpiles()) { stockpiles.add(stockpile.getName()); } Set existing = new HashSet<>(); Set open = new HashSet<>(); for (String fit : selectedFits) { if (stockpiles.contains(fit)) { //Exist existing.add(fit); } else { open.add(fit); } } if (open.size() > 1) { OptionEnum option = null; template = null; for (String fit : open) { option = importStockpileItems(fits.get(fit), option, options(ImportOptions.TEMPLATE, ImportOptions.NEW, ImportOptions.ADD), fit); } } else { existing.addAll(open); } OptionEnum option = null; for (String fit : existing) { option = importStockpileItems(fits.get(fit), option, fit); } } private void importText() { TextImportType systemType = TextImportType.EVE_MULTIBUY; try { systemType = TextImportType.valueOf(Settings.get().getImportSettings(NAME, systemType)); } catch (IllegalArgumentException ex) { //No problem, use default } importText("", systemType); } private void importText(String text, TextImportType selected) { textImport.importText(text, TextImportType.values(), selected, new TextImportHandler() { @Override public void addItems(TextReturn textReturn) { TextImportType importType = textReturn.getType(); String importText = textReturn.getText(); Map data = importType.importText(importText); //Validate Output if (data == null || data.isEmpty()) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), GuiShared.get().textInvalid(), GuiShared.get().textImport(), JOptionPane.PLAIN_MESSAGE); importText(importText, importType); //Again! return; } //Add items importStockpileItems(data, importType.getName()); } }); } private OptionEnum importStockpileItems(Map data, String name) { return importStockpileItems(data, null, options(ImportOptions.NEW, ImportOptions.ADD), name); } private OptionEnum importStockpileItems(Map data, OptionEnum option, String name) { return importStockpileItems(data, option, options(ImportOptions.NEW, ImportOptions.ADD), name); } private OptionEnum importStockpileItems(Map data, OptionEnum option, List options, String name) { return importOptions(data, option, 1, false, options, new StockpileImportAction>() { @Override public String getName(Map data) { return name; } @Override public boolean action(Map data, OptionEnum xmlOptions) { if (xmlOptions == ImportOptions.TEMPLATE) { xmlOptions.setAll(true); //Always do this for all //Blueprint/Formula Options BpOptions bpOptions = JMenuStockpile.selectBpImportOptions(program, data.keySet(), false); if (bpOptions == null) { return false; //Cancelled } //Create Template Stockpile if (template == null) { template = stockpileDialog.showTemplate(); } if (template == null) { //Dialog cancelled return false; //Retry } //Create Stockpile from template Stockpile stockpile = new Stockpile(name, template); //Create items List items = JMenuStockpile.toStockpileItems(program, bpOptions, stockpile, data.keySet(), data, Collections.emptyMap()); if (items == null) { return false; //Cancelled } Settings.lock("Stockpile (Import Items Template)"); for (StockpileItem item : items) { stockpile.add(item); } addSettingStockpile(stockpile, true); //Add imported stockpile to Settings Settings.unlock("Stockpile (Import Items Template)"); program.saveSettings("Stockpile (Import Items Template)"); //Update UI addStockpile(stockpile); //Add imported stockpile to Settings } else if (xmlOptions == ImportOptions.NEW) { //Blueprint/Formula Options BpOptions bpOptions = JMenuStockpile.selectBpImportOptions(program, data.keySet(), false); if (bpOptions == null) { return false; //Cancelled } //Create Stockpile Stockpile stockpile = stockpileDialog.showAdd(name); if (stockpile == null) { //Dialog cancelled return false; //Retry } //Create items List items = JMenuStockpile.toStockpileItems(program, bpOptions, stockpile, data.keySet(), data, Collections.emptyMap()); if (items == null) { return false; //Cancelled } Settings.lock("Stockpile (Import Items New)"); for (StockpileItem item : items) { stockpile.add(item); } Settings.unlock("Stockpile (Import Items New)"); program.saveSettings("Stockpile (Import Items New)"); //Update stockpile data addStockpile(stockpile); scrollToSctockpile(stockpile); } else if (xmlOptions == ImportOptions.ADD) { //Select Stockpiles List stockpiles = stockpileSelectionDialog.show(getShownStockpiles(), Settings.get().getStockpiles(), TabsStockpile.get().showHidden(), false); if (stockpiles == null) { return false; } //Stand-in stockpile (will be replaced) Stockpile stockpile = new Stockpile("", 1L, new ArrayList<>(), 1.0, false); //Create items List items = JMenuStockpile.toStockpileItems(program, stockpile, data.keySet(), data, Collections.emptyMap(), false); if (items == null) { return false; //Cancelled } //Merge Into for (Stockpile existingStockpile : stockpiles) { addToStockpile(existingStockpile, items, true, false); //Merge imported stockpile items into existing stockpiles } program.saveSettings("Stockpile (Import Items Add)"); } //Skip - Do nothing return true; } }); } private void importXml() { jFileChooser.setSelectedFile(new File("")); int value = jFileChooser.showOpenDialog(program.getMainWindow().getFrame()); if (value == JCustomFileChooser.APPROVE_OPTION) { List stockpiles = SettingsReader.loadStockpile(jFileChooser.getSelectedFile().getAbsolutePath()); if (stockpiles != null) { importStockpiles(stockpiles); } else { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsStockpile.get().importXmlFailedMsg(), TabsStockpile.get().importFailedTitle(), JOptionPane.WARNING_MESSAGE); } } } private void importXmlText() { jTextDialog.setLineWrap(true); String importText = jTextDialog.importText(); jTextDialog.setLineWrap(false); if (importText == null) { return; //Cancel } List stockpiles = StockpileReader.load(importText); if (stockpiles != null) { importStockpiles(stockpiles); } else { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsStockpile.get().importTextFailedMsg(), TabsStockpile.get().importFailedTitle(), JOptionPane.WARNING_MESSAGE); } } private void importStockpiles(List stockpiles) { if (stockpiles == null) { return; } stockpiles = stockpileSelectionDialog.show(stockpiles, false); if (stockpiles == null) { return; } List existing = new ArrayList<>(); List open = new ArrayList<>(); for (Stockpile stockpile : stockpiles) { if (Settings.get().getStockpiles().contains(stockpile)) { //Exist existing.add(stockpile); } else { open.add(stockpile); } } boolean save = importStockpiles(open, options(ImportOptions.KEEP, ImportOptions.NEW, ImportOptions.ADD, ImportOptions.SKIP)); save = importStockpiles(existing, options(ImportOptions.RENAME, ImportOptions.MERGE, ImportOptions.OVERWRITE, ImportOptions.ADD, ImportOptions.SKIP)) | save; if (save) { program.saveSettings("Stockpile (Import)"); } } private List options(OptionEnum... options) { return Arrays.asList(options); } private boolean importStockpiles(List stockpiles, List options) { boolean save = false; int count = stockpiles.size(); OptionEnum option = null; for (Stockpile stockpile : stockpiles) { option = importOptions(stockpile, option, count, true, options, new StockpileImportAction() { @Override public String getName(Stockpile value) { return value.getName(); } @Override public boolean action(Stockpile value, OptionEnum xmlOptions) { if (xmlOptions == ImportOptions.KEEP) { Settings.lock("Stockpile (Import New)"); addSettingStockpile(value, true); //Add Settings.unlock("Stockpile (Import New)"); //Update UI addStockpile(value); } else if (xmlOptions == ImportOptions.RENAME || xmlOptions == ImportOptions.NEW) { Stockpile returnRename = stockpileDialog.showRename(value); //Rename stockpile if (returnRename == null) { //Cancel return false; } //Update UI addStockpile(returnRename); } else if (xmlOptions == ImportOptions.MERGE) { int index = Settings.get().getStockpiles().indexOf(value); //Get index of old Stockpile Stockpile mergeStockpile = Settings.get().getStockpiles().get(index); //Get old stockpile addToStockpile(mergeStockpile, value.getItems(), true, true); //Merge old and imported stockpiles } else if (xmlOptions == ImportOptions.OVERWRITE) { Settings.lock("Stockpile (Import Overwrite)"); //Remove int index = Settings.get().getStockpiles().indexOf(value); //Get index of old Stockpile Stockpile removeStockpile = Settings.get().getStockpiles().get(index); //Get old stockpile removeStockpile(removeStockpile); //Remove old stockpile from the UI Settings.get().getStockpiles().remove(removeStockpile); //Remove old stockpile from the Settings //Add addSettingStockpile(value, true); //Add imported stockpile to Settings Settings.unlock("Stockpile (Import Overwrite)"); //Update UI addStockpile(value); //Add imported stockpile to Settings } else if (xmlOptions == ImportOptions.ADD) { List stockpiles = stockpileSelectionDialog.show(getShownStockpiles(), Settings.get().getStockpiles(), TabsStockpile.get().showHidden(), false); if (stockpiles == null) { return false; } for (Stockpile existingStockpile : stockpiles) { addToStockpile(existingStockpile, value.getItems(), true, false); //Merge imported stockpile items into existing stockpiles } program.saveSettings("Stockpile (Import Merge)"); } //Skip - Do nothing return true; } }); if (option == ImportOptions.KEEP || option == ImportOptions.OVERWRITE || option == ImportOptions.ADD) { save = true; } count--; } return save; } private OptionEnum importOptions(T value, OptionEnum option, int count, boolean showAll, List options, StockpileImportAction action) { if (option == null || !option.isAll()) { //Not decided - ask what to do option = stockpileImportDialog.show(action.getName(value), TabsStockpile.get().importOptions(), TabsStockpile.get().importOptionsAll(count), count > 1, showAll, options, option); } boolean ok = action.action(value, option); if (!ok) { option.setAll(false); return importOptions(value, option, count, showAll, options, action); //Retry - if RENAME_ALL, ask again } return option; } private List getShownStockpiles() { return getShownStockpiles(program); } public static List getShownStockpiles(Program program) { return getShownStockpiles(program.getProfileManager()); } public static List getShownStockpiles(ProfileManager profileManager) { List shown = new ArrayList<>(); for (Stockpile stockpile : Settings.get().getStockpiles()) { if (profileManager.getStockpileIDs().isHidden(stockpile.getStockpileID())) { continue; } shown.add(stockpile); } return shown; } public static void addSettingStockpile(Stockpile stockpile, boolean sort) { Settings.get().getStockpiles().add(stockpile); if (sort) { sortSettingStockpile(); } } public static void sortSettingStockpile() { Collections.sort(Settings.get().getStockpiles()); } private void exportXml() { List stockpiles = stockpileSelectionDialog.show(getShownStockpiles(), Settings.get().getStockpiles(), TabsStockpile.get().showHidden(), false); if (stockpiles != null) { jFileChooser.setSelectedFile(new File("")); int value = jFileChooser.showSaveDialog(program.getMainWindow().getFrame()); if (value == JCustomFileChooser.APPROVE_OPTION) { SettingsWriter.saveStockpiles(stockpiles, jFileChooser.getSelectedFile().getAbsolutePath()); } } } private void exportText() { List stockpiles = stockpileSelectionDialog.show(getShownStockpiles(), Settings.get().getStockpiles(), TabsStockpile.get().showHidden(), false); if (stockpiles != null) { String json = StockpileWriter.save(stockpiles); if (json != null) { jTextDialog.setLineWrap(true); jTextDialog.exportText(json); jTextDialog.setLineWrap(false); } } } private Stockpile getSelectedStockpile() { int index = jTable.getSelectedRow(); if (index < 0 || index >= tableModel.getRowCount()) { return null; } Object o = tableModel.getElementAt(index); if (o instanceof SeparatorList.Separator) { SeparatorList.Separator separator = (SeparatorList.Separator) o; StockpileItem item = (StockpileItem) separator.first(); return item.getStockpile(); } return null; } private class StockpileTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { JMenuInfo.stockpileItem(jPopupMenu, selectionModel.getSelected()); } @Override public void addToolMenu(JComponent jComponent) { List edit = new ArrayList<>(); List delete = new ArrayList<>(); List items = new ArrayList<>(); ArrayList selected = new ArrayList<>(selectionModel.getSelected()); for (Object object : selected) { if (object.getClass() == StockpileItem.class) { StockpileItem item = (StockpileItem) object; edit.add(item); delete.add(item); items.add(item); } else if (object instanceof SubpileStock) { SubpileStock item = (SubpileStock) object; if (item.isEditable()) { edit.add(item); } } } jComponent.add(new JStockpileItemMenu(StockpileTab.this, program, edit, delete, items)); MenuManager.addSeparator(jComponent); } } private class ListenerClass implements ActionListener, ListEventListener, ColumnValueChangeListener { @Override public void listChanged(final ListEvent listChanges) { List items = EventListManager.safeList(filterList); //Remove StockpileTotal and SeparatorList.Separator for (int i = 0; i < items.size(); i++) { Object object = items.get(i); if ((object instanceof SeparatorList.Separator) || (object instanceof StockpileTotal)) { items.remove(i); i--; } } double volumnNow = 0; double volumnNeeded = 0; double valueNow = 0; double valueNeeded = 0; for (StockpileItem item : items) { volumnNow = volumnNow + item.getVolumeNow(); if (item.getVolumeNeeded() < 0) { //Only add if negative volumnNeeded = volumnNeeded + item.getVolumeNeeded(); } valueNow = valueNow + item.getValueNow(); if (item.getValueNeeded() < 0) { //Only add if negative valueNeeded = valueNeeded + item.getValueNeeded(); } } jVolumeNow.setNumber(TabsStockpile.get().now(), volumnNow); jValueNow.setNumber(TabsStockpile.get().now(), valueNow); jVolumeNeeded.setNumber(TabsStockpile.get().needed(), volumnNeeded); jValueNeeded.setNumber(TabsStockpile.get().needed(), valueNeeded); } @Override public void actionPerformed(final ActionEvent e) { if (StockpileCellAction.SHOPPING_LIST_SINGLE.name().equals(e.getActionCommand())) { //Shopping list single Stockpile stockpile = getSelectedStockpile(); if (stockpile != null) { stockpileShoppingListDialog.show(stockpile); } } else if (StockpileAction.SHOPPING_LIST_MULTI.name().equals(e.getActionCommand())) { //Shopping list multi List stockpiles = stockpileSelectionDialog.show(getShownStockpiles(), Settings.get().getStockpiles(), TabsStockpile.get().showHidden(), false); if (stockpiles != null) { stockpileShoppingListDialog.show(stockpiles); } } else if (StockpileAction.SHOW_HIDE.name().equals(e.getActionCommand())) { //Shopping list multi List selected = new ArrayList<>(); Set all = new HashSet<>(); for (Stockpile stockpile : Settings.get().getStockpiles()) { all.add(stockpile.getStockpileID()); if (program.getProfileManager().getStockpileIDs().isShown(stockpile.getStockpileID())) { selected.add(stockpile); } } List stockpiles = stockpileSelectionDialog.show(Settings.get().getStockpiles(), selected, true); if (stockpiles == null) { return; //Cancel } Set hidden = new HashSet<>(all); for (Stockpile stockpile : stockpiles) { hidden.remove(stockpile.getStockpileID()); } Set oldData = program.getProfileManager().getStockpileIDs().getHidden(); if (!oldData.equals(hidden)) { //Hide Set hide = new HashSet<>(hidden); //To be hidden hide.removeAll(oldData); //Remove already hidden //Show Set show = new HashSet<>(oldData); //Currently hidden show.removeAll(hidden); //Remove still hidden //Update data (must be done after making the removed and added lists) program.getProfileManager().getStockpileIDs().setHidden(hidden); //Update GUI for (Stockpile stockpile : Settings.get().getStockpiles()) { long stockpileID = stockpile.getStockpileID(); if (hide.contains(stockpileID)) { //Hidden removeItems(stockpile.getItems()); } else if (show.contains(stockpileID)) { //Shown addStockpile(stockpile); } //Else: Not changed } } } else if (StockpileAction.SUBPILE_TREE.name().equals(e.getActionCommand())) { List updated = new ArrayList<>(); for (Stockpile stockpile : getShownStockpiles()) { updated.addAll(stockpile.getSubpileStocks()); } try { eventList.getReadWriteLock().writeLock().lock(); if (jShowSubpileTree.isSelected()) { eventList.addAll(updated); } else { eventList.removeAll(updated); } } finally { eventList.getReadWriteLock().writeLock().unlock(); } Settings.lock("Show Subpile Tree"); Settings.get().setShowSubpileTree(jShowSubpileTree.isSelected()); Settings.unlock("Show Subpile Tree"); program.saveSettings("Show Subpile Tree"); } else if (StockpileAction.IMPORT_TEXT.name().equals(e.getActionCommand())) { //Add stockpile (EFT Import) importText(); } else if (StockpileAction.IMPORT_XML.name().equals(e.getActionCommand())) { //Add stockpile (Xml) importXml(); } else if (StockpileAction.IMPORT_EVE_XML_FIT.name().equals(e.getActionCommand())) { //Add stockpile (Xml) importEveXml(); } else if (StockpileAction.IMPORT_XML_TEXT.name().equals(e.getActionCommand())) { //Add stockpile (Xml) importXmlText(); } else if (StockpileAction.EXPORT_XML.name().equals(e.getActionCommand())) { //Export XML exportXml(); } else if (StockpileAction.EXPORT_TEXT.name().equals(e.getActionCommand())) { //Export XML exportText(); } else if (StockpileAction.ADD_STOCKPILE.name().equals(e.getActionCommand())) { //Add stockpile Stockpile stockpile = stockpileDialog.showAdd(); if (stockpile != null) { addStockpile(stockpile); scrollToSctockpile(stockpile); } } else if (StockpileCellAction.EDIT_STOCKPILE.name().equals(e.getActionCommand())) { //Edit stockpile Stockpile stockpile = getSelectedStockpile(); if (stockpile != null) { boolean updated = stockpileDialog.showEdit(stockpile); if (updated) { //To tricker resort removeStockpile(stockpile); addStockpile(stockpile); } } } else if (StockpileCellAction.CLONE_STOCKPILE.name().equals(e.getActionCommand())) { //Clone stockpile Stockpile stockpile = getSelectedStockpile(); if (stockpile != null) { Stockpile cloneStockpile = stockpileDialog.showClone(stockpile); if (cloneStockpile != null) { addStockpile(cloneStockpile); } } } else if (StockpileCellAction.HIDE_STOCKPILE.name().equals(e.getActionCommand())) { //Hide stockpile Stockpile stockpile = getSelectedStockpile(); if (stockpile == null) { return; } program.getProfileManager().getStockpileIDs().hide(stockpile.getStockpileID()); removeItems(stockpile.getItems()); } else if (StockpileCellAction.DELETE_STOCKPILE.name().equals(e.getActionCommand())) { //Delete stockpile Stockpile stockpile = getSelectedStockpile(); if (stockpile != null) { int value = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), stockpile.getName(), TabsStockpile.get().deleteStockpileTitle(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (value == JOptionPane.OK_OPTION) { Settings.lock("Stockpile (Delete Stockpile)"); //Remove stockpile Settings.get().getStockpiles().remove(stockpile); //Remove Group Settings.get().getStockpileGroupSettings().removeGroup(stockpile); StockpileSeparatorTableCell.updateGroups(this); //Remove subpile links for (Stockpile parentStockpile : stockpile.getSubpiles().keySet()) { parentStockpile.removeSubpileLink(stockpile); } stockpile.getSubpiles().clear(); //Remove all Subpiles updateSubpile(stockpile); //Remove SubpileItems from Table //Remove deleted stockpile from all subpiles for (Stockpile parentStockpile : stockpile.getSubpileLinks()) { parentStockpile.getSubpiles().remove(stockpile); updateSubpile(parentStockpile); } Settings.unlock("Stockpile (Delete Stockpile)"); program.saveSettings("Stockpile (Delete Stockpile)"); removeStockpile(stockpile); } } } else if (StockpileAction.DELETE_STOCKPILE_MULTI.name().equals(e.getActionCommand())) { //Delete stockpiles List stockpiles = stockpileSelectionDialog.show(getShownStockpiles(), Settings.get().getStockpiles(), TabsStockpile.get().showHidden(), false); if (stockpiles == null || stockpiles.isEmpty()) { return; } String msg; if (stockpiles.size() > 1) { msg = TabsStockpile.get().deleteStockpileMsg(stockpiles.size()); } else { msg = stockpiles.get(0).getName(); } int value = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), msg, TabsStockpile.get().deleteStockpileTitle(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (value != JOptionPane.OK_OPTION) { return; } //Remove Groups removeGroupNoUpdate(stockpiles); //Update Table Cell StockpileSeparatorTableCell.updateGroups(this); Settings.lock("Stockpile (Delete Stockpile)"); for (Stockpile stockpile : stockpiles) { //Remove stockpile Settings.get().getStockpiles().remove(stockpile); //Remove subpile links for (Stockpile parentStockpile : stockpile.getSubpiles().keySet()) { parentStockpile.removeSubpileLink(stockpile); } stockpile.getSubpiles().clear(); //Remove all Subpiles updateSubpile(stockpile); //Remove SubpileItems from Table //Remove deleted stockpile from all subpiles for (Stockpile parentStockpile : stockpile.getSubpileLinks()) { parentStockpile.getSubpiles().remove(stockpile); updateSubpile(parentStockpile); } } Settings.unlock("Stockpile (Delete Stockpile)"); //Remove stockpiles from GUI removeStockpiles(stockpiles); program.saveSettings("Stockpile (Delete Stockpile)"); } else if (StockpileCellAction.ADD_ITEM.name().equals(e.getActionCommand())) { //Add item Stockpile stockpile = getSelectedStockpile(); if (stockpile != null) { List stockpileItems = stockpileItemDialog.showAdd(stockpile); if (stockpileItems != null) { //Edit/Add/Update existing or cancel addToStockpile(stockpile, stockpileItems, false, true); } } } else if (StockpileAction.COLLAPSE_GROUPS.name().equals(e.getActionCommand())) { expandGroups(false, MATCH_ALL_GROUPS); } else if (StockpileAction.EXPAND_GROUPS.name().equals(e.getActionCommand())) { expandGroups(true, MATCH_ALL_GROUPS); } else if (StockpileAction.EDIT_GROUPS.name().equals(e.getActionCommand())) { Set groups = Settings.get().getStockpileGroupSettings().getGroups(); jAutoCompleteDialog.updateData(groups); String group = jAutoCompleteDialog.show(); if (group == null) { return; } List oldStockpiles = Settings.get().getStockpileGroupSettings().getStockpiles(group); List newStockpiles = stockpileSelectionDialog.show(getShownStockpiles(), oldStockpiles, Settings.get().getStockpiles(), TabsStockpile.get().showHidden(), true); if (newStockpiles == null) { return; } List added = new ArrayList<>(newStockpiles); added.removeAll(oldStockpiles); List removed = new ArrayList<>(oldStockpiles); removed.removeAll(newStockpiles); updateGroups(group, removed, added); //Update Table Cell StockpileSeparatorTableCell.updateGroups(this); //Save Settings program.saveSettings("Stockpile (Stockpile Edit Groups)"); } else if (StockpileCellAction.GROUP_RENAME.name().equals(e.getActionCommand())) { Stockpile stockpile = getSelectedStockpile(); if (stockpile == null) { return; } String oldGroup = Settings.get().getStockpileGroupSettings().getGroup(stockpile); if (oldGroup == null || oldGroup.isEmpty()) { return; } String newGroup = getGroupName(TabsStockpile.get().groupRenameTitle(), false, oldGroup, oldGroup); if (newGroup == null || newGroup.isEmpty() || newGroup.equals(oldGroup)) { return; } List stockpiles = Settings.get().getStockpileGroupSettings().getStockpiles(oldGroup); //Backup expanded boolean expanded = Settings.get().getStockpileGroupSettings().isGroupExpanded(oldGroup); //Update setGroup(newGroup, stockpiles); //Update Table Cell StockpileSeparatorTableCell.updateGroups(this); //Save Settings program.saveSettings("Stockpile (Stockpile Rename Group)"); //Restore expanded expandGroups(expanded, new MatchGroup(newGroup)); } else if (StockpileCellAction.GROUP_SHOPPING_LIST.name().equals(e.getActionCommand())) { //Collapse all Stockpile stockpile = getSelectedStockpile(); if (stockpile == null) { return; } String group = stockpile.getGroup(); if (group == null || group.isEmpty()) { return; } List stockpiles = Settings.get().getStockpileGroupSettings().getStockpiles(group); if (stockpiles == null || stockpiles.isEmpty()) { return; } int returnValue = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), TabsStockpile.get().groupShoppingListMsg(), TabsStockpile.get().groupShoppingListTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE); if (returnValue == JOptionPane.YES_OPTION) { stockpileShoppingListDialog.show(stockpiles); } else { List shownStockpiles = new ArrayList<>(); for (Stockpile s : stockpiles) { if (program.getProfileManager().getStockpileIDs().isShown(s.getStockpileID())) { shownStockpiles.add(s); } } stockpileShoppingListDialog.show(shownStockpiles); } } else if (StockpileAction.COLLAPSE.name().equals(e.getActionCommand())) { //Collapse all jTable.expandSeparators(false); Settings.get().getStockpileGroupSettings().setStockpileExpanded(Settings.get().getStockpiles(), false); } else if (StockpileAction.EXPAND.name().equals(e.getActionCommand())) { //Expand all jTable.expandSeparators(true); Settings.get().getStockpileGroupSettings().setStockpileExpanded(Settings.get().getStockpiles(), true); } else if (StockpileCellAction.GROUP_EXPAND.name().equals(e.getActionCommand())) { expandGroupStockpiles(true); } else if (StockpileCellAction.GROUP_COLLAPSE.name().equals(e.getActionCommand())) { expandGroupStockpiles(false); } else if (StockpileCellAction.GROUP_TOGGLE_COLLAPSE.name().equals(e.getActionCommand())) { Stockpile stockpile = getSelectedStockpile(); if (stockpile == null) { return; } String group = Settings.get().getStockpileGroupSettings().getGroup(stockpile); boolean expand = !Settings.get().getStockpileGroupSettings().isGroupExpanded(group); expandGroups(expand, new MatchGroup(group)); } else if (StockpileCellAction.GROUP_NEW.name().equals(e.getActionCommand())) { Stockpile stockpile = getSelectedStockpile(); if (stockpile == null) { return; } String group = getGroupName(TabsStockpile.get().groupAddTitle(), true, null, null); if (group == null) { return; //Cancelled } String oldGroup = Settings.get().getStockpileGroupSettings().getGroup(stockpile); if (oldGroup.equals(group)) { return; //No change } setGroup(group, stockpile); //Change or add group //Update Table Cell StockpileSeparatorTableCell.updateGroups(this); //Save Settings program.saveSettings("Stockpile (Stockpile New Group)"); } else if (StockpileCellAction.GROUP_CHANGE_ADD.name().equals(e.getActionCommand())) { Stockpile stockpile = getSelectedStockpile(); if (stockpile == null) { return; } Object source = e.getSource(); String newGroup; if (source instanceof JCheckBoxMenuItem) { newGroup = ((JCheckBoxMenuItem)source).getText(); } else { return; } String oldGroup = Settings.get().getStockpileGroupSettings().getGroup(stockpile); if (newGroup.equals(oldGroup)) { removeGroup(stockpile); //Remove from group } else { setGroup(newGroup, stockpile); //Change or add group } //Update Table Cell StockpileSeparatorTableCell.updateGroups(this); //Save Settings program.saveSettings("Stockpile (Stockpile Add Group)"); } else if (StockpileCellAction.SUBPILES.name().equals(e.getActionCommand())) { Stockpile stockpile = getSelectedStockpile(); if (stockpile != null) { List listData = new ArrayList<>(); listData.clear(); listData.addAll(Settings.get().getStockpiles()); listData.remove(stockpile); //Remove self remove(listData, stockpile, stockpile.getSubpileLinks()); //Remove interlinked Collections.sort(listData); List stockpiles = stockpileSelectionDialog.show(listData, stockpile.getSubpiles().keySet(), true); if (stockpiles == null) { return; } Settings.lock("Stockpile (Updated Subpiles)"); //Remove old Links for (Stockpile parentStockpile : stockpile.getSubpiles().keySet()) { parentStockpile.removeSubpileLink(stockpile); } Map old = new HashMap<>(stockpile.getSubpiles()); //Copy stockpile.getSubpiles().clear(); for (Stockpile parentStockpile : stockpiles) { Double value = old.get(parentStockpile); if (value != null) { stockpile.getSubpiles().put(parentStockpile, value); } else { stockpile.getSubpiles().put(parentStockpile, 1.0); } parentStockpile.addSubpileLink(stockpile); } Settings.unlock("Stockpile (Updated Subpiles)"); updateStockpile(stockpile); updateSubpile(stockpile); program.saveSettings("Stockpile (Updated subpiles)"); } } } private void remove(List listData, Stockpile parentLink, List subpileLinks) { for (Stockpile subpileLink : subpileLinks) { listData.remove(subpileLink); remove(listData, parentLink, subpileLink.getSubpileLinks()); } } @Override public void columnValueChanged() { program.saveSettings("Stockpile: Target changed"); } } public static class StockpileSeparatorComparator implements Comparator { @Override public int compare(final StockpileItem o1, final StockpileItem o2) { return o1.getSeparator().compareTo(o2.getSeparator()); } } public class StockpileFilterControl extends FilterControl { public StockpileFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override protected void afterFilter() { jTable.loadExpandedState(); //Load Expanded State loadGroupStockpileExpandedState(); } @Override protected void beforeFilter() { enableGroupFirstUpdate(); jTable.saveExpandedState(); } @Override public void saveSettings(final String msg) { program.saveSettings("Stockpile Table: " + msg); //Save Stockpile Filters and Export Settings } } public static class TotalComparator implements Comparator { private final Comparator comparator; public TotalComparator() { List> comparators = new ArrayList<>(); comparators.add(new StockpileSeparatorComparator()); comparators.add(new InnerSubpileComparator()); comparators.add(new InnerTotalComparator()); comparator = GlazedLists.chainComparators(comparators); } @Override public int compare(final StockpileItem o1, final StockpileItem o2) { return comparator.compare(o1, o2); } private static class InnerSubpileComparator implements Comparator { @Override public int compare(final StockpileItem o1, final StockpileItem o2) { if ((o1 instanceof SubpileItem) && (o2 instanceof SubpileItem)) { SubpileItem item1 = (SubpileItem) o1; SubpileItem item2 = (SubpileItem) o2; return item1.getOrder().compareTo(item2.getOrder()); //Equal (both SubpileItem) } else if (o1 instanceof SubpileItem) { return -1; //Before } else if (o2 instanceof SubpileItem) { return 1; //After } else { return 0; //Equal (not SubpileItem) } } } private static class InnerTotalComparator implements Comparator { @Override public int compare(final StockpileItem o1, final StockpileItem o2) { if ((o1 instanceof StockpileTotal) && (o2 instanceof StockpileTotal)) { return 0; //Equal (both StockpileTotal) } else if (o1 instanceof StockpileTotal) { return 1; //After } else if (o2 instanceof StockpileTotal) { return -1; //Before } else { return 0; //Equal (not StockpileTotal) } } } } private static interface StockpileImportAction { public String getName(T value); public boolean action(T value, OptionEnum xmlOptions); } private static interface GroupMatching { public boolean matches(String group); } private static class MatchAllGroups implements GroupMatching { @Override public boolean matches(String group) { return !group.isEmpty(); } } private static class MatchGroup implements GroupMatching { private final String group; public MatchGroup(String group) { this.group = group; } @Override public boolean matches(String group) { return this.group.equals(group); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/stockpile/StockpileTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.stockpile; import java.awt.Component; import java.util.Comparator; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileTotal; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.SubpileStock; import net.nikr.eve.jeveasset.i18n.TabsStockpile; public enum StockpileTableFormat implements EnumTableColumn { NAME(String.class) { @Override public String getColumnName() { return TabsStockpile.get().columnName(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getName(); } }, TAGS(Tags.class) { @Override public String getColumnName() { return TabsStockpile.get().columnTags(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getTags(); } }, GROUP(String.class) { @Override public String getColumnName() { return TabsStockpile.get().columnGroup(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getItem().getGroup(); } }, CATEGORY(String.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCategory(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getItem().getCategory(); } }, SLOT(String.class) { @Override public String getColumnName() { return TabsStockpile.get().columnSlot(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getItem().getSlot(); } }, CHARGE_SIZE(String.class) { @Override public String getColumnName() { return TabsStockpile.get().columnChargeSize(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getItem().getChargeSize(); } }, META(Integer.class) { @Override public String getColumnName() { return TabsStockpile.get().columnMeta(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getMeta(); } }, COUNT_MINIMUM(Double.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCountMinimum(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getCountMinimum(); } @Override public boolean isColumnEditable(final Object baseObject) { if (baseObject instanceof StockpileItem) { return ((StockpileItem)baseObject).isEditable(); } return false; } @Override public boolean setColumnValue(final Object baseObject, final Object editedValue) { if ((editedValue instanceof Double) && (baseObject instanceof StockpileItem)) { StockpileItem item = (StockpileItem) baseObject; double before = item.getCountMinimum(); double after = (Double) editedValue; item.setCountMinimum(after); return before != after; } return false; } }, COUNT_MINIMUM_MULTIPLIED(Long.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCountMinimumMultiplied(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getCountMinimumMultiplied(); } }, COUNT_NOW(Long.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCountNow(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getCountNow(); } }, COUNT_NEEDED(Long.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCountNeeded(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getCountNeeded(); } }, PERCENT_NEEDED(Percent.class) { @Override public String getColumnName() { return TabsStockpile.get().columnPercentNeeded(); } @Override public Object getColumnValue(final StockpileItem from) { return Percent.create(from.getPercentNeeded()); } }, COUNT_NOW_INVENTORY(Long.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCountNowInventory(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getInventoryCountNow(); } }, COUNT_NOW_BUY_ORDERS(Long.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCountNowBuyOrders(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getBuyOrdersCountNow(); } }, COUNT_NOW_SELL_ORDERS(Long.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCountNowSellOrders(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getSellOrdersCountNow(); } }, COUNT_NOW_BUY_TRANSACTIONS(Long.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCountNowBuyTransactions(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getBuyTransactionsCountNow(); } }, COUNT_NOW_SELL_TRANSACTIONS(Long.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCountNowSellTransactions(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getSellTransactionsCountNow(); } }, COUNT_NOW_JOBS(Long.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCountNowJobs(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getJobsCountNow(); } }, COUNT_NOW_BUYING_CONTRACTS(Long.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCountNowBuyingContracts(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getBuyingContractsCountNow(); } }, COUNT_NOW_BOUGHT_CONTRACTS(Long.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCountNowBoughtContracts(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getBoughtContractsCountNow(); } }, COUNT_NOW_SELLING_CONTRACTS(Long.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCountNowSellingContracts(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getSellingContractsCountNow(); } }, COUNT_NOW_SOLD_CONTRACTS(Long.class) { @Override public String getColumnName() { return TabsStockpile.get().columnCountNowSoldContracts(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getSoldContractsCountNow(); } }, PRICE(Double.class) { @Override public String getColumnName() { return TabsStockpile.get().columnPrice(); } @Override public String getColumnToolTip() { return TabsStockpile.get().columnPriceToolTip(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getDynamicPrice(); } }, PRICE_SELL_MIN(Double.class) { @Override public String getColumnName() { return TabsStockpile.get().columnPriceSellMin(); } @Override public String getColumnToolTip() { return TabsStockpile.get().columnPriceSellMinToolTip(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getPriceSellMin(); } }, PRICE_BUY_MAX(Double.class) { @Override public String getColumnName() { return TabsStockpile.get().columnPriceBuyMax(); } @Override public String getColumnToolTip() { return TabsStockpile.get().columnPriceSellMinToolTip(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getPriceBuyMax(); } }, PRICE_TRANSACTION_AVERAGE(Double.class) { @Override public String getColumnName() { return TabsStockpile.get().columnPriceTransactionAverage(); } @Override public String getColumnToolTip() { return TabsStockpile.get().columnPriceTransactionAverageToolTip(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getTransactionAveragePrice(); } }, EVE_UI(Component.class) { @Override public String getColumnName() { return TabsStockpile.get().columnEveUi(); } @Override public String getColumnToolTip() { return TabsStockpile.get().columnEveUiToolTip(); } @Override public boolean isColumnEditable(Object baseObject) { if (baseObject instanceof StockpileTotal || baseObject instanceof SubpileStock) { return false; } return true; } @Override public Object getColumnValue(final StockpileItem from) { return from.getButton(); } }, VALUE_NOW(Double.class) { @Override public String getColumnName() { return TabsStockpile.get().columnValueNow(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getValueNow(); } }, VALUE_NEEDED(Double.class) { @Override public String getColumnName() { return TabsStockpile.get().columnValueNeeded(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getValueNeeded(); } }, VOLUME_NOW(Double.class) { @Override public String getColumnName() { return TabsStockpile.get().columnVolumeNow(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getVolumeNow(); } }, VOLUME_NEEDED(Double.class) { @Override public String getColumnName() { return TabsStockpile.get().columnVolumeNeeded(); } @Override public Object getColumnValue(final StockpileItem from) { return from.getVolumeNeeded(); } }; private final Class type; private final Comparator comparator; private StockpileTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tracker/JTrackerEditDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tracker; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JTextField; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.TrackerData; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.JOptionInput; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.shared.components.JSelectionDialog; import net.nikr.eve.jeveasset.gui.tabs.values.AssetValue; import net.nikr.eve.jeveasset.gui.tabs.values.Value; import net.nikr.eve.jeveasset.i18n.TabsTracker; public class JTrackerEditDialog extends JDialogCentered { private enum TrackerEditAction { OK, CANCEL, EDIT_WALLET, EDIT_ASSETS } private static final int FIELD_WIDTH = 140; //GUI private final JTextField jDate; private final JTextField jWalletBalance; private final JTextField jImplants; private final JButton jWalletBalanceFilterable; private final JTextField jAssets; private final JButton jAssetsFilterable; private final JTextField jSellOrders; private final JTextField jEscrows; private final JTextField jEscrowsToCover; private final JTextField jManufacturing; private final JTextField jContractCollateral; private final JTextField jContractValue; private final JTextField jSkillPoints; private final JButton jOK; private final JSelectionDialog jSelectionDialog; private final List balanceUpdates = new ArrayList<>(); private final List assetUpdates = new ArrayList<>(); //Data private Value value; private boolean update; public JTrackerEditDialog(Program program) { super(program, TabsTracker.get().edit(), Images.TOOL_TRACKER.getImage()); ListenerClass listener = new ListenerClass(); jSelectionDialog = new JSelectionDialog<>(program); JLabel jDateLabel = new JLabel(TabsTracker.get().date()); jDate = new JTextField(); jDate.setEditable(false); jDate.setEnabled(false); jDate.setHorizontalAlignment(JLabel.RIGHT); JLabel jWalletBalanceLabel = new JLabel(TabsTracker.get().walletBalance()); jWalletBalance = new JTextField(); jWalletBalance.setHorizontalAlignment(JTextField.RIGHT); jWalletBalance.addFocusListener(listener); JLabel jImplantsLabel = new JLabel(TabsTracker.get().implants()); jImplants = new JTextField(); jImplants.setHorizontalAlignment(JTextField.RIGHT); jImplants.addFocusListener(listener); jWalletBalanceFilterable = new JButton(Images.EDIT_EDIT.getIcon()); jWalletBalanceFilterable.setActionCommand(TrackerEditAction.EDIT_WALLET.name()); jWalletBalanceFilterable.addActionListener(listener); JLabel jAssetsLabel = new JLabel(TabsTracker.get().assets()); jAssets = new JTextField(); jAssets.setHorizontalAlignment(JTextField.RIGHT); jAssets.addFocusListener(listener); jAssetsFilterable = new JButton(Images.EDIT_EDIT.getIcon()); jAssetsFilterable.setActionCommand(TrackerEditAction.EDIT_ASSETS.name()); jAssetsFilterable.addActionListener(listener); JLabel jSellOrdersLabel = new JLabel(TabsTracker.get().sellOrders()); jSellOrders = new JTextField(); jSellOrders.setHorizontalAlignment(JTextField.RIGHT); jSellOrders.addFocusListener(listener); JLabel jEscrowsLabel = new JLabel(TabsTracker.get().escrows()); jEscrows = new JTextField(); jEscrows.setHorizontalAlignment(JTextField.RIGHT); jEscrows.addFocusListener(listener); JLabel jEscrowsToCoverLabel = new JLabel(TabsTracker.get().escrowsToCover()); jEscrowsToCover = new JTextField(); jEscrowsToCover.setHorizontalAlignment(JTextField.RIGHT); jEscrowsToCover.addFocusListener(listener); JLabel jManufacturingLabel = new JLabel(TabsTracker.get().manufacturing()); jManufacturing = new JTextField(); jManufacturing.setHorizontalAlignment(JTextField.RIGHT); jManufacturing.addFocusListener(listener); JLabel jContractCollateralLabel = new JLabel(TabsTracker.get().contractCollateral()); jContractCollateral = new JTextField(); jContractCollateral.setHorizontalAlignment(JTextField.RIGHT); jContractCollateral.addFocusListener(listener); JLabel jContractValueLabel = new JLabel(TabsTracker.get().contractValue()); jContractValue = new JTextField(); jContractValue.setHorizontalAlignment(JTextField.RIGHT); jContractValue.addFocusListener(listener); JLabel jSkillPointValueLabel = new JLabel(TabsTracker.get().skillPoints()); jSkillPoints = new JTextField(); jSkillPoints.setHorizontalAlignment(JTextField.RIGHT); jSkillPoints.addFocusListener(listener); jOK = new JButton(TabsTracker.get().ok()); jOK.setActionCommand(TrackerEditAction.OK.name()); jOK.addActionListener(listener); JButton jCancel = new JButton(TabsTracker.get().cancel()); jCancel.setActionCommand(TrackerEditAction.CANCEL.name()); jCancel.addActionListener(listener); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jDateLabel) .addComponent(jWalletBalanceLabel) .addComponent(jAssetsLabel) .addComponent(jImplantsLabel) .addComponent(jSellOrdersLabel) .addComponent(jEscrowsLabel) .addComponent(jEscrowsToCoverLabel) .addComponent(jManufacturingLabel) .addComponent(jContractCollateralLabel) .addComponent(jContractValueLabel) .addComponent(jSkillPointValueLabel) ) .addGroup(layout.createParallelGroup() .addComponent(jDate, FIELD_WIDTH, FIELD_WIDTH, FIELD_WIDTH) .addComponent(jWalletBalance, FIELD_WIDTH, FIELD_WIDTH, FIELD_WIDTH) .addComponent(jAssets, FIELD_WIDTH, FIELD_WIDTH, FIELD_WIDTH) .addComponent(jImplants, FIELD_WIDTH, FIELD_WIDTH, FIELD_WIDTH) .addComponent(jSellOrders, FIELD_WIDTH, FIELD_WIDTH, FIELD_WIDTH) .addComponent(jEscrows, FIELD_WIDTH, FIELD_WIDTH, FIELD_WIDTH) .addComponent(jEscrowsToCover, FIELD_WIDTH, FIELD_WIDTH, FIELD_WIDTH) .addComponent(jManufacturing, FIELD_WIDTH, FIELD_WIDTH, FIELD_WIDTH) .addComponent(jContractCollateral, FIELD_WIDTH, FIELD_WIDTH, FIELD_WIDTH) .addComponent(jContractValue, FIELD_WIDTH, FIELD_WIDTH, FIELD_WIDTH) .addComponent(jSkillPoints, FIELD_WIDTH, FIELD_WIDTH, FIELD_WIDTH) ) .addGroup(layout.createParallelGroup() .addComponent(jWalletBalanceFilterable) .addComponent(jAssetsFilterable) ) ) .addGroup(layout.createSequentialGroup() .addGap(0, 0, Integer.MAX_VALUE) .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jDateLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jDate, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jWalletBalanceLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jWalletBalance, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jWalletBalanceFilterable, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jAssetsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jAssets, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jAssetsFilterable, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jImplantsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jImplants, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jSellOrdersLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSellOrders, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jEscrowsLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jEscrows, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jEscrowsToCoverLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jEscrowsToCover, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jManufacturingLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jManufacturing, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jContractCollateralLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jContractCollateral, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jContractValueLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jContractValue, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jSkillPointValueLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSkillPoints, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } public boolean showEdit(Value value) { this.value = value; update = false; balanceUpdates.clear(); assetUpdates.clear(); if (value.getBalanceFilter().size() < 2) { jWalletBalance.setEnabled(true); jWalletBalanceFilterable.setVisible(false); } else { jWalletBalance.setEnabled(false); jWalletBalanceFilterable.setVisible(true); } if (value.getAssetsFilter().size() < 2) { jAssets.setEnabled(true); jAssetsFilterable.setVisible(false); } else { jAssets.setEnabled(false); jAssetsFilterable.setVisible(true); } jWalletBalance.setText(format(value.getBalanceTotal())); jAssets.setText(format(value.getAssetsTotal())); jImplants.setText(format(value.getImplants())); jSellOrders.setText(format(value.getSellOrders())); jEscrows.setText(format(value.getEscrows())); jEscrowsToCover.setText(format(value.getEscrowsToCover())); jManufacturing.setText(format(value.getManufacturing())); jContractCollateral.setText(format(value.getContractCollateral())); jContractValue.setText(format(value.getContractValue())); jSkillPoints.setText(format(value.getSkillPoints())); jDate.setText(format(value.getDate())); setVisible(true); return update; } private String format(double d) { return Formatter.longFormat(d); } private String format(Date d) { return Formatter.columnDate(d); } private double parse(String s) throws ParseException { return Formatter.longParse(s); } @Override protected JComponent getDefaultFocus() { return jWalletBalance; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { } @Override protected void save() { try { double walletBalanc = parse(jWalletBalance.getText()); double assets = parse(jAssets.getText()); double implants = parse(jImplants.getText()); double sellOrders = parse(jSellOrders.getText()); double escrows = parse(jEscrows.getText()); double escrowsToCover = parse(jEscrowsToCover.getText()); double manufacturing = parse(jManufacturing.getText()); double contractCollateral = parse(jContractCollateral.getText()); double contractValue = parse(jContractValue.getText()); double skillPointValue = parse(jSkillPoints.getText()); try { TrackerData.writeLock(); if (value.getBalanceFilter().isEmpty()) { value.setBalanceTotal(walletBalanc); } else if (value.getBalanceFilter().size() == 1) { for (Map.Entry entry : value.getBalanceFilter().entrySet()) { //Just done once... value.removeBalance(entry.getKey()); //Remove old value value.addBalance(entry.getKey(), walletBalanc); //Add new value } } else { for (FilterUpdate filterUpdate : balanceUpdates) { value.removeBalance(filterUpdate.getKey()); value.addBalance(filterUpdate.getKey(), filterUpdate.getValue()); } } if (value.getAssetsFilter().isEmpty()) { value.setAssetsTotal(assets); } else if (value.getAssetsFilter().size() == 1) { for (Map.Entry entry : value.getAssetsFilter().entrySet()) { //Just done once... value.removeAssets(entry.getKey()); //Remove old value value.addAssets(entry.getKey(), assets); //Add new value } } else { for (FilterUpdate filterUpdate : assetUpdates) { AssetValue assetValue = AssetValue.create(filterUpdate.getKey()); value.removeAssets(assetValue); value.addAssets(assetValue, filterUpdate.getValue()); } } value.setImplants(implants); value.setSellOrders(sellOrders); value.setEscrows(escrows); value.setEscrowsToCover(escrowsToCover); value.setManufacturing(manufacturing); value.setContractCollateral(contractCollateral); value.setContractValue(contractValue); value.setSkillPoints((long)skillPointValue); } finally { TrackerData.writeUnlock(); } TrackerData.save("Edited"); update = true; setVisible(false); } catch (ParseException ex) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsTracker.get().invalid(), TabsTracker.get().error(), JOptionPane.ERROR_MESSAGE); } } private Double getValue(Double balance) { String balanceReturn = JOptionInput.showInputDialog(getDialog(), TabsTracker.get().enterNewValue(), format(balance)); if (balanceReturn == null) { return null; //Cancel } try { return parse(balanceReturn); } catch (ParseException ex) { JOptionPane.showMessageDialog(getDialog(), TabsTracker.get().invalidNumberMsg(), TabsTracker.get().invalidNumberTitle(), JOptionPane.WARNING_MESSAGE); return getValue(balance); } } private class ListenerClass implements ActionListener, FocusListener { @Override public void actionPerformed(ActionEvent e) { if (TrackerEditAction.OK.name().equals(e.getActionCommand())) { save(); } else if (TrackerEditAction.CANCEL.name().equals(e.getActionCommand())) { setVisible(false); } else if (TrackerEditAction.EDIT_WALLET.name().equals(e.getActionCommand())) { //Create values for selection dialog Set ids = new TreeSet<>(); for (String id : value.getBalanceFilter().keySet()) { ids.add(TabsTracker.get().division(id)); } //Select Division String returnValue = jSelectionDialog.show(TabsTracker.get().selectDivision(), ids); if (returnValue == null) { return; //Cancel } Double balance = null; String key = null; //Match return value with key and balance for (Map.Entry entry : value.getBalanceFilter().entrySet()) { if (TabsTracker.get().division(entry.getKey()).equals(returnValue)) { balance = entry.getValue(); key = entry.getKey(); break; //Item found } } if (balance != null) { //Item found balance = getValue(balance); //Get new value if (balance != null) { //Update number balanceUpdates.add(new FilterUpdate(key, balance)); //Add update to queue (will only be executed if this dialog closed by pressing OK) //Update displayed total - only a GUI thing, the textfield is never used when getBalanceFilter is not empty Map map = new HashMap<>(value.getBalanceFilter()); for (FilterUpdate filterUpdate : balanceUpdates) { map.put(filterUpdate.getKey(), filterUpdate.getValue()); } double total = 0; for (double d : map.values()) { total = total + d; } jWalletBalance.setText(format(total)); } } } else if (TrackerEditAction.EDIT_ASSETS.name().equals(e.getActionCommand())) { //Create values for selection dialog Map> values = new TreeMap<>(); for (AssetValue assetValue : value.getAssetsFilter().keySet()) { String location = assetValue.getLocation(); Set flags = values.get(location); if (flags == null) { flags = new TreeSet<>(); values.put(location, flags); } String flag = assetValue.getFlag(); if (flag == null) { flag = TabsTracker.get().other(); } flags.add(flag); } //Select Location String returnLocation = null; if (values.keySet().size() > 1) { returnLocation = jSelectionDialog.show(TabsTracker.get().selectLocation(), values.keySet()); } else { //Size is always 1 (one) or 0 (zero) for (String s : values.keySet()) { returnLocation = s; //Only done if size is 1 (one) AKA only done once } } if (returnLocation == null) { return; //Cancelled or Empty } //Select Flag Set flags = values.get(returnLocation); String returnFlag = TabsTracker.get().other(); //Used if size is 1 if (flags.size() > 1) { //Always contain "Other" flag returnFlag = jSelectionDialog.show(TabsTracker.get().selectFlag(), flags); if (returnFlag == null) { return; //Cancel } } else if (flags.size() == 1) { //Size is always 1 (one) or 0 (zero) for (String s : flags) { returnFlag = s; //Only done if size is 1 (one) AKA only done once } } AssetValue assetValue; if (returnFlag.equals(TabsTracker.get().other())) { assetValue = AssetValue.create(returnLocation); } else { assetValue = AssetValue.create(returnLocation + " > " + returnFlag); } Double asset = value.getAssetsFilter().get(assetValue); if (asset != null) { //Item found asset = getValue(asset); //Get new value if (asset != null) { //Update number assetUpdates.add(new FilterUpdate(assetValue.getID(), asset)); //Add update to queue (will only be executed if this dialog closed by pressing OK) //Update displayed total - only a GUI thing, the textfield is never used when getAssetsFilter is not empty Map map = new HashMap<>(); for (Map.Entry entry : value.getAssetsFilter().entrySet()) { map.put(entry.getKey().getID(), entry.getValue()); } for (FilterUpdate filterUpdate : assetUpdates) { map.put(filterUpdate.getKey(), filterUpdate.getValue()); } double total = 0; for (double d : map.values()) { total = total + d; } jAssets.setText(format(total)); } } } } @Override public void focusGained(FocusEvent e) { JTextField jTextField = (JTextField) e.getSource(); ColorSettings.configReset(jTextField); } @Override public void focusLost(FocusEvent e) { JTextField jTextField = (JTextField) e.getSource(); try { parse(jTextField.getText()); ColorSettings.configReset(jTextField); } catch (ParseException ex) { ColorSettings.config(jTextField, ColorEntry.GLOBAL_ENTRY_INVALID); } jTextField.setCaretPosition(jTextField.getText().length()); } } private static class FilterUpdate { private final String key; private final Double value; public FilterUpdate(String key, Double value) { this.key = key; this.value = value; } public String getKey() { return key; } public Double getValue() { return value; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tracker/QuickDate.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tracker; import java.util.Calendar; import java.util.Date; import net.nikr.eve.jeveasset.i18n.TabsTracker; public enum QuickDate { EMPTY(null, null, TabsTracker.get().quickDate()) ,RESET(null, null, TabsTracker.get().reset()) ,DAY_ONE(Calendar.DAY_OF_YEAR, -1, TabsTracker.get().day1()) ,WEEK_ONE(Calendar.DAY_OF_YEAR, -7, TabsTracker.get().week1()) ,WEEK_TWO(Calendar.DAY_OF_YEAR, -14, TabsTracker.get().week2()) ,MONTH_ONE(Calendar.MONTH, -1, TabsTracker.get().month1()) ,MONTH_THREE(Calendar.MONTH, -3, TabsTracker.get().months3()) ,MONTH_SIX(Calendar.MONTH, -6, TabsTracker.get().months6()) ,YEAR_ONE(Calendar.YEAR, -1, TabsTracker.get().year1()) ,YEAR_TWO(Calendar.YEAR, -2, TabsTracker.get().years2()); private final Integer field; private final Integer amount; private final String title; private QuickDate(Integer field, Integer amount, String title) { this.field = field; this.amount = amount; this.title = title; } public Date apply(Date to) { if (field == null || amount == null) { return null; } Calendar calendar = Calendar.getInstance(); calendar.setTime(to); calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0); calendar.set(Calendar.MILLISECOND, 0); calendar.add(field, amount); return calendar.getTime(); } public boolean isValid(Date from, Date to) { if (to == null) { to = new Date(); //now } if (from == null) { return false; } to = apply(to); return from.equals(to); } public QuickDate getSelected(Date from, Date to) { for (QuickDate quickDate : QuickDate.values()) { if (quickDate.isValid(from, to)) { return quickDate; } } return QuickDate.EMPTY; } @Override public String toString() { return title; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tracker/TrackerAssetFilterDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tracker; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.TreeList; import ca.odell.glazedlists.matchers.Matcher; import ca.odell.glazedlists.swing.EventTreeModel; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.Timer; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.CheckBoxNode; import net.nikr.eve.jeveasset.gui.shared.components.CheckBoxNodeEditor; import net.nikr.eve.jeveasset.gui.shared.components.CheckBoxNodeRenderer; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.i18n.TabsTracker; public class TrackerAssetFilterDialog extends JDialogCentered { private final JTree jTree; private final JTextField jFilter; private final JCheckBox jNewSelected; private final EventList eventList; private final Timer timer; private final FilterList filterList; private boolean save = false; public TrackerAssetFilterDialog(Program program) { super(program, TabsTracker.get().filterTitle(), Images.TOOL_TRACKER.getImage()); //Backend eventList = EventListManager.create(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Tree eventList.getReadWriteLock().readLock().lock(); TreeList treeList = new TreeList<>(EventModels.createSwingThreadProxyList(filterList), new CheckBoxNodeFormat(), TreeList.nodesStartExpanded()); eventList.getReadWriteLock().readLock().unlock(); EventTreeModel eventTreeModel = new EventTreeModel<>(treeList); jTree = new JTree(eventTreeModel); jTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); jTree.putClientProperty("JTree.lineStyle", "None"); jTree.setExpandsSelectedPaths(true); jTree.setRootVisible(false); jTree.setShowsRootHandles(true); jTree.setVisibleRowCount(0); jTree.setCellRenderer(new CheckBoxNodeRenderer()); jTree.setCellEditor(new CheckBoxNodeEditor(jTree)); jTree.setEditable(true); jTree.setLargeModel(true); jTree.setRowHeight(16); timer = new Timer(500, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { timer.stop(); filter(); } }); JLabel jSearch = new JLabel(TabsTracker.get().search()); jFilter = new JTextField(); jFilter.getDocument().addDocumentListener(new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { timer.stop(); timer.start(); } @Override public void removeUpdate(DocumentEvent e) { timer.stop(); timer.start(); } @Override public void changedUpdate(DocumentEvent e) { timer.stop(); timer.start(); } }); JButton jClear = new JButton(Images.TAB_CLOSE.getIcon()); jClear.setContentAreaFilled(false); jClear.setFocusPainted(false); jClear.setPressedIcon(Images.TAB_CLOSE_ACTIVE.getIcon()); jClear.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jFilter.setText(""); timer.stop(); filter(); } }); jNewSelected = new JCheckBox(TabsTracker.get().newSelected()); jNewSelected.setSelected(Settings.get().getTrackerSettings().isSelectNew()); JButton jOK = new JButton(TabsTracker.get().ok()); jOK.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { save = true; setVisible(false); } }); JButton jCancel = new JButton(TabsTracker.get().cancel()); jCancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setVisible(false); } }); JScrollPane jTreeScroll = new JScrollPane(jTree); jTreeScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jSearch) .addComponent(jFilter, 0, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jClear, 16, 16, 16) ) .addComponent(jTreeScroll, 0, GroupLayout.PREFERRED_SIZE, 600) .addGroup(layout.createSequentialGroup() .addComponent(jNewSelected) .addGap(0, 0, Integer.MAX_VALUE) .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jSearch, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFilter, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jClear, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jTreeScroll, 0, GroupLayout.PREFERRED_SIZE, 500) .addGroup(layout.createParallelGroup() .addComponent(jNewSelected) .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } @Override protected JComponent getDefaultFocus() { return jTree; } @Override protected JButton getDefaultButton() { return null; } @Override protected void windowShown() { } @Override protected void save() { } public boolean isSelectNew() { return jNewSelected.isSelected(); } public boolean showLocations(Map nodes) { //Reset save = false; jFilter.setText(""); timer.stop(); filterList.setMatcher(null); //Copy list Map cloneList = cloneList(nodes); //Set data try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(cloneList.values()); } finally { eventList.getReadWriteLock().writeLock().unlock(); } if (cloneList.size() > 35) { jTree.setVisibleRowCount(35); } else { jTree.setVisibleRowCount(cloneList.size()); } expandAll(); //Expand all //Show setVisible(true); boolean changed = changed(cloneList, nodes); //Only need to update if something have been changed... if (save && changed) { //If changed nodes.clear(); nodes.putAll(cloneList); } return save && changed; } private void filter() { if (jFilter.getText().isEmpty()) { filterList.setMatcher(null); try { eventList.getReadWriteLock().readLock().lock(); for (CheckBoxNode node : eventList) { node.show(); } } finally { eventList.getReadWriteLock().readLock().unlock(); } } else { try { eventList.getReadWriteLock().readLock().lock(); for (CheckBoxNode node : eventList) { node.hide(); } } finally { eventList.getReadWriteLock().readLock().unlock(); } filterList.setMatcher(new CheckBoxNodeMatcher(jFilter.getText())); } expandAll(); } private Map cloneList(Map nodes) { Map clonesCache = new HashMap<>(); Map clonedNodes = new TreeMap<>(); for (Map.Entry entry : nodes.entrySet()) { clonedNodes.put(entry.getKey(), cloneTree(clonesCache, entry.getValue())); } return clonedNodes; } private CheckBoxNode cloneTree(Map clonesCache, CheckBoxNode oldNode) { CheckBoxNode oldParent = oldNode.getParent(); CheckBoxNode cloneParent = null; if (oldParent != null) { cloneParent = cloneTree(clonesCache, oldParent); } CheckBoxNode cloneNode = clonesCache.get(oldNode.getNodeID()); if (cloneNode == null) { cloneNode = new CheckBoxNode(cloneParent, oldNode); clonesCache.put(cloneNode.getNodeID(), cloneNode); } return cloneNode; } /** * Check if the clone tree have been changed compared to the source tree * @param clone Clone Tree * @param source Source Tree * @return true if the maps are not equal. false if the maps are equal */ private boolean changed(Map clone, Map source) { for (Map.Entry entry : clone.entrySet()) { CheckBoxNode sourceNode = source.get(entry.getKey()); CheckBoxNode cloneNode = entry.getValue(); if (cloneNode.isSelected() != sourceNode.isSelected()) { return true; } } return false; } private void expandAll() { if (jTree.getRowCount() > 0) { //Always expand root jTree.expandRow(0); } for (int i = 0; i < jTree.getRowCount(); i++) { //Expand everything TreePath path = jTree.getPathForRow(i); Object object = path.getLastPathComponent(); if (object instanceof TreeList.Node) { TreeList.Node node = (TreeList.Node) object; if (node.getChildren().size() > 5000) { //Ignore nodes with more that 5000 children continue; } } jTree.expandPath(path); } } private static class CheckBoxNodeFormat implements TreeList.Format { private final CheckBoxNodeComparator comparator = new CheckBoxNodeComparator(); @Override public void getPath(List path, CheckBoxNode element) { addParents(path, element); path.add(element); } @Override public boolean allowsChildren(CheckBoxNode element) { return true; } @Override public Comparator getComparator(int depth) { return comparator; } private void addParents(List path, CheckBoxNode element) { CheckBoxNode parent = element.getParent(); if (parent != null) { path.add(0, parent); addParents(path, parent); } } private static class CheckBoxNodeComparator implements Comparator { @Override public int compare(CheckBoxNode o1, CheckBoxNode o2) { return o1.compareTo(o2); } } } private static class CheckBoxNodeMatcher implements Matcher { private final String text; public CheckBoxNodeMatcher(String text) { this.text = text.toLowerCase(); } @Override public boolean matches(CheckBoxNode item) { if (item.isShown()) { //already evaluated return true; } return item.matches(text); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tracker/TrackerDate.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tracker; import java.util.Date; import java.util.Objects; import net.nikr.eve.jeveasset.gui.shared.Formatter; public class TrackerDate implements Comparable { private final Date date; private final String compare; public TrackerDate(Date date) { this.date = date; this.compare = Formatter.dateOnly(date); } public Date getDate() { return date; } @Override public int compareTo(TrackerDate o) { return compare.compareTo(o.compare); } @Override public int hashCode() { int hash = 7; hash = 97 * hash + Objects.hashCode(this.compare); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final TrackerDate other = (TrackerDate) obj; if (!Objects.equals(this.compare, other.compare)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tracker/TrackerNote.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tracker; public class TrackerNote { private final String note; public TrackerNote(String note) { this.note = note; } public String getNote() { return note; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tracker/TrackerSkillPointFilter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tracker; import java.util.Objects; public class TrackerSkillPointFilter implements Comparable { private final String name; private boolean enabled; private long minimum; public TrackerSkillPointFilter(String name, boolean enabled, long minimum) { this.name = name; this.enabled = enabled; this.minimum = minimum; } public TrackerSkillPointFilter(TrackerSkillPointFilter filter) { this.name = filter.name; this.enabled = filter.enabled; this.minimum = filter.minimum; } public TrackerSkillPointFilter(String name) { this.name = name; this.enabled = true; this.minimum = 0; } public String getName() { return name; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public long getMinimum() { return minimum; } public void setMinimum(long minimum) { this.minimum = minimum; } public boolean isEmpty() { return this.minimum == 0 && enabled; } @Override public int compareTo(TrackerSkillPointFilter o) { return this.getName().compareTo(o.getName()); } @Override public int hashCode() { int hash = 7; hash = 37 * hash + Objects.hashCode(this.name); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final TrackerSkillPointFilter other = (TrackerSkillPointFilter) obj; if (!Objects.equals(this.name, other.name)) { return false; } return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tracker/TrackerSkillPointsFilterDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tracker; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.GlazedLists; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.TreeSet; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.TabsTracker; public class TrackerSkillPointsFilterDialog extends JDialogCentered { private final JCheckBox jAll; private final JAutoColumnTable jTable; private final EventList eventList; private final DefaultEventTableModel tableModel; private final JButton jOK; private boolean save = false; public TrackerSkillPointsFilterDialog(Program program) { super(program, TabsTracker.get().skillPointFilters(), Images.TOOL_TRACKER.getImage()); jAll = new JCheckBox(TabsTracker.get().all()); jAll.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { selectAll(jAll.isSelected()); } }); eventList = EventListManager.create(); eventList.addListEventListener(new ListEventListener() { @Override public void listChanged(ListEvent listChanges) { updateSelected(); } }); tableModel = EventModels.createTableModel(eventList, TableFormatFactory.trackerSkillPointsFilterTableFormat()); jTable = new JAutoColumnTable(program, tableModel); jTable.getTableHeader().setReorderingAllowed(false); JScrollPane jTableScroll = new JScrollPane(jTable); jTableScroll.getVerticalScrollBar().setUnitIncrement(19); jTableScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); DefaultEventSelectionModel selectionModel = EventModels.createSelectionModel(eventList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); jOK = new JButton(TabsTracker.get().ok()); jOK.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { save(); } }); JButton jCancel = new JButton(TabsTracker.get().cancel()); jCancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setVisible(false); } }); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(jAll) .addComponent(jTableScroll, 0, GroupLayout.PREFERRED_SIZE, 750) .addGroup(layout.createSequentialGroup() .addGap(0, 0, Integer.MAX_VALUE) .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jAll) .addComponent(jTableScroll, 0, GroupLayout.PREFERRED_SIZE, 450) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } public boolean show() { Set filters = new TreeSet<>(); for (OwnerType ownerType : program.getOwnerTypes()) { if (ownerType.isCorporation()) { continue; //Corporation can not have skill points } final String ownerName = ownerType.getOwnerName(); TrackerSkillPointFilter filter = Settings.get().getTrackerSettings().getSkillPointFilters().get(ownerName); if (filter == null) { filter = new TrackerSkillPointFilter(ownerName); } filters.add(new TrackerSkillPointFilter(filter)); //Working Copy } //Update rows (Add all rows) try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(filters); } finally { eventList.getReadWriteLock().writeLock().unlock(); } jTable.setPreferredScrollableViewportSize(jTable.getPreferredSize()); save = false; setVisible(true); return save; } private void selectAll(final boolean selected) { try { eventList.getReadWriteLock().writeLock().lock(); for (TrackerSkillPointFilter filter : eventList) { filter.setEnabled(selected); } } finally { eventList.getReadWriteLock().writeLock().unlock(); } for (int row = 0; row < jTable.getRowCount(); row++) { tableModel.fireTableCellUpdated(row, 0); } } private void updateSelected() { try { eventList.getReadWriteLock().readLock().lock(); for (TrackerSkillPointFilter filter : eventList) { if (!filter.isEnabled()) { jAll.setSelected(false); return; } } jAll.setSelected(true); } finally { eventList.getReadWriteLock().readLock().unlock(); } } @Override protected JComponent getDefaultFocus() { return jOK; } @Override protected JButton getDefaultButton() { return jOK; } @Override protected void windowShown() { } @Override protected void save() { save = !compareLists(eventList, Settings.get().getTrackerSettings().getSkillPointFilters().values(), new ListComparator()); if (save) { try { eventList.getReadWriteLock().readLock().lock(); Settings.lock("Tracker Skill Points Filters: Update"); for (TrackerSkillPointFilter filter : eventList) { Settings.get().getTrackerSettings().getSkillPointFilters().put(filter.getName(), filter); } } finally { Settings.unlock("Tracker Skill Points Filters: Update"); program.saveSettings("Tracker Skill Points Filters: Update"); eventList.getReadWriteLock().readLock().unlock(); } } setVisible(false); } private boolean compareLists(Collection list1, Collection list2, Comparator comparator) { // if not the same size, lists are not equal if (list1.size() != list2.size()) { return false; } // create sorted copies to avoid modifying the original lists List copy1 = new ArrayList<>(list1); List copy2 = new ArrayList<>(list2); Collections.sort(copy1, comparator); Collections.sort(copy2, comparator); // iterate through the elements and compare them one by one using // the provided comparator. Iterator it1 = copy1.iterator(); Iterator it2 = copy2.iterator(); while (it1.hasNext()) { T t1 = it1.next(); T t2 = it2.next(); if (comparator.compare(t1, t2) != 0) { // as soon as a difference is found, stop looping return false; } } return true; } private static class ListComparator implements Comparator { @Override public int compare(TrackerSkillPointFilter o1, TrackerSkillPointFilter o2) { int compared; compared = GlazedLists.comparableComparator().compare(o1.getName(), o2.getName()); if (compared != 0) { return compared; } compared = GlazedLists.comparableComparator().compare(o1.getMinimum(), o2.getMinimum()); if (compared != 0) { return compared; } compared = GlazedLists.comparableComparator().compare(o1.isEnabled(), o2.isEnabled()); if (compared != 0) { return compared; } return 0; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tracker/TrackerSkillPointsFilterTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tracker; import java.util.Comparator; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.TabsTracker; public enum TrackerSkillPointsFilterTableFormat implements EnumTableColumn { ENABLED(Boolean.class) { @Override public String getColumnName() { return TabsTracker.get().columnShow(); } @Override public Object getColumnValue(final TrackerSkillPointFilter from) { return from.isEnabled(); } @Override public boolean isColumnEditable(final Object baseObject) { return true; } @Override public boolean setColumnValue(final Object baseObject, final Object editedValue) { if ((editedValue instanceof Boolean) && (baseObject instanceof TrackerSkillPointFilter)) { TrackerSkillPointFilter owner = (TrackerSkillPointFilter) baseObject; boolean before = owner.isEnabled(); boolean after = (Boolean) editedValue; owner.setEnabled(after); return before != after; } return false; } }, NAME(String.class) { @Override public String getColumnName() { return TabsTracker.get().columnName(); } @Override public Object getColumnValue(final TrackerSkillPointFilter from) { return from.getName(); } }, MINIMUM(Long.class) { @Override public String getColumnName() { return TabsTracker.get().columnMinimum(); } @Override public Object getColumnValue(final TrackerSkillPointFilter from) { return from.getMinimum(); } @Override public boolean isColumnEditable(final Object baseObject) { return true; } @Override public boolean setColumnValue(final Object baseObject, final Object editedValue) { if ((editedValue instanceof Long) && (baseObject instanceof TrackerSkillPointFilter)) { TrackerSkillPointFilter owner = (TrackerSkillPointFilter) baseObject; long before = owner.getMinimum(); long after = (Long) editedValue; if (after < 0) { return false; } owner.setMinimum(after); return before != after; } return false; } }; private final Class type; private final Comparator comparator; private TrackerSkillPointsFilterTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tracker/TrackerTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tracker; import com.github.lgooddatepicker.optionalusertools.DateChangeListener; import com.github.lgooddatepicker.zinternaltools.DateChangeEvent; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Ellipse2D; import java.awt.geom.Rectangle2D; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import javax.swing.AbstractListModel; import javax.swing.ButtonGroup; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.ListModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.TrackerData; import net.nikr.eve.jeveasset.data.settings.TrackerSettings; import net.nikr.eve.jeveasset.data.settings.TrackerSettings.DisplayType; import net.nikr.eve.jeveasset.data.settings.TrackerSettings.ShowOption; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.JStatusLabel; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.JFreeChartUtil; import net.nikr.eve.jeveasset.gui.shared.JFreeChartUtil.SimpleRenderer; import net.nikr.eve.jeveasset.gui.shared.ColorIcon; import net.nikr.eve.jeveasset.gui.shared.ColorUtil; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.InstantToolTip; import net.nikr.eve.jeveasset.gui.shared.JOptionInput; import net.nikr.eve.jeveasset.gui.shared.components.CheckBoxNode; import net.nikr.eve.jeveasset.gui.shared.components.JCustomFileChooser; import net.nikr.eve.jeveasset.gui.shared.components.JDateChooser; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow; import net.nikr.eve.jeveasset.gui.shared.components.JLockWindow.LockWorkerAdaptor; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.components.JMultiSelectionList; import net.nikr.eve.jeveasset.gui.shared.components.JSelectionDialog; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.AutoNumberFormat; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.MenuItemValue; import net.nikr.eve.jeveasset.gui.tabs.values.AssetValue; import net.nikr.eve.jeveasset.gui.tabs.values.DataSetCreator; import net.nikr.eve.jeveasset.gui.tabs.values.Value; import net.nikr.eve.jeveasset.gui.tabs.values.ValueTableTab; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.i18n.TabsTracker; import net.nikr.eve.jeveasset.io.local.SettingsReader; import net.nikr.eve.jeveasset.io.local.TrackerReader; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.jfree.chart.ChartMouseEvent; import org.jfree.chart.ChartMouseListener; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.LogarithmicAxis; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.labels.XYToolTipGenerator; import org.jfree.chart.plot.DefaultDrawingSupplier; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.ui.RectangleEdge; import org.jfree.data.time.SimpleTimePeriod; import org.jfree.data.time.TimePeriodValues; import org.jfree.data.time.TimePeriodValuesCollection; import org.jfree.data.xy.XYDataset; public class TrackerTab extends JMainTabSecondary { private enum TrackerAction { QUICK_DATE, UPDATE_DATA, UPDATE_SHOWN, IMPORT_FILE, INCLUDE_ZERO, LOGARITHMIC, ALL, EDIT, DELETE, NOTE_ADD, NOTE_DELETE, PROFILE, FILTER_ASSETS, FILTER_WALLET_BALANCE, FILTER_SKILL_POINTS } public static enum ImportOptions { KEEP() { @Override public String getName() { return TabsTracker.get().importFileOptionsKeep(); } }, OVERWRITE() { @Override public String getName() { return TabsTracker.get().importFileOptionsOverwrite(); } }, REPLACE() { @Override public String getName() { return TabsTracker.get().importFileOptionsReplace(); } }; abstract public String getName(); @Override public String toString() { return getName(); } } private final Shape NO_FILTER = new Rectangle(-3, -3, 6, 6); private final Shape BUG_CORP_CONTAINERS_FILTER = new Ellipse2D.Float(-3.0f, -2.0f, 6.0f, 4.0f); private final Shape FILTER_AND_DEFAULT = new Ellipse2D.Float(-3.0f, -3.0f, 6.0f, 6.0f); private final int PANEL_WIDTH_MINIMUM = 160; //GUI private final JDateChooser jFrom; private final JDateChooser jTo; private final JMultiSelectionList jOwners; private final JComboBox jQuickDate; private final JDropDownButton jShow; private final JCheckBoxMenuItem jAll; private final JCheckBoxMenuItem jTotal; private final JCheckBoxMenuItem jWalletBalance; private final JButton jWalletBalanceFilters; private final JCheckBoxMenuItem jAssets; private final JCheckBoxMenuItem jImplants; private final JButton jAssetsFilters; private final JCheckBoxMenuItem jSellOrders; private final JCheckBoxMenuItem jEscrows; private final JCheckBoxMenuItem jEscrowsToCover; private final JCheckBoxMenuItem jManufacturing; private final JCheckBoxMenuItem jContractCollateral; private final JCheckBoxMenuItem jContractValue; private final JCheckBoxMenuItem jSkillPointsValue; private final JButton jSkillPointsFilters; private final JCheckBox jAllProfiles; private final JCheckBox jCharacterCorporations; private final JMenuItem jImportFile; private final JCheckBoxMenuItem jIncludeZero; private final JRadioButtonMenuItem jLogarithmic; private final JPopupMenu jPopupMenu; private final JMenuItem jAddNote; private final JMenu jEditNote; private final List values; private final JStatusLabel jTotalStatus; private final JStatusLabel jWalletBalanceStatus; private final JStatusLabel jAssetsStatus; private final JStatusLabel jImplantsStatus; private final JStatusLabel jSellOrdersStatus; private final JStatusLabel jEscrowsStatus; private final JStatusLabel jEscrowsToCoverStatus; private final JStatusLabel jManufacturingStatus; private final JStatusLabel jContractCollateralStatus; private final JStatusLabel jContractValueStatus; private final JStatusLabel jSkillPointsStatus; //Graph private final JFreeChart jFreeChart; private final ChartPanel jChartPanel; private final MyRenderer renderer; private final TimePeriodValuesCollection dataset = new TimePeriodValuesCollection(); private final DateAxis domainAxis; private final LogarithmicAxis rangeLogarithmicAxis; private final NumberAxis rangeLinearAxis; private TimePeriodValues walletBalance; private TimePeriodValues assets; private TimePeriodValues implants; private TimePeriodValues sellOrders; private TimePeriodValues escrows; private TimePeriodValues escrowsToCover; private TimePeriodValues manufacturing; private TimePeriodValues contractCollateral; private TimePeriodValues contractValue; private TimePeriodValues skillPointsValue; //Dialog private final JTrackerEditDialog jEditDialog; private final JSelectionDialog jSelectionDialog; private final TrackerWalletFilterDialog walletFilterDialog; private final TrackerAssetFilterDialog assetFilterDialog; private final TrackerSkillPointsFilterDialog skillPointsFilterDialog; private final JCustomFileChooser jFileChooser; private final JLockWindow jLockWindow; //Listener private final ListenerClass listener = new ListenerClass(); //Data private Map cache; private final Map accountNodes = new TreeMap<>(); private final Map assetNodes = new TreeMap<>(); private Integer assetNoFilterColumn = null; private Integer assetBuggedFilterColumn = null; private Integer walletColumn = null; private boolean updateLock = false; public static final String NAME = "tracker"; //Not to be changed! public TrackerTab(Program program) { super(program, NAME, TabsTracker.get().title(), Images.TOOL_TRACKER.getIcon(), true); walletFilterDialog = new TrackerWalletFilterDialog(program); assetFilterDialog = new TrackerAssetFilterDialog(program); skillPointsFilterDialog = new TrackerSkillPointsFilterDialog(program); TrackerSettings trackerSettings = Settings.get().getTrackerSettings(); List extensions = new ArrayList<>(); extensions.add("xml"); extensions.add("zip"); extensions.add("json"); extensions.add("backup"); jFileChooser = new JCustomFileChooser(extensions); jFileChooser.setMultiSelectionEnabled(false); jFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); jLockWindow = new JLockWindow(program.getMainWindow().getFrame()); jPopupMenu = new JPopupMenu(); jPopupMenu.addPopupMenuListener(listener); JMenuItem jMenuItem; jMenuItem = new JMenuItem(TabsTracker.get().edit(), Images.EDIT_EDIT.getIcon()); jMenuItem.setActionCommand(TrackerAction.EDIT.name()); jMenuItem.addActionListener(listener); jPopupMenu.add(jMenuItem); jMenuItem = new JMenuItem(TabsTracker.get().delete(), Images.EDIT_DELETE.getIcon()); jMenuItem.setActionCommand(TrackerAction.DELETE.name()); jMenuItem.addActionListener(listener); jPopupMenu.add(jMenuItem); jPopupMenu.addSeparator(); jAddNote = new JMenuItem(TabsTracker.get().notesAdd(), Images.EDIT_ADD.getIcon()); jAddNote.setActionCommand(TrackerAction.NOTE_ADD.name()); jAddNote.addActionListener(listener); jPopupMenu.add(jAddNote); jEditNote = new JMenu(TabsTracker.get().note()); jEditNote.setIcon(Images.SETTINGS_USER_NAME.getIcon()); jPopupMenu.add(jEditNote); values = JMenuInfo.createDefault(jPopupMenu); jMenuItem = new JMenuItem(TabsTracker.get().edit(), Images.EDIT_EDIT.getIcon()); jMenuItem.setActionCommand(TrackerAction.NOTE_ADD.name()); jMenuItem.addActionListener(listener); jEditNote.add(jMenuItem); jMenuItem = new JMenuItem(TabsTracker.get().delete(), Images.EDIT_DELETE.getIcon()); jMenuItem.setActionCommand(TrackerAction.NOTE_DELETE.name()); jMenuItem.addActionListener(listener); jEditNote.add(jMenuItem); jEditDialog = new JTrackerEditDialog(program); jSelectionDialog = new JSelectionDialog<>(program); JSeparator jDateSeparator = new JSeparator(); jQuickDate = new JComboBox<>(QuickDate.values()); jQuickDate.setActionCommand(TrackerAction.QUICK_DATE.name()); jQuickDate.addActionListener(listener); JLabel jFromLabel = new JLabel(TabsTracker.get().from()); jFrom = new JDateChooser(true); if (trackerSettings.getFromDate() != null) { jFrom.setDate(trackerSettings.getFromDate()); } jFrom.addDateChangeListener(listener); JLabel jToLabel = new JLabel(TabsTracker.get().to()); jTo = new JDateChooser(true); if (trackerSettings.getToDate() != null) { jTo.setDate(trackerSettings.getToDate()); } jTo.addDateChangeListener(listener); jShow = new JDropDownButton(TabsTracker.get().show(), Images.LOC_INCLUDE.getIcon()); jShow.setHorizontalAlignment(JButton.LEFT); jShow.setIcon(trackerSettings.hasShowOption(ShowOption.ALL) ? Images.LOC_INCLUDE.getIcon() : Images.EDIT_EDIT_WHITE.getIcon()); jAll = new JCheckBoxMenuItem(General.get().all()); jAll.setSelected(trackerSettings.hasShowOption(ShowOption.ALL)); jAll.setActionCommand(TrackerAction.ALL.name()); jAll.addActionListener(listener); jAll.setFont(new Font(jAll.getFont().getName(), Font.ITALIC, jAll.getFont().getSize())); jShow.add(jAll, true); jTotal = new JCheckBoxMenuItem(TabsTracker.get().total()); jTotal.setSelected(trackerSettings.hasShowOption(ShowOption.ALL) || trackerSettings.hasShowOption(ShowOption.TOTAL)); jTotal.setActionCommand(TrackerAction.UPDATE_SHOWN.name()); jTotal.addActionListener(listener); jShow.add(jTotal, true); jWalletBalance = new JCheckBoxMenuItem(TabsTracker.get().walletBalance()); jWalletBalance.setSelected(trackerSettings.hasShowOption(ShowOption.ALL) || trackerSettings.hasShowOption(ShowOption.WALLET)); jWalletBalance.setActionCommand(TrackerAction.UPDATE_SHOWN.name()); jWalletBalance.addActionListener(listener); jShow.add(jWalletBalance, true); jWalletBalanceFilters = new JButton(TabsTracker.get().walletBalanceFilters()); jWalletBalanceFilters.setIcon(Images.LOC_INCLUDE.getIcon()); jWalletBalanceFilters.setHorizontalAlignment(JButton.LEFT); jWalletBalanceFilters.setActionCommand(TrackerAction.FILTER_WALLET_BALANCE.name()); jWalletBalanceFilters.addActionListener(listener); jAssets = new JCheckBoxMenuItem(TabsTracker.get().assets()); jAssets.setSelected(trackerSettings.hasShowOption(ShowOption.ALL) || trackerSettings.hasShowOption(ShowOption.ASSET)); jAssets.setActionCommand(TrackerAction.UPDATE_SHOWN.name()); jAssets.addActionListener(listener); jShow.add(jAssets, true); jImplants = new JCheckBoxMenuItem(TabsTracker.get().implants()); jImplants.setSelected(trackerSettings.hasShowOption(ShowOption.ALL) || trackerSettings.hasShowOption(ShowOption.IMPLANT)); jImplants.setActionCommand(TrackerAction.UPDATE_SHOWN.name()); jImplants.addActionListener(listener); jShow.add(jImplants, true); jAssetsFilters = new JButton(TabsTracker.get().assetsFilters()); jAssetsFilters.setIcon(Images.LOC_INCLUDE.getIcon()); jAssetsFilters.setHorizontalAlignment(JButton.LEFT); jAssetsFilters.setActionCommand(TrackerAction.FILTER_ASSETS.name()); jAssetsFilters.addActionListener(listener); jSellOrders = new JCheckBoxMenuItem(TabsTracker.get().sellOrders()); jSellOrders.setSelected(trackerSettings.hasShowOption(ShowOption.ALL) || trackerSettings.hasShowOption(ShowOption.SELL_ORDER)); jSellOrders.setActionCommand(TrackerAction.UPDATE_SHOWN.name()); jSellOrders.addActionListener(listener); jShow.add(jSellOrders, true); jEscrows = new JCheckBoxMenuItem(TabsTracker.get().escrows()); jEscrows.setSelected(trackerSettings.hasShowOption(ShowOption.ALL) || trackerSettings.hasShowOption(ShowOption.ESCROW)); jEscrows.setActionCommand(TrackerAction.UPDATE_SHOWN.name()); jEscrows.addActionListener(listener); jShow.add(jEscrows, true); jEscrowsToCover = new JCheckBoxMenuItem(TabsTracker.get().escrowsToCover()); jEscrowsToCover.setSelected(trackerSettings.hasShowOption(ShowOption.ALL) || trackerSettings.hasShowOption(ShowOption.ESCROW_TO_COVER)); jEscrowsToCover.setActionCommand(TrackerAction.UPDATE_SHOWN.name()); jEscrowsToCover.addActionListener(listener); jShow.add(jEscrowsToCover, true); jManufacturing = new JCheckBoxMenuItem(TabsTracker.get().manufacturing()); jManufacturing.setSelected(trackerSettings.hasShowOption(ShowOption.ALL) || trackerSettings.hasShowOption(ShowOption.MANUFACTURING)); jManufacturing.setActionCommand(TrackerAction.UPDATE_SHOWN.name()); jManufacturing.addActionListener(listener); jShow.add(jManufacturing, true); jContractCollateral = new JCheckBoxMenuItem(TabsTracker.get().contractCollateral()); jContractCollateral.setSelected(trackerSettings.hasShowOption(ShowOption.ALL) || trackerSettings.hasShowOption(ShowOption.COLLATERAL)); jContractCollateral.setActionCommand(TrackerAction.UPDATE_SHOWN.name()); jContractCollateral.addActionListener(listener); jShow.add(jContractCollateral, true); jContractValue = new JCheckBoxMenuItem(TabsTracker.get().contractValue()); jContractValue.setSelected(trackerSettings.hasShowOption(ShowOption.ALL) || trackerSettings.hasShowOption(ShowOption.CONTRACT)); jContractValue.setActionCommand(TrackerAction.UPDATE_SHOWN.name()); jContractValue.addActionListener(listener); jShow.add(jContractValue, true); jSkillPointsValue = new JCheckBoxMenuItem(TabsTracker.get().skillPointValue()); jSkillPointsValue.setSelected(trackerSettings.hasShowOption(ShowOption.ALL) || trackerSettings.hasShowOption(ShowOption.SKILL_POINT)); jSkillPointsValue.setActionCommand(TrackerAction.UPDATE_SHOWN.name()); jSkillPointsValue.addActionListener(listener); jShow.add(jSkillPointsValue, true); jSkillPointsFilters = new JButton(TabsTracker.get().skillPointFilters()); jSkillPointsFilters.setIcon(Images.LOC_INCLUDE.getIcon()); jSkillPointsFilters.setHorizontalAlignment(JButton.LEFT); jSkillPointsFilters.setActionCommand(TrackerAction.FILTER_SKILL_POINTS.name()); jSkillPointsFilters.addActionListener(listener); JSeparator jOwnersSeparator = new JSeparator(); jAllProfiles = new JCheckBox(TabsTracker.get().allProfiles()); jAllProfiles.setSelected(trackerSettings.isAllProfiles()); jAllProfiles.setActionCommand(TrackerAction.PROFILE.name()); jAllProfiles.addActionListener(listener); jCharacterCorporations = new JCheckBox(TabsTracker.get().characterCorporations()); jCharacterCorporations.setSelected(trackerSettings.isCharacterCorporations()); jCharacterCorporations.setActionCommand(TrackerAction.PROFILE.name()); jCharacterCorporations.addActionListener(listener); jOwners = new JMultiSelectionList<>(); jOwners.getSelectionModel().addListSelectionListener(listener); JScrollPane jOwnersScroll = new JScrollPane(jOwners); jTotalStatus = StatusPanel.createLabel(TabsTracker.get().statusTotal(), new ColorIcon(Color.RED.darker()), AutoNumberFormat.ISK); this.addStatusbarLabel(jTotalStatus); jWalletBalanceStatus = StatusPanel.createLabel(TabsTracker.get().statusBalance(), new ColorIcon(Color.BLUE.darker()), AutoNumberFormat.ISK); this.addStatusbarLabel(jWalletBalanceStatus); jAssetsStatus = StatusPanel.createLabel(TabsTracker.get().statusAssets(), new ColorIcon(Color.GREEN.darker().darker()), AutoNumberFormat.ISK); this.addStatusbarLabel(jAssetsStatus); jImplantsStatus = StatusPanel.createLabel(TabsTracker.get().statusImplants(), new ColorIcon(Color.MAGENTA.darker()), AutoNumberFormat.ISK); this.addStatusbarLabel(jImplantsStatus); jSellOrdersStatus = StatusPanel.createLabel(TabsTracker.get().statusSellOrders(), new ColorIcon(Color.CYAN.darker()), AutoNumberFormat.ISK); this.addStatusbarLabel(jSellOrdersStatus); jEscrowsStatus = StatusPanel.createLabel(TabsTracker.get().statusEscrows(), new ColorIcon(Color.BLACK), AutoNumberFormat.ISK); this.addStatusbarLabel(jEscrowsStatus); jEscrowsToCoverStatus = StatusPanel.createLabel(TabsTracker.get().statusEscrowsToCover(), new ColorIcon(Color.GRAY), AutoNumberFormat.ISK); this.addStatusbarLabel(jEscrowsToCoverStatus); jManufacturingStatus = StatusPanel.createLabel(TabsTracker.get().statusManufacturing(), new ColorIcon(Color.MAGENTA), AutoNumberFormat.ISK); this.addStatusbarLabel(jManufacturingStatus); jContractCollateralStatus = StatusPanel.createLabel(TabsTracker.get().statusContractCollateral(), new ColorIcon(Color.PINK), AutoNumberFormat.ISK); this.addStatusbarLabel(jContractCollateralStatus); jContractValueStatus = StatusPanel.createLabel(TabsTracker.get().statusContractValue(), new ColorIcon(Color.ORANGE), AutoNumberFormat.ISK); this.addStatusbarLabel(jContractValueStatus); jSkillPointsStatus = StatusPanel.createLabel(TabsTracker.get().statusSkillPointValue(), new ColorIcon(Color.YELLOW), AutoNumberFormat.ISK); this.addStatusbarLabel(jSkillPointsStatus); JLabel jHelp = new JLabel(TabsTracker.get().help()); jHelp.setIcon(Images.MISC_HELP.getIcon()); JLabel jNoFilter = new JLabel(TabsTracker.get().helpLegacyData()); jNoFilter.setToolTipText(TabsTracker.get().helpLegacyDataToolTip()); jNoFilter.setIcon(new ShapeIcon(NO_FILTER)); InstantToolTip.install(jNoFilter); JLabel jBuggedFilter = new JLabel(TabsTracker.get().helpBugData()); jBuggedFilter.setToolTipText(TabsTracker.get().helpBugDataToolTip()); jBuggedFilter.setIcon(new ShapeIcon(BUG_CORP_CONTAINERS_FILTER)); InstantToolTip.install(jBuggedFilter); JLabel jFilter = new JLabel(TabsTracker.get().helpNewData()); jFilter.setToolTipText(TabsTracker.get().helpNewDataToolTip()); jFilter.setIcon(new ShapeIcon(FILTER_AND_DEFAULT)); InstantToolTip.install(jFilter); JDropDownButton jSettings = new JDropDownButton(Images.DIALOG_SETTINGS.getIcon(), JDropDownButton.RIGHT); jImportFile = new JMenuItem(TabsTracker.get().importFile(), Images.EDIT_IMPORT.getIcon()); jImportFile.setSelected(true); jImportFile.setActionCommand(TrackerAction.IMPORT_FILE.name()); jImportFile.addActionListener(listener); jSettings.add(jImportFile); jSettings.addSeparator(); jIncludeZero = new JCheckBoxMenuItem(TabsTracker.get().includeZero()); jIncludeZero.setSelected(trackerSettings.isIncludeZero()); jIncludeZero.setActionCommand(TrackerAction.INCLUDE_ZERO.name()); jIncludeZero.addActionListener(listener); jSettings.add(jIncludeZero); jSettings.addSeparator(); ButtonGroup buttonGroup = new ButtonGroup(); JRadioButtonMenuItem jLinear = new JRadioButtonMenuItem(TabsTracker.get().scaleLinear()); jLinear.setSelected(trackerSettings.getDisplayType() == DisplayType.LINEAR); jLinear.setActionCommand(TrackerAction.LOGARITHMIC.name()); jLinear.addActionListener(listener); jSettings.add(jLinear); buttonGroup.add(jLinear); jLogarithmic = new JRadioButtonMenuItem(TabsTracker.get().scaleLogarithmic()); jLogarithmic.setSelected(trackerSettings.getDisplayType() == DisplayType.LOGARITHMIC); jLogarithmic.setActionCommand(TrackerAction.LOGARITHMIC.name()); jLogarithmic.addActionListener(listener); jSettings.add(jLogarithmic); buttonGroup.add(jLogarithmic); domainAxis = JFreeChartUtil.createDateAxis(); rangeLogarithmicAxis = JFreeChartUtil.createLogarithmicAxis(trackerSettings.isIncludeZero()); rangeLinearAxis = JFreeChartUtil.createNumberAxis(trackerSettings.isIncludeZero()); renderer = new MyRenderer(); renderer.setDefaultToolTipGenerator(new XYToolTipGenerator() { @Override public String generateToolTip(XYDataset dataset, int series, int item) { Date date = new Date(dataset.getX(series, item).longValue()); Number isk = dataset.getY(series, item); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(""); stringBuilder.append(""); stringBuilder.append(dataset.getSeriesKey(series)); stringBuilder.append(": "); stringBuilder.append(Formatter.iskFormat(isk)); stringBuilder.append("
"); stringBuilder.append(""); stringBuilder.append(TabsTracker.get().date()); stringBuilder.append(": "); stringBuilder.append(Formatter.columnDateOnly(date)); TrackerNote trackerNote = trackerSettings.getNotes().get(new TrackerDate(date)); if (trackerNote != null) { stringBuilder.append("
"); stringBuilder.append(TabsTracker.get().note()); stringBuilder.append(": "); stringBuilder.append(trackerNote.getNote()); } return stringBuilder.toString(); } }); XYPlot plot; if (trackerSettings.getDisplayType() == DisplayType.LINEAR) { plot = JFreeChartUtil.createPlot(dataset, domainAxis, rangeLinearAxis, renderer); } else { plot = JFreeChartUtil.createPlot(dataset, domainAxis, rangeLogarithmicAxis, renderer); } plot.setDrawingSupplier(new MyDrawingSupplier()); jFreeChart = JFreeChartUtil.createChart(plot); jChartPanel = JFreeChartUtil.createChartPanel(jFreeChart); jChartPanel.addChartMouseListener(listener); int gapWidth = 5; int labelWidth = Math.max(jFromLabel.getPreferredSize().width, jToLabel.getPreferredSize().width); int panelWidth = Math.max(PANEL_WIDTH_MINIMUM, jCharacterCorporations.getPreferredSize().width); panelWidth = Math.max(panelWidth, jFrom.getPreferredSize().width + labelWidth + gapWidth); panelWidth = Math.max(panelWidth, jTo.getPreferredSize().width + labelWidth + gapWidth); int dateWidth = panelWidth - labelWidth - gapWidth; layout.setHorizontalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addComponent(jHelp) .addGap(20) .addComponent(jNoFilter) .addGap(20) .addComponent(jBuggedFilter) .addGap(20) .addComponent(jFilter) .addGap(20, 20, Integer.MAX_VALUE) .addComponent(jSettings, Program.getIconButtonsWidth(), Program.getIconButtonsWidth(), Program.getIconButtonsWidth()) .addGap(6) ) .addComponent(jChartPanel) ) .addGroup(layout.createParallelGroup() .addComponent(jQuickDate, panelWidth, panelWidth, panelWidth) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jFromLabel, labelWidth, labelWidth, labelWidth) .addComponent(jToLabel, labelWidth, labelWidth, labelWidth) ) .addGap(gapWidth) .addGroup(layout.createParallelGroup() .addComponent(jFrom, dateWidth, dateWidth, dateWidth) .addComponent(jTo, dateWidth, dateWidth, dateWidth) ) ) .addComponent(jDateSeparator, panelWidth, panelWidth, panelWidth) .addComponent(jShow, panelWidth, panelWidth, panelWidth) .addComponent(jAssetsFilters, panelWidth, panelWidth, panelWidth) .addComponent(jWalletBalanceFilters, panelWidth, panelWidth, panelWidth) .addComponent(jSkillPointsFilters, panelWidth, panelWidth, panelWidth) .addComponent(jOwnersSeparator, panelWidth, panelWidth, panelWidth) .addComponent(jAllProfiles, panelWidth, panelWidth, panelWidth) .addComponent(jCharacterCorporations, panelWidth, panelWidth, panelWidth) .addComponent(jOwnersScroll, panelWidth, panelWidth, panelWidth) ) ); layout.setVerticalGroup( layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(jHelp, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jNoFilter, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jBuggedFilter, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFilter, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSettings, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jChartPanel) ) .addGroup(layout.createSequentialGroup() .addComponent(jQuickDate, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addGroup(layout.createParallelGroup() .addComponent(jFromLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jFrom, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup() .addComponent(jToLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jTo, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addComponent(jDateSeparator, 3, 3, 3) .addComponent(jShow, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jAssetsFilters, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jWalletBalanceFilters, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jSkillPointsFilters, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOwnersSeparator, 3, 3, 3) .addComponent(jAllProfiles, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCharacterCorporations, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jOwnersScroll, 70, 70, Integer.MAX_VALUE) ) ); DataSetCreator.purgeInvalidTrackerAssetValues(); } @Override public void updateData() { updateNodes(); //Must be first or NPE! updateButtonIcons(); updateOwners(); createData(); updateFilterButtons(); } @Override public void repaintTable() { updateShown(); } @Override public void clearData() { } @Override public void updateCache() { } @Override public Collection getLocations() { return new ArrayList<>(); //No Location } public void checkAll() { if (!Settings.get().isAskedCheckAllTracker()) { Settings.lock("Tracker: Check All"); Settings.get().setAskedCheckAllTracker(true); Settings.unlock("Tracker: Check All"); program.saveSettings("Tracker: Check All"); boolean isAll = true; for (CheckBoxNode node : assetNodes.values()) { if (!node.isSelected()) { isAll = false; break; } } boolean empty = false; try { TrackerData.readLock(); empty = TrackerData.get().isEmpty(); } finally { TrackerData.readUnlock(); } if (!isAll && !empty) { int value = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), TabsTracker.get().checkAllLocationsMsg(), TabsTracker.get().checkAllLocationsTitle(), JOptionPane.OK_CANCEL_OPTION); if (value == JOptionPane.OK_OPTION) { for (CheckBoxNode node : assetNodes.values()) { if (node.isParent()) { continue; } node.setSelected(true); } updateSettings(); createData(); updateButtonIcons(); } else { showLocationFilter(); } } } } public void showSkillPointsFilter() { boolean save = skillPointsFilterDialog.show(); if (save) { //Tracker if (program.getMainWindow().isOpen(this)) { createData(); updateButtonIcons(); } //Isk ValueTableTab iskTab = program.getIskTab(false); if (iskTab != null && program.getMainWindow().isOpen(iskTab)) { iskTab.updateData(); } } } private void updateFilterButtons() { if (updateLock) { return; } List owners = jOwners.getSelectedValuesList(); boolean balanceFilter = false; boolean assetsFilter = false; try { TrackerData.readLock(); for (String owner : owners) { for (Value data : TrackerData.get().get(owner)) { //Get all account wallet account keys if (!data.getBalanceFilter().isEmpty()) { balanceFilter = true; } //Get all asset IDs if (!data.getAssetsFilter().isEmpty()) { assetsFilter = true; } if (balanceFilter && assetsFilter) { break; } } } } finally { TrackerData.readUnlock(); } jWalletBalanceFilters.setEnabled(balanceFilter); jAssetsFilters.setEnabled(assetsFilter); } private void updateOwners() { updateLock = true; Set trackerOwners; try { TrackerData.readLock(); trackerOwners = new TreeSet<>(TrackerData.get().keySet()); } finally { TrackerData.readUnlock(); } Set uniqueOwners; if (jAllProfiles.isSelected()) { uniqueOwners = new HashSet<>(trackerOwners); } else { //Profile owners uniqueOwners = new HashSet<>(); boolean characterCorporations = jCharacterCorporations.isSelected(); for (OwnerType owner : program.getOwnerTypes()) { if (trackerOwners.contains(owner.getOwnerName())) { uniqueOwners.add(owner.getOwnerName()); } if (characterCorporations && owner.getCorporationName() != null && trackerOwners.contains(owner.getCorporationName())) { uniqueOwners.add(owner.getCorporationName()); } } } final List ownersList = new ArrayList<>(uniqueOwners); Collections.sort(ownersList); if (ownersList.isEmpty()) { jOwners.setEnabled(false); jOwners.setModel(new AbstractListModel() { @Override public int getSize() { return 1; } @Override public String getElementAt(int index) { return TabsTracker.get().noDataFound(); } }); } else { jOwners.setEnabled(true); jOwners.setModel(new AbstractListModel() { @Override public int getSize() { return ownersList.size(); } @Override public String getElementAt(int index) { return ownersList.get(index); } }); List owners = Settings.get().getTrackerSettings().getSelectedOwners(); if (owners == null) { jOwners.selectAll(); } else { ListModel model = jOwners.getModel(); for (int i = 0; i < model.getSize(); i++) { String ownerName = model.getElementAt(i); if (owners.contains(ownerName)) { jOwners.addSelectionInterval(i, i); } } } } updateLock = false; } private void updateNodes() { accountNodes.clear(); assetNodes.clear(); //Find all saved Keys/IDs Set walletIDs = new TreeSet<>(); Set assetsIDs = new TreeSet<>(); try { TrackerData.readLock(); for (List list : TrackerData.get().values()) { for (Value data : list) { //Get all account wallet account keys walletIDs.addAll(data.getBalanceFilter().keySet()); //Get all asset IDs assetsIDs.addAll(data.getAssetsFilter().keySet()); } } } finally { TrackerData.readUnlock(); } //WALLET - Make nodes for found wallet account keys CheckBoxNode corporationWalletNode = new CheckBoxNode(null, TabsTracker.get().corporationWallet(), TabsTracker.get().corporationWallet(), false); for (String id : walletIDs) { accountNodes.put(id, new CheckBoxNode(corporationWalletNode, id, TabsTracker.get().division(id), selectNode(id))); } String characterWalletID = "0"; CheckBoxNode characterWalletNode = new CheckBoxNode(null, characterWalletID, TabsTracker.get().characterWallet(), selectNode(characterWalletID)); accountNodes.put(characterWalletID, characterWalletNode); //ASSETS - Make nodes for found asset IDs CheckBoxNode assetNode = new CheckBoxNode(null, TabsTracker.get().assets(), TabsTracker.get().assets(), false); assetNodes.put(assetNode.getNodeID(), assetNode); CheckBoxNode knownLocationsNode = new CheckBoxNode(assetNode, TabsTracker.get().knownLocations(), TabsTracker.get().knownLocations(), false); assetNodes.put(knownLocationsNode.getNodeID(), knownLocationsNode); CheckBoxNode unknownLocationsNode = new CheckBoxNode(assetNode, TabsTracker.get().unknownLocations(), TabsTracker.get().unknownLocations(), false); assetNodes.put(unknownLocationsNode.getNodeID(), unknownLocationsNode); Map nodeCache = new HashMap<>(); for (AssetValue assetValue : assetsIDs) { String location = assetValue.getLocation(); String flag = assetValue.getFlag(); String id = assetValue.getID(); CheckBoxNode locationNode = nodeCache.get(location); if (locationNode == null) { if (location.startsWith("[Unknown Location #")) { locationNode = new CheckBoxNode(unknownLocationsNode, location, location, selectNode(location)); } else { locationNode = new CheckBoxNode(knownLocationsNode, location, location, selectNode(location)); } nodeCache.put(location, locationNode); assetNodes.put(locationNode.getNodeID(), locationNode); } CheckBoxNode flagNode = nodeCache.get(id); if (flagNode == null) { if (!locationNode.isParent()) { //When adding first child //Replace parent location (don't use location as ID) nodeCache.remove(location); assetNodes.remove(location); String locationNodeID = locationNode.getNodeID() + " > Parent"; if (location.startsWith("[Unknown Location #")) { locationNode = new CheckBoxNode(unknownLocationsNode, locationNodeID, location, selectNode(locationNodeID)); } else { locationNode = new CheckBoxNode(knownLocationsNode, locationNodeID, location, selectNode(locationNodeID)); } nodeCache.put(location, locationNode); assetNodes.put(locationNodeID, locationNode); //Other Node (use the location as ID) CheckBoxNode otherNode = new CheckBoxNode(locationNode, location, TabsTracker.get().other(), selectNode(location)); assetNodes.put(location, otherNode); } flagNode = new CheckBoxNode(locationNode, id, ApiIdConverter.getFlagName(flag), selectNode(id)); nodeCache.put(id, flagNode); } assetNodes.put(id, flagNode); } } private boolean selectNode(String id) { Boolean selected = Settings.get().getTrackerSettings().getFilters().get(id); if (selected != null) { return selected; } else { return Settings.get().getTrackerSettings().isSelectNew(); } } private void createData() { if (updateLock) { return; } List owners = jOwners.getSelectedValuesList(); walletBalance = new TimePeriodValues(TabsTracker.get().walletBalance()); assets = new TimePeriodValues(TabsTracker.get().assets()); implants = new TimePeriodValues(TabsTracker.get().implants()); sellOrders = new TimePeriodValues(TabsTracker.get().sellOrders()); escrows = new TimePeriodValues(TabsTracker.get().escrows()); escrowsToCover = new TimePeriodValues(TabsTracker.get().escrowsToCover()); manufacturing = new TimePeriodValues(TabsTracker.get().manufacturing()); contractCollateral = new TimePeriodValues(TabsTracker.get().contractCollateral()); contractValue = new TimePeriodValues(TabsTracker.get().contractValue()); skillPointsValue = new TimePeriodValues(TabsTracker.get().skillPointValue()); Date from = getFromDate(); Date to = getToDate(); cache = new TreeMap<>(); Map accountNodesMap = new HashMap<>(accountNodes); Map assetNodesMap = new HashMap<>(assetNodes); Map assetNoFilterColumns = new TreeMap<>(); Map assetBuggedFilterColumns = new TreeMap<>(); Map walletColumns = new TreeMap<>(); if (owners != null) { //No data set... try { TrackerData.readLock(); Map> trackerDataByDate = getTrackerDataByDate(owners); Map lastMap = new HashMap<>(); for (Map.Entry> dateEntry : trackerDataByDate.entrySet()) { final Date date = dateEntry.getKey(); final Value value; if ((from == null || date.after(from)) && (to == null || date.before(to))) { value = new Value(date); cache.put(new SimpleTimePeriod(date, date), value); } else { continue; } for (Map.Entry ownerEntry : dateEntry.getValue().entrySet()) { Value data = ownerEntry.getValue(); if (data == null) { Value last = lastMap.get(ownerEntry.getKey()); if (last != null) { data = last; } } if (data == null) { continue; } else { lastMap.put(ownerEntry.getKey(), data); } //Assets containers fixed assetBuggedFilterColumns.put(date, data.isAssetsContainersFixed()); //Assets Filters if (data.getAssetsFilter().isEmpty()) { value.addAssets(data.getAssetsTotal()); //Default Boolean assetBoolean = assetNoFilterColumns.get(date); if (assetBoolean == null) { assetNoFilterColumns.put(date, false); } } else { assetNoFilterColumns.put(date, true); for (Map.Entry entry : data.getAssetsFilter().entrySet()) { if (assetNodesMap.get(entry.getKey().getID()).isSelected()) { value.addAssets(entry.getValue()); } } } value.addEscrows(data.getEscrows()); value.addEscrowsToCover(data.getEscrowsToCover()); value.addManufacturing(data.getManufacturing()); value.addContractCollateral(data.getContractCollateral()); value.addContractValue(data.getContractValue()); TrackerSkillPointFilter skillPointFilter = Settings.get().getTrackerSettings().getSkillPointFilters().get(ownerEntry.getKey()); if (skillPointFilter != null) { if (skillPointFilter.isEnabled()) { value.addSkillPointValue(data.getSkillPoints(), skillPointFilter.getMinimum()); } } else { value.addSkillPointValue(data.getSkillPoints(), 0); } value.addImplants(data.getImplants()); value.addSellOrders(data.getSellOrders()); if (data.getBalanceFilter().isEmpty()) { value.addBalance(data.getBalanceTotal()); //Default Boolean walletBoolean = walletColumns.get(date); if (walletBoolean == null) { walletColumns.put(date, false); } } else { walletColumns.put(date, true); for (Map.Entry entry : data.getBalanceFilter().entrySet()) { if (accountNodesMap.get(entry.getKey()).isSelected()) { value.addBalance(entry.getValue()); } } } } } } finally { TrackerData.readUnlock(); } for (Map.Entry entry : cache.entrySet()) { walletBalance.add(entry.getKey(), entry.getValue().getBalanceTotal()); assets.add(entry.getKey(), entry.getValue().getAssetsTotal()); implants.add(entry.getKey(), entry.getValue().getImplants()); sellOrders.add(entry.getKey(), entry.getValue().getSellOrders()); escrows.add(entry.getKey(), entry.getValue().getEscrows()); escrowsToCover.add(entry.getKey(), entry.getValue().getEscrowsToCover()); manufacturing.add(entry.getKey(), entry.getValue().getManufacturing()); contractCollateral.add(entry.getKey(), entry.getValue().getContractCollateral()); contractValue.add(entry.getKey(), entry.getValue().getContractValue()); skillPointsValue.add(entry.getKey(), entry.getValue().getSkillPointValue()); } } int count; count = 0; assetNoFilterColumn = assetNoFilterColumns.size(); //Default for (Map.Entry entry : assetNoFilterColumns.entrySet()) { if (entry.getValue()) { assetNoFilterColumn = count; break; } count++; } count = 0; assetBuggedFilterColumn = assetBuggedFilterColumns.size(); //Default for (Map.Entry entry : assetBuggedFilterColumns.entrySet()) { if (entry.getValue()) { assetBuggedFilterColumn = count; break; } count++; } count = 0; walletColumn = walletColumns.size(); //Default for (Map.Entry entry : walletColumns.entrySet()) { if (entry.getValue()) { walletColumn = count; break; } count++; } updateShown(); } private Map> getTrackerDataByDate(final List owners) { Map> trackerDataByDate = new TreeMap<>(); Map empty = new HashMap<>(); for (String owner : owners) { empty.put(owner, null); } for (String owner : owners) { for (Value data : TrackerData.get().get(owner)) { Date key = data.getDate(); Map map = trackerDataByDate.get(key); if (map == null) { map = new HashMap<>(empty); trackerDataByDate.put(key, map); } map.put(owner, data); } } return trackerDataByDate; } private void updateButtonIcons() { boolean isAll; boolean isSome; //Assets isAll = true; isSome = false; for (CheckBoxNode node : assetNodes.values()) { if (!node.isSelected()) { isAll = false; } if (node.isSelected()) { isSome = true; } } if (isAll) { jAssetsFilters.setIcon(Images.LOC_INCLUDE.getIcon()); } else if (isSome) { jAssetsFilters.setIcon(Images.EDIT_EDIT_WHITE.getIcon()); } else { jAssetsFilters.setIcon(Images.UPDATE_DONE_ERROR.getIcon()); } //Wallet isAll = true; isSome = false; for (CheckBoxNode node : accountNodes.values()) { if (!node.isSelected()) { isAll = false; } if (node.isSelected()) { isSome = true; } } if (isAll) { jWalletBalanceFilters.setIcon(Images.LOC_INCLUDE.getIcon()); } else if (isSome) { jWalletBalanceFilters.setIcon(Images.EDIT_EDIT_WHITE.getIcon()); } else { jWalletBalanceFilters.setIcon(Images.UPDATE_DONE_ERROR.getIcon()); } isAll = true; for (TrackerSkillPointFilter filter : Settings.get().getTrackerSettings().getSkillPointFilters().values()) { if (!filter.isEmpty()) { isAll = false; break; } } if (isAll) { jSkillPointsFilters.setIcon(Images.LOC_INCLUDE.getIcon()); } else { jSkillPointsFilters.setIcon(Images.EDIT_EDIT_WHITE.getIcon()); } } private void updateShown() { //Remove All while (dataset.getSeriesCount() != 0) { dataset.removeSeries(0); } renderer.clear(); TimePeriodValues total = new TimePeriodValues(TabsTracker.get().total()); Value first = null; Value last = null; Double firstTotal = null; Double lastTotal = null; for (Map.Entry entry : cache.entrySet()) { double t = 0; if (jWalletBalance.isSelected() && walletBalance != null) { t += entry.getValue().getBalanceTotal(); } if (jAssets.isSelected() && assets != null) { t += entry.getValue().getAssetsTotal(); } if (jImplants.isSelected() && implants != null) { t += entry.getValue().getImplants(); } if (jSellOrders.isSelected() && sellOrders != null) { t += entry.getValue().getSellOrders(); } if (jEscrows.isSelected() && escrows != null) { t += entry.getValue().getEscrows(); } //Escrows To Cover is not money you own, it's technically money you owe //Therefore, it's not included in the total //See: https://forums-archive.eveonline.com/message/6607898#post6607898 //if (jEscrowsToCover.isSelected() && escrowsToCover != null) { // t += entry.getValue().getEscrowsToCover(); //} if (jManufacturing.isSelected() && manufacturing != null) { t += entry.getValue().getManufacturing(); } if (jContractCollateral.isSelected() && contractCollateral != null) { t += entry.getValue().getContractCollateral(); } if (jContractValue.isSelected() && contractValue != null) { t += entry.getValue().getContractValue(); } if (jSkillPointsValue.isSelected() && skillPointsValue != null) { t += entry.getValue().getSkillPointValue(); } total.add(entry.getKey(), t); if (firstTotal == null) { firstTotal = t; } lastTotal = t; if (first == null) { first = entry.getValue(); } last = entry.getValue(); } if (firstTotal != null && lastTotal != null) { jTotalStatus.setNumber(lastTotal - firstTotal); } else { jTotalStatus.setNumber(0.0); } jWalletBalanceStatus.setVisible(jWalletBalance.isSelected()); if (first != null && last != null) { jWalletBalanceStatus.setNumber(last.getBalanceTotal() - first.getBalanceTotal()); } else { jWalletBalanceStatus.setNumber(0.0); } jAssetsStatus.setVisible(jAssets.isSelected()); if (first != null && last != null) { jAssetsStatus.setNumber(last.getAssetsTotal() - first.getAssetsTotal()); } else { jAssetsStatus.setNumber(0.0); } jImplantsStatus.setVisible(jImplants.isSelected()); if (first != null && last != null) { jImplantsStatus.setNumber(last.getImplants() - first.getImplants()); } else { jImplantsStatus.setNumber(0.0); } jSellOrdersStatus.setVisible(jSellOrders.isSelected()); if (first != null && last != null) { jSellOrdersStatus.setNumber(last.getSellOrders() - first.getSellOrders()); } else { jSellOrdersStatus.setNumber(0.0); } jEscrowsStatus.setVisible(jEscrows.isSelected()); if (first != null && last != null) { jEscrowsStatus.setNumber(last.getEscrows() - first.getEscrows()); } else { jEscrowsStatus.setNumber(0.0); } jEscrowsToCoverStatus.setVisible(jEscrowsToCover.isSelected()); if (first != null && last != null) { jEscrowsToCoverStatus.setNumber(last.getEscrowsToCover() - first.getEscrowsToCover()); } else { jEscrowsToCoverStatus.setNumber(0.0); } jManufacturingStatus.setVisible(jManufacturing.isSelected()); if (first != null && last != null) { jManufacturingStatus.setNumber(last.getManufacturing() - first.getManufacturing()); } else { jManufacturingStatus.setNumber(0.0); } jContractCollateralStatus.setVisible(jContractCollateral.isSelected()); if (first != null && last != null) { jContractCollateralStatus.setNumber(last.getContractCollateral() - first.getContractCollateral()); } else { jContractCollateralStatus.setNumber(0.0); } jContractValueStatus.setVisible(jContractValue.isSelected()); if (first != null && last != null) { jContractValueStatus.setNumber(last.getContractValue() - first.getContractValue()); } else { jContractValueStatus.setNumber(0.0); } jSkillPointsStatus.setVisible(jSkillPointsValue.isSelected()); if (first != null && last != null) { jSkillPointsStatus.setNumber(last.getSkillPointValue()- first.getSkillPointValue()); } else { jSkillPointsStatus.setNumber(0.0); } //Update Shown boolean bright = ColorUtil.isBrightColor(jPanel.getBackground()); if (jTotal.isSelected()) { //Update total dataset.addSeries(total); Integer minNoFilterColumn = null; Integer minBuggedFilterColumn = null; if (jWalletBalance.isSelected() && walletColumn != null) { minNoFilterColumn = walletColumn; } if (jAssets.isSelected()) { if (assetNoFilterColumn != null) { if (minNoFilterColumn != null) { minNoFilterColumn = Math.min(minNoFilterColumn, assetNoFilterColumn); } else { minNoFilterColumn = assetNoFilterColumn; } } if (assetBuggedFilterColumn != null) { if (minBuggedFilterColumn != null) { minBuggedFilterColumn = Math.min(minBuggedFilterColumn, assetBuggedFilterColumn); } else { minBuggedFilterColumn = assetBuggedFilterColumn; } } } renderer.addNoFilter(dataset.getSeriesCount() - 1, minNoFilterColumn); renderer.addBuggedFilter(dataset.getSeriesCount() - 1, minBuggedFilterColumn); updateRender(bright, dataset.getSeriesCount() - 1, Color.RED.darker()); } if (jWalletBalance.isSelected() && walletBalance != null) { dataset.addSeries(walletBalance); renderer.addNoFilter(dataset.getSeriesCount() - 1, walletColumn); updateRender(bright, dataset.getSeriesCount() - 1, Color.BLUE.darker()); } if (jAssets.isSelected() && assets != null) { dataset.addSeries(assets); renderer.addNoFilter(dataset.getSeriesCount() - 1, assetNoFilterColumn); renderer.addBuggedFilter(dataset.getSeriesCount() - 1, assetBuggedFilterColumn); updateRender(bright, dataset.getSeriesCount() - 1, Color.GREEN.darker().darker()); } if (jImplants.isSelected() && implants != null) { dataset.addSeries(implants); updateRender(bright, dataset.getSeriesCount() - 1, Color.MAGENTA.darker()); } if (jSellOrders.isSelected() && sellOrders != null) { dataset.addSeries(sellOrders); updateRender(bright, dataset.getSeriesCount() - 1, Color.CYAN.darker()); } if (jEscrows.isSelected() && escrows != null) { dataset.addSeries(escrows); updateRender(bright, dataset.getSeriesCount() - 1, Color.BLACK); } if (jEscrowsToCover.isSelected() && escrowsToCover != null) { dataset.addSeries(escrowsToCover); updateRender(bright, dataset.getSeriesCount() - 1, Color.GRAY); } if (jManufacturing.isSelected() && manufacturing != null) { dataset.addSeries(manufacturing); updateRender(bright, dataset.getSeriesCount() - 1, Color.MAGENTA); } if (jContractCollateral.isSelected() && contractCollateral != null) { dataset.addSeries(contractCollateral); updateRender(bright, dataset.getSeriesCount() - 1, Color.PINK); } if (jContractValue.isSelected() && contractValue != null) { dataset.addSeries(contractValue); updateRender(bright, dataset.getSeriesCount() - 1, Color.ORANGE); } if (jSkillPointsValue.isSelected() && skillPointsValue != null) { dataset.addSeries(skillPointsValue); updateRender(bright, dataset.getSeriesCount() - 1, Color.YELLOW); } //Add empty dataset if (dataset.getSeriesCount() == 0) { TimePeriodValues timePeriodValues = new TimePeriodValues(TabsTracker.get().empty()); dataset.addSeries(timePeriodValues); updateRender(bright, dataset.getSeriesCount() - 1, Color.BLACK); } rangeLogarithmicAxis.setAutoRange(true); rangeLinearAxis.setAutoRange(true); jFreeChart.getXYPlot().getDomainAxis().setAutoRange(true); JFreeChartUtil.updateTickScale(domainAxis, rangeLinearAxis, dataset); } private void updateRender(boolean bright, int index, Color color) { if (Settings.get().isEasyChartColors()) { if (bright) { if (ColorUtil.luminance(color) > 0.8) { color = color.darker(); } } else { if (ColorUtil.luminance(color) < 0.2) { color = color.brighter(); } } } renderer.setSeriesPaint(index, color); renderer.setSeriesStroke(index, new BasicStroke(1)); } private void updateSettings() { Settings.lock("Tracker Filters: Update"); Settings.get().getTrackerSettings().getFilters().clear(); for (CheckBoxNode checkBoxNode : assetNodes.values()) { if (checkBoxNode.isParent()) { continue; } Settings.get().getTrackerSettings().getFilters().put(checkBoxNode.getNodeID(), checkBoxNode.isSelected()); } for (CheckBoxNode checkBoxNode : accountNodes.values()) { Settings.get().getTrackerSettings().getFilters().put(checkBoxNode.getNodeID(), checkBoxNode.isSelected()); } Settings.get().getTrackerSettings().setSelectNew(assetFilterDialog.isSelectNew()); Settings.unlock("Tracker Filters: Update"); program.saveSettings("Tracker Filters: Update"); } private String getSelectedOwner(boolean all) { List owners = jOwners.getSelectedValuesList(); if (owners.size() == 1) { return jOwners.getSelectedValue(); } else { List list = new ArrayList<>(); if (all) { list.add(General.get().all()); } for (String owner : owners) { Value value = getSelectedValue(owner); if (value != null) { list.add(owner); } } return jSelectionDialog.show(TabsTracker.get().selectOwner(), list); } } private Value getSelectedValue(String owner) { String date = Formatter.simpleDate(new Date((long)jFreeChart.getXYPlot().getDomainCrosshairValue())); try { TrackerData.readLock(); for (Value value : TrackerData.get().get(owner)) { if (date.equals(Formatter.simpleDate(value.getDate()))) { return value; } } } finally { TrackerData.readUnlock(); } return null; } private void addNote() { Date date = new Date((long)jFreeChart.getXYPlot().getDomainCrosshairValue()); TrackerNote trackerNote = Settings.get().getTrackerSettings().getNotes().get(new TrackerDate(date)); String newNote; if (trackerNote == null) { newNote = JOptionInput.showInputDialog(program.getMainWindow().getFrame(), TabsTracker.get().notesEditMsg(), TabsTracker.get().notesEditTitle(), JOptionPane.PLAIN_MESSAGE); } else { newNote = (String) JOptionInput.showInputDialog(program.getMainWindow().getFrame(), TabsTracker.get().notesEditMsg(), TabsTracker.get().notesEditTitle(), JOptionPane.PLAIN_MESSAGE, null, null, trackerNote.getNote()); } if (newNote != null) { Settings.lock("Tracker Notes (Set Note)"); Settings.get().getTrackerSettings().getNotes().put(new TrackerDate(date), new TrackerNote(newNote)); Settings.unlock("Tracker Notes (Set Note)"); program.saveSettings("Tracker Data (Set Note)"); } } private void removeNote() { Date date = new Date((long)jFreeChart.getXYPlot().getDomainCrosshairValue()); TrackerNote trackerNote = Settings.get().getTrackerSettings().getNotes().get(new TrackerDate(date)); int returnValue = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), TabsTracker.get().notesDeleteMsg(trackerNote.getNote()), TabsTracker.get().notesDeleteTitle(), JOptionPane.OK_CANCEL_OPTION); if (returnValue == JOptionPane.OK_OPTION) { Settings.lock("Tracker Notes (Delete Note)"); Settings.get().getTrackerSettings().getNotes().remove(new TrackerDate(date)); Settings.unlock("Tracker Notes (Delete Note)"); program.saveSettings("Tracker Data (Delete Note)"); } } private class MyDrawingSupplier extends DefaultDrawingSupplier { @Override public Shape getNextShape() { return FILTER_AND_DEFAULT; } } private class MyRenderer extends SimpleRenderer { private final Map noFilters = new HashMap<>(); private final Map buggedFilters = new HashMap<>(); public MyRenderer() { super(true, true); } @Override public Shape getItemShape(int row, int column) { Integer noFiltersColumn = noFilters.get(row); Integer buggedFiltersColumn = buggedFilters.get(row); if (noFiltersColumn != null && noFiltersColumn > column) { return NO_FILTER; } else if (buggedFiltersColumn != null && buggedFiltersColumn > column) { return BUG_CORP_CONTAINERS_FILTER; } else { return FILTER_AND_DEFAULT; } } public void clear() { noFilters.clear(); buggedFilters.clear(); } public void addNoFilter(int row, Integer column) { if (column != null) { noFilters.put(row, column); } } public void addBuggedFilter(int row, Integer column) { if (column != null) { buggedFilters.put(row, column); } } } private static class ShapeIcon implements Icon { private final Shape shape; private final Color color; public ShapeIcon(Shape shape, Color color) { this.shape = shape; this.color = color; } public ShapeIcon(Shape shape) { this(shape, Color.BLACK); } @Override public void paintIcon(Component c, Graphics g, int x, int y) { Graphics2D g2d = (Graphics2D)g.create(); RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHints(rh); g2d.setColor(color); g2d.translate(x - shape.getBounds().x, y - shape.getBounds().y); g2d.fill(shape); g2d.dispose(); } @Override public int getIconWidth() { return shape.getBounds().width; } @Override public int getIconHeight() { return shape.getBounds().height; } } private Date getFromDate() { LocalDate date = jFrom.getDate(); if (date == null) { return null; } Instant instant = date.atStartOfDay().atZone(ZoneId.of("GMT")).toInstant(); //Start of day - GMT return Date.from(instant); } private Date getToDate() { LocalDate date = jTo.getDate(); if (date == null) { return null; } Instant instant = date.atTime(23, 59, 59).atZone(ZoneId.of("GMT")).toInstant(); //End of day - GMT return Date.from(instant); } private void showLocationFilter() { boolean save = assetFilterDialog.showLocations(assetNodes); if (save) { //Need refilter updateSettings(); createData(); updateButtonIcons(); } else if (assetFilterDialog.isSelectNew() != Settings.get().getTrackerSettings().isSelectNew()) { Settings.lock("Tracker Filters: Update"); Settings.get().getTrackerSettings().setSelectNew(assetFilterDialog.isSelectNew()); Settings.unlock("Tracker Filters: Update"); program.saveSettings("Tracker Filters: Update"); } } private class ListenerClass implements ActionListener, PopupMenuListener, ChartMouseListener, ListSelectionListener, DateChangeListener { @Override public void actionPerformed(ActionEvent e) { TrackerSettings trackerSettings = Settings.get().getTrackerSettings(); if (TrackerAction.QUICK_DATE.name().equals(e.getActionCommand())) { QuickDate quickDate = (QuickDate) jQuickDate.getSelectedItem(); if (quickDate == QuickDate.RESET) { jTo.clearDate(); jFrom.clearDate(); } else { Date toDate = getToDate(); if (toDate == null) { toDate = new Date(); //now } Date fromDate = quickDate.apply(toDate); if (fromDate != null) { jFrom.setDate(fromDate); } } trackerSettings.setFromDate(getFromDate()); trackerSettings.setToDate(getToDate()); updateSettings(); } else if (TrackerAction.INCLUDE_ZERO.name().equals(e.getActionCommand())) { rangeLogarithmicAxis.setAutoRangeIncludesZero(jIncludeZero.isSelected()); rangeLinearAxis.setAutoRangeIncludesZero(jIncludeZero.isSelected()); trackerSettings.setIncludeZero(jIncludeZero.isSelected()); updateSettings(); } else if (TrackerAction.LOGARITHMIC.name().equals(e.getActionCommand())) { if (jLogarithmic.isSelected()) { jFreeChart.getXYPlot().setRangeAxis(rangeLogarithmicAxis); trackerSettings.setDisplayType(DisplayType.LOGARITHMIC); } else { jFreeChart.getXYPlot().setRangeAxis(rangeLinearAxis); trackerSettings.setDisplayType(DisplayType.LINEAR); } updateSettings(); } else if (TrackerAction.UPDATE_DATA.name().equals(e.getActionCommand())) { createData(); } else if (TrackerAction.UPDATE_SHOWN.name().equals(e.getActionCommand())) { updateShown(); jAll.setSelected(jTotal.isSelected() && jWalletBalance.isSelected() && jAssets.isSelected() && jImplants.isSelected() && jSellOrders.isSelected() && jEscrows.isSelected() && jEscrowsToCover.isSelected() && jManufacturing.isSelected() && jContractCollateral.isSelected() && jContractValue.isSelected() && jSkillPointsValue.isSelected()); if (jAll.isSelected()) { jShow.setIcon(Images.LOC_INCLUDE.getIcon()); trackerSettings.getShowOptions().clear(); trackerSettings.getShowOptions().add(ShowOption.ALL); } else { jShow.setIcon(Images.EDIT_EDIT_WHITE.getIcon()); trackerSettings.getShowOptions().clear(); if (jTotal.isSelected()) { trackerSettings.getShowOptions().add(ShowOption.TOTAL); } if (jWalletBalance.isSelected()) { trackerSettings.getShowOptions().add(ShowOption.WALLET); } if (jAssets.isSelected()) { trackerSettings.getShowOptions().add(ShowOption.ASSET); } if (jImplants.isSelected()) { trackerSettings.getShowOptions().add(ShowOption.IMPLANT); } if (jSellOrders.isSelected()) { trackerSettings.getShowOptions().add(ShowOption.SELL_ORDER); } if (jEscrows.isSelected()) { trackerSettings.getShowOptions().add(ShowOption.ESCROW); } if (jEscrowsToCover.isSelected()) { trackerSettings.getShowOptions().add(ShowOption.ESCROW_TO_COVER); } if (jManufacturing.isSelected()) { trackerSettings.getShowOptions().add(ShowOption.MANUFACTURING); } if (jContractCollateral.isSelected()) { trackerSettings.getShowOptions().add(ShowOption.COLLATERAL); } if (jContractValue.isSelected()) { trackerSettings.getShowOptions().add(ShowOption.CONTRACT); } if (jSkillPointsValue.isSelected()) { trackerSettings.getShowOptions().add(ShowOption.SKILL_POINT); } } updateSettings(); } else if (TrackerAction.ALL.name().equals(e.getActionCommand())) { jTotal.setSelected(jAll.isSelected()); jWalletBalance.setSelected(jAll.isSelected()); jAssets.setSelected(jAll.isSelected()); jImplants.setSelected(jAll.isSelected()); jSellOrders.setSelected(jAll.isSelected()); jEscrows.setSelected(jAll.isSelected()); jEscrowsToCover.setSelected(jAll.isSelected()); jManufacturing.setSelected(jAll.isSelected()); jContractCollateral.setSelected(jAll.isSelected()); jContractValue.setSelected(jAll.isSelected()); jSkillPointsValue.setSelected(jAll.isSelected()); trackerSettings.getShowOptions().clear(); if (jAll.isSelected()) { jShow.setIcon(Images.LOC_INCLUDE.getIcon()); trackerSettings.getShowOptions().add(ShowOption.ALL); } else { jShow.setIcon(Images.EDIT_EDIT_WHITE.getIcon()); } updateShown(); updateSettings(); } else if (TrackerAction.EDIT.name().equals(e.getActionCommand())) { jFreeChart.getXYPlot().setDomainCrosshairVisible(true); String owner = getSelectedOwner(false); if (owner == null) { return; } Value value = getSelectedValue(owner); if (value == null) { return; } boolean update = jEditDialog.showEdit(value); if (update) { createData(); } jFreeChart.getXYPlot().setDomainCrosshairVisible(false); } else if (TrackerAction.DELETE.name().equals(e.getActionCommand())) { jFreeChart.getXYPlot().setDomainCrosshairVisible(true); String owner = getSelectedOwner(true); if (owner == null) { return; } List owners = new ArrayList<>(); if (owner.equals(General.get().all())) { owners.addAll(jOwners.getSelectedValuesList()); } else { owners.add(owner); } Map values = new HashMap<>(); for (String s : owners) { Value value = getSelectedValue(s); if (value != null) { values.put(s, value); } } if (values.isEmpty()) { return; } int retrunValue = JOptionPane.showConfirmDialog(program.getMainWindow().getFrame(), TabsTracker.get().deleteSelected(), TabsTracker.get().delete(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (retrunValue == JOptionPane.OK_OPTION) { for (Map.Entry entry : values.entrySet()) { //Remove value TrackerData.remove(entry.getKey(), entry.getValue()); } TrackerData.save("Deleted"); updateData(); } jFreeChart.getXYPlot().setDomainCrosshairVisible(false); } else if (TrackerAction.NOTE_DELETE.name().equals(e.getActionCommand())) { jFreeChart.getXYPlot().setDomainCrosshairVisible(true); removeNote(); jFreeChart.getXYPlot().setDomainCrosshairVisible(false); } else if (TrackerAction.NOTE_ADD.name().equals(e.getActionCommand())) { jFreeChart.getXYPlot().setDomainCrosshairVisible(true); addNote(); jFreeChart.getXYPlot().setDomainCrosshairVisible(false); } else if (TrackerAction.PROFILE.name().equals(e.getActionCommand())) { if (!updateLock) { boolean allProfiles = jAllProfiles.isSelected(); boolean characterCorporations = jCharacterCorporations.isSelected(); trackerSettings.setAllProfiles(allProfiles); trackerSettings.setCharacterCorporations(characterCorporations); program.saveSettings("Tracker (Owner Settings)"); } updateData(); } else if (TrackerAction.FILTER_WALLET_BALANCE.name().equals(e.getActionCommand())) { boolean save = walletFilterDialog.showWallet(accountNodes); if (save) { //Need refilter updateSettings(); createData(); updateButtonIcons(); } } else if (TrackerAction.FILTER_ASSETS.name().equals(e.getActionCommand())) { showLocationFilter(); } else if (TrackerAction.FILTER_SKILL_POINTS.name().equals(e.getActionCommand())) { showSkillPointsFilter(); } else if (TrackerAction.IMPORT_FILE.name().equals(e.getActionCommand())) { jFileChooser.setCurrentDirectory(new File(FileUtil.getPathDataDirectory())); int value = jFileChooser.showOpenDialog(program.getMainWindow().getFrame()); if (value != JCustomFileChooser.APPROVE_OPTION) { return; //Cancel } jLockWindow.show(TabsTracker.get().importFileImport(), new ImportFileLockWorker(jFileChooser.getSelectedFile())); } } @Override public void dateChanged(DateChangeEvent event) { Date from = getFromDate(); Date to = getToDate(); QuickDate quickDate = (QuickDate) jQuickDate.getSelectedItem(); if (!quickDate.isValid(from, to)) { QuickDate selected = quickDate.getSelected(from, to); jQuickDate.setSelectedItem(selected); } if (from != null && to != null && from.after(to)) { jTo.setDate(from); } Settings.get().getTrackerSettings().setFromDate(getFromDate()); Settings.get().getTrackerSettings().setToDate(getToDate()); createData(); } @Override public void chartMouseClicked(final ChartMouseEvent cme) { if (cme.getTrigger().getClickCount() % 2 == 0) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (cache.isEmpty()) { return; } jFreeChart.getXYPlot().setDomainCrosshairVisible(true); double xValue = jFreeChart.getXYPlot().getDomainCrosshairValue(); double yValue = jFreeChart.getXYPlot().getRangeCrosshairValue(); RectangleEdge xEdge = jFreeChart.getXYPlot().getDomainAxisEdge(); RectangleEdge yEdge = jFreeChart.getXYPlot().getRangeAxisEdge(); Rectangle2D dataArea = jChartPanel.getScreenDataArea(); // jChartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(0).getDataArea(); int x = (int) jFreeChart.getXYPlot().getDomainAxis().valueToJava2D(xValue, dataArea, xEdge); int y = (int) jFreeChart.getXYPlot().getRangeAxis().valueToJava2D(yValue, dataArea, yEdge); Date date = new Date((long)xValue); values.clear(); JMenuItem jIskValue = JMenuInfo.createMenuItem(values, jPopupMenu, yValue, JMenuInfo.AutoNumberFormat.ISK, TabsTracker.get().selectionIsk(), TabsTracker.get().selectionShortIsk(), Images.TOOL_VALUES.getIcon()); JMenuItem jDateValue = JMenuInfo.createMenuItem(values, jPopupMenu, Formatter.columnDateOnly(date), TabsTracker.get().selectionDate(), TabsTracker.get().selectionShortDate(), Images.EDIT_DATE.getIcon()); TrackerNote trackerNote = Settings.get().getTrackerSettings().getNotes().get(new TrackerDate(date)); JMenuItem jNote; if (trackerNote != null) { jAddNote.setVisible(false); jEditNote.setVisible(true); jNote = JMenuInfo.createMenuItem(values, jPopupMenu, trackerNote.getNote(), TabsTracker.get().selectionNote(), TabsTracker.get().selectionShortNote(), Images.SETTINGS_USER_NAME.getIcon()); } else { jAddNote.setVisible(true); jEditNote.setVisible(false); jNote = null; } jPopupMenu.addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { jPopupMenu.remove(jIskValue); jPopupMenu.remove(jDateValue); if (jNote != null) { jPopupMenu.remove(jNote); } } @Override public void popupMenuCanceled(PopupMenuEvent e) { } }); jPopupMenu.show((Component)cme.getTrigger().getSource(), x, y); } }); } } @Override public void chartMouseMoved(ChartMouseEvent cme) { } @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { jFreeChart.getXYPlot().setDomainCrosshairVisible(false); } @Override public void popupMenuCanceled(PopupMenuEvent e) { } @Override public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } if (!updateLock) { List selectedOwners = jOwners.getSelectedValuesList(); Settings.get().getTrackerSettings().setSelectedOwners(selectedOwners); program.saveSettings("Tracker (Owners Selection)"); } updateFilterButtons(); createData(); } } private class ImportFileLockWorker extends LockWorkerAdaptor { private File file; private Map> trackerData = null; public ImportFileLockWorker(File file) { this.file = file; } @Override public void task() { File unzippedFile = null; String extension = FileUtil.getExtension(file); if (extension.equals("zip")) { //Unzip file (if needed) ZipInputStream zis = null; try { zis = new ZipInputStream(new FileInputStream(file)); ZipEntry zipEntry = zis.getNextEntry(); while(zipEntry != null) { String filename = zipEntry.getName(); if (filename.equals("settings.xml") || filename.equals("tracker.json")) { unzippedFile = new File(FileUtil.getPathDataDirectory() + File.separator + "temp_" + filename); if (unzippedFile.toPath().normalize().startsWith(FileUtil.getPathDataDirectory() + File.separator)) { //Make sure path is correct FileOutputStream fos = new FileOutputStream(unzippedFile); byte[] buffer = new byte[1024]; int len; while ((len = zis.read(buffer)) > 0) { fos.write(buffer, 0, len); } fos.close(); //Set file and extension to the unzipped file file = unzippedFile; extension = FileUtil.getExtension(file); break; } } zipEntry = zis.getNextEntry(); } zis.closeEntry(); zis.close(); } catch (IOException ex) { //Ignore errors } finally { try { if (zis != null) { zis.close(); } } catch (IOException ex) { } } } switch (extension) { //Load data (if possible) case "xml": case "backup": trackerData = SettingsReader.loadTracker(file.getAbsolutePath()); break; case "json": trackerData = TrackerReader.load(file.getAbsolutePath(), false); break; default: trackerData = null; break; } if (unzippedFile != null) { //Clean up temp file unzippedFile.delete(); } } @Override public void hidden() { if (trackerData == null) { //Invalid file JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsTracker.get().importFileInvalidMsg(), TabsTracker.get().importFileTitle(), JOptionPane.WARNING_MESSAGE); return; } //Overwrite? Object value = JOptionPane.showInputDialog(program.getMainWindow().getFrame(), TabsTracker.get().importFileOptionsMsg(), TabsTracker.get().importFileTitle(), JOptionPane.PLAIN_MESSAGE, null, ImportOptions.values(), ImportOptions.KEEP); if (value == null) { return; //Cancel } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { jLockWindow.show(TabsTracker.get().importFileImport(), new LockWorkerAdaptor() { @Override public void task() { if (value == ImportOptions.REPLACE) { TrackerData.set(trackerData); } else { TrackerData.addAll(trackerData, value == ImportOptions.OVERWRITE); } TrackerData.save("File Import", true); } @Override public void gui() { updateData(); } }); } }); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tracker/TrackerWalletFilterDialog.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tracker; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.CheckBoxNode; import net.nikr.eve.jeveasset.gui.shared.components.CheckBoxNodeEditor; import net.nikr.eve.jeveasset.gui.shared.components.CheckBoxNodeRenderer; import net.nikr.eve.jeveasset.gui.shared.components.JDialogCentered; import net.nikr.eve.jeveasset.i18n.DialoguesSettings; import net.nikr.eve.jeveasset.i18n.TabsTracker; public class TrackerWalletFilterDialog extends JDialogCentered { private final JTree jTree; private final DefaultMutableTreeNode rootNode; private final DefaultTreeModel treeModel; private boolean save = false; public TrackerWalletFilterDialog(Program program) { super(program, TabsTracker.get().filterTitle(), Images.TOOL_TRACKER.getImage()); rootNode = new DefaultMutableTreeNode(DialoguesSettings.get().root()); treeModel = new DefaultTreeModel(rootNode); jTree = new JTree(treeModel); jTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); jTree.putClientProperty("JTree.lineStyle", "None"); jTree.setExpandsSelectedPaths(true); jTree.setRootVisible(false); jTree.setShowsRootHandles(true); jTree.setVisibleRowCount(0); jTree.setCellRenderer(new CheckBoxNodeRenderer()); jTree.setCellEditor(new CheckBoxNodeEditor(jTree)); jTree.setEditable(true); JButton jOK = new JButton(TabsTracker.get().ok()); jOK.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { save = true; setVisible(false); } }); JButton jCancel = new JButton(TabsTracker.get().cancel()); jCancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setVisible(false); } }); JScrollPane jTreeScroll = new JScrollPane(jTree); jTreeScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jTreeScroll, 0, GroupLayout.PREFERRED_SIZE, 600) .addGroup(layout.createSequentialGroup() .addGap(0, 0, Integer.MAX_VALUE) .addComponent(jOK, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) .addComponent(jCancel, Program.getButtonsWidth(), Program.getButtonsWidth(), Program.getButtonsWidth()) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jTreeScroll, 0, GroupLayout.PREFERRED_SIZE, 500) .addGroup(layout.createParallelGroup() .addComponent(jOK, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCancel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) ); } private DefaultMutableTreeNode add(final CheckBoxNode checkBoxNode, final DefaultMutableTreeNode parentNode) { jTree.setVisibleRowCount(jTree.getVisibleRowCount() + 1); DefaultMutableTreeNode node = new DefaultMutableTreeNode(checkBoxNode); if (parentNode == null) { treeModel.insertNodeInto(node, rootNode, rootNode.getChildCount()); } else { treeModel.insertNodeInto(node, parentNode, parentNode.getChildCount()); } return node; } private void expandAll(final TreePath parent, final boolean expand) { TreeNode node = (TreeNode) parent.getLastPathComponent(); if (node.getChildCount() >= 0) { for (Enumeration e = node.children(); e.hasMoreElements();) { TreeNode n = (TreeNode) e.nextElement(); TreePath path = parent.pathByAddingChild(n); expandAll(path, expand); } } if (expand) { jTree.expandPath(parent); } else { jTree.collapsePath(parent); } } @Override protected JComponent getDefaultFocus() { return jTree; } @Override protected JButton getDefaultButton() { return null; } @Override protected void windowShown() { } @Override protected void save() { } public boolean showWallet(Map nodes) { save = false; rootNode.removeAllChildren(); treeModel.reload(); jTree.setVisibleRowCount(0); Map cloneList = cloneList(nodes); Map cache = new HashMap<>(); for (CheckBoxNode node : cloneList.values()) { addTree(cache, node); } expandAll(new TreePath((rootNode)), true); super.setVisible(true); boolean changed = changed(cloneList, nodes); //Only need to update if something have been changed... if (save && changed) { nodes.clear(); nodes.putAll(cloneList); } return save && changed; } private Map cloneList(Map nodes) { Map clonesCache = new HashMap<>(); Map clonedNodes = new TreeMap<>(); for (Map.Entry entry : nodes.entrySet()) { clonedNodes.put(entry.getKey(), cloneTree(clonesCache, entry.getValue())); } return clonedNodes; } private DefaultMutableTreeNode addTree(Map cache, CheckBoxNode node) { //Add parents if any... CheckBoxNode checkBoxNode = node.getParent(); DefaultMutableTreeNode parentNode = null; if (checkBoxNode != null) { parentNode = addTree(cache, checkBoxNode); } //Add this node, if not already added DefaultMutableTreeNode treeNode = cache.get(node.getNodeID()); if (treeNode == null) { treeNode = add(node, parentNode); cache.put(node.getNodeID(), treeNode); } return treeNode; } private CheckBoxNode cloneTree(Map clonesCache, CheckBoxNode oldNode) { CheckBoxNode oldParent = oldNode.getParent(); CheckBoxNode cloneParent = null; if (oldParent != null) { cloneParent = cloneTree(clonesCache, oldParent); } CheckBoxNode cloneNode = clonesCache.get(oldNode.getNodeID()); if (cloneNode == null) { cloneNode = new CheckBoxNode(cloneParent, oldNode); clonesCache.put(cloneNode.getNodeID(), cloneNode); } return cloneNode; } /** * Check if the clone tree have been changed compared to the source tree * @param clone Clone Tree * @param source Source Tree * @return true if the maps are not equal. false if the maps are equal */ private boolean changed(Map clone, Map source) { for (Map.Entry entry : clone.entrySet()) { CheckBoxNode sourceNode = source.get(entry.getKey()); CheckBoxNode cloneNode = entry.getValue(); if (cloneNode.isSelected() != sourceNode.isSelected()) { return true; } } return false; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/transaction/JTransactionTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.transaction; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; public class JTransactionTable extends JAutoColumnTable { private final DefaultEventTableModel tableModel; public JTransactionTable(Program program, final DefaultEventTableModel tableModel) { super(program, tableModel); this.tableModel = tableModel; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); boolean isSelected = isCellSelected(row, column); MyTransaction transaction = tableModel.getElementAt(row); String columnName = (String) this.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); if (columnName.equals(TransactionTableFormat.NAME.getColumnName())) { if (transaction.isSell()) { ColorSettings.configCell(component, ColorEntry.TRANSACTIONS_SOLD, isSelected); } else { ColorSettings.configCell(component, ColorEntry.TRANSACTIONS_BOUGHT, isSelected); } } if (columnName.equals(TransactionTableFormat.VALUE.getColumnName()) && transaction.isBuy()) { ColorSettings.configCell(component, ColorEntry.GLOBAL_VALUE_NEGATIVE, isSelected); } //User set location if (transaction.getLocation().isUserLocation() && columnName.equals(TransactionTableFormat.LOCATION.getColumnName())) { ColorSettings.configCell(component, ColorEntry.CUSTOM_USER_LOCATION, isSelected); return component; } //Added date if (columnName.equals(TransactionTableFormat.ADDED.getColumnName()) && Settings.get().getTableChanged(TransactionTab.NAME).before(transaction.getAdded())) { ColorSettings.configCell(component, ColorEntry.TRANSACTIONS_NEW, isSelected); } return component; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/transaction/TransactionTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.transaction; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.tag.TagUpdate; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.JStatusLabel; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabPrimary; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.AutoNumberFormat; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.PaddingTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.i18n.TabsTransaction; public class TransactionTab extends JMainTabPrimary implements TagUpdate { private final JAutoColumnTable jTable; private final JStatusLabel jSellOrdersCount; private final JStatusLabel jSellOrdersTotal; private final JStatusLabel jSellOrdersAverage; private final JStatusLabel jBothOrdersCount; private final JStatusLabel jBothOrdersTotal; private final JStatusLabel jBothOrdersAverage; private final JStatusLabel jBuyOrdersCount; private final JStatusLabel jBuyOrdersTotal; private final JStatusLabel jBuyOrdersAverage; private final JButton jClearNew; //Table private final TransactionsFilterControl filterControl; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventTableModel tableModel; private final FilterList filterList; private final EventList eventList; private final DefaultEventSelectionModel selectionModel; public static final String NAME = "transaction"; //Not to be changed! public TransactionTab(final Program program) { super(program, NAME, TabsTransaction.get().title(), Images.TOOL_TRANSACTION.getIcon(), true); ListenerClass listener = new ListenerClass(); //StatusPanels must be initialized before the eventlist //Sell JLabel jSellOrders = StatusPanel.createIcon(Images.ORDERS_SELL.getIcon(), TabsTransaction.get().sellTitle()); this.addStatusbarLabel(jSellOrders); jSellOrdersCount = StatusPanel.createLabel(TabsTransaction.get().sellCount(), Images.EDIT_ADD.getIcon(), AutoNumberFormat.ITEMS); this.addStatusbarLabel(jSellOrdersCount); jSellOrdersTotal = StatusPanel.createLabel(TabsTransaction.get().sellTotal(), Images.TOOL_VALUES.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jSellOrdersTotal); jSellOrdersAverage = StatusPanel.createLabel(TabsTransaction.get().sellAvg(), Images.ASSETS_AVERAGE.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jSellOrdersAverage); //Both JLabel jBothOrders = StatusPanel.createIcon(Images.TOOL_TRANSACTION.getIcon(), TabsTransaction.get().bothTitle()); this.addStatusbarLabel(jBothOrders); jBothOrdersCount = StatusPanel.createLabel(TabsTransaction.get().bothCount(), Images.EDIT_ADD.getIcon(), AutoNumberFormat.ITEMS); this.addStatusbarLabel(jBothOrdersCount); jBothOrdersTotal = StatusPanel.createLabel(TabsTransaction.get().bothTotal(), Images.TOOL_VALUES.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jBothOrdersTotal); jBothOrdersAverage = StatusPanel.createLabel(TabsTransaction.get().bothAvg(), Images.ASSETS_AVERAGE.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jBothOrdersAverage); //Buy JLabel jBuyOrders = StatusPanel.createIcon(Images.ORDERS_BUY.getIcon(), TabsTransaction.get().buyTitle()); this.addStatusbarLabel(jBuyOrders); jBuyOrdersCount = StatusPanel.createLabel(TabsTransaction.get().buyCount(), Images.EDIT_ADD.getIcon(), AutoNumberFormat.ITEMS); this.addStatusbarLabel(jBuyOrdersCount); jBuyOrdersTotal = StatusPanel.createLabel(TabsTransaction.get().buyTotal(), Images.TOOL_VALUES.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jBuyOrdersTotal); jBuyOrdersAverage = StatusPanel.createLabel(TabsTransaction.get().buyAvg(), Images.ASSETS_AVERAGE.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jBuyOrdersAverage); JFixedToolBar jToolBar = new JFixedToolBar(); jClearNew = new JButton(TabsTransaction.get().clearNew(), Images.UPDATE_DONE_OK.getIcon()); jClearNew.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Settings.get().getTableChanged().put(NAME, new Date()); jTable.repaint(); jClearNew.setEnabled(false); program.saveSettings("Table Changed (transaction cleared)"); } }); jToolBar.addButton(jClearNew); //Table Format tableFormat = TableFormatFactory.transactionTableFormat(); //Backend eventList = program.getProfileData().getTransactionsEventList(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList sortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(sortedList); eventList.getReadWriteLock().readLock().unlock(); filterList.addListEventListener(listener); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JTransactionTable(program, tableModel); jTable.setCellSelectionEnabled(true); PaddingTableCellRenderer.install(jTable, 1); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll Panels JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new TransactionsFilterControl(sortedList); //Menu installTableTool(new TransactionTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, MyTransaction.class); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, jToolBar.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void updateTags() { beforeUpdateData(); tableModel.fireTableDataChanged(); filterControl.refilter(); afterUpdateData(); } @Override public void clearData() { filterControl.clearCache(); } @Override public void updateCache() { Date current = Settings.get().getTableChanged(NAME); boolean newFound = false; try { eventList.getReadWriteLock().readLock().lock(); for (MyTransaction transaction : eventList) { if (current.before(transaction.getAdded())) { newFound = true; break; } } } finally { eventList.getReadWriteLock().readLock().unlock(); } filterControl.createCache(); final boolean found = newFound; Program.ensureEDT(new Runnable() { @Override public void run() { jClearNew.setEnabled(found); } }); } @Override public Collection getLocations() { try { eventList.getReadWriteLock().readLock().lock(); return new ArrayList<>(eventList); } finally { eventList.getReadWriteLock().readLock().unlock(); } } public void addFilters(final List filters) { filterControl.addFilters(filters); } private class TransactionTableMenu implements TableMenu { @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { JMenuInfo.transctions(jPopupMenu, selectionModel.getSelected()); } @Override public void addToolMenu(JComponent jComponent) { } } private class ListenerClass implements ListEventListener { @Override public void listChanged(ListEvent listChanges) { double sellTotal = 0; double buyTotal = 0; long sellCount = 0; long buyCount = 0; try { filterList.getReadWriteLock().readLock().lock(); for (MyTransaction transaction : filterList) { if (transaction.isSell()) { //Sell sellTotal += transaction.getPrice() * transaction.getQuantity(); sellCount += transaction.getQuantity(); } else { //Buy buyTotal += transaction.getPrice() * transaction.getQuantity(); buyCount += transaction.getQuantity(); } } } finally { filterList.getReadWriteLock().readLock().unlock(); } double sellAvg = 0; if (sellTotal > 0 && sellCount > 0) { sellAvg = sellTotal / sellCount; } double buyAvg = 0; if (buyTotal > 0 && buyCount > 0) { buyAvg = buyTotal / buyCount; } double bothTotal = sellTotal + buyTotal; double bothCount = sellCount + buyCount; double bothAvg = 0; if (bothTotal > 0 && bothCount > 0) { bothAvg = bothTotal / bothCount; } jSellOrdersCount.setNumber(sellCount); jSellOrdersTotal.setNumber(sellTotal); jSellOrdersAverage.setNumber(sellAvg); jBothOrdersCount.setNumber(sellCount + buyCount); jBothOrdersTotal.setNumber(bothTotal); jBothOrdersAverage.setNumber(bothAvg); jBuyOrdersCount.setNumber(buyCount); jBuyOrdersTotal.setNumber(buyTotal); jBuyOrdersAverage.setNumber(buyAvg); } } private class TransactionsFilterControl extends FilterControl { public TransactionsFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("Transaction Table: " + msg); //Save Transaction Filters and Export Settings } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/transaction/TransactionTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.transaction; import java.util.Comparator; import java.util.Date; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.LongInt; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.i18n.TabsTransaction; public enum TransactionTableFormat implements EnumTableColumn { DATE(Date.class) { @Override public String getColumnName() { return TabsTransaction.get().columnTransactionDate(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getDate(); } }, TAGS(Tags.class) { @Override public String getColumnName() { return TabsTransaction.get().columnTags(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getTags(); } }, ADDED(Date.class) { @Override public String getColumnName() { return TabsTransaction.get().columnAdded(); } @Override public String getColumnToolTip() { return TabsTransaction.get().columnAddedToolTip(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getAdded(); } }, NAME(String.class) { @Override public String getColumnName() { return TabsTransaction.get().columnName(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getItem().getTypeName(); } }, GROUP(String.class) { @Override public String getColumnName() { return TabsTransaction.get().columnGroup(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getItem().getGroup(); } }, CATEGORY(String.class) { @Override public String getColumnName() { return TabsTransaction.get().columnCategory(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getItem().getCategory(); } }, QUANTITY(Integer.class) { @Override public String getColumnName() { return TabsTransaction.get().columnQuantity(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getQuantity(); } }, PRICE(Double.class) { @Override public String getColumnName() { return TabsTransaction.get().columnPrice(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getPrice(); } }, TAX(Double.class) { @Override public String getColumnName() { return TabsTransaction.get().columnTax(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getTax(); } }, VALUE(Double.class) { @Override public String getColumnName() { return TabsTransaction.get().columnValue(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getValue(); } }, OWNER(String.class) { @Override public String getColumnName() { return TabsTransaction.get().columnOwner(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getOwnerName(); } }, LOCATION(String.class) { @Override public String getColumnName() { return TabsTransaction.get().columnStationName(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getLocation(); } }, SYSTEM(String.class) { @Override public String getColumnName() { return TabsTransaction.get().columnSystem(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getLocation().getSystem(); } }, CONSTELLATION(String.class) { @Override public String getColumnName() { return TabsTransaction.get().columnConstellation(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getLocation().getConstellation(); } }, REGION(String.class) { @Override public String getColumnName() { return TabsTransaction.get().columnRegion(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getLocation().getRegion(); } }, TRANSACTION_PRICE(Double.class) { @Override public String getColumnName() { return TabsTransaction.get().columnTransactionPrice(); } @Override public String getColumnToolTip() { return TabsTransaction.get().columnTransactionPriceToolTip(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getTransactionPrice(); } }, TRANSACTION_MARGIN(Double.class) { @Override public String getColumnName() { return TabsTransaction.get().columnTransactionMargin(); } @Override public String getColumnToolTip() { return TabsTransaction.get().columnTransactionMarginToolTip(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getTransactionMargin(); } }, TRANSACTION_PROFIT(Double.class) { @Override public String getColumnName() { return TabsTransaction.get().columnTransactionProfitDifference(); } @Override public String getColumnToolTip() { return TabsTransaction.get().columnTransactionProfitDifferenceToolTip(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getTransactionProfitDifference(); } }, TRANSACTION_PROFIT_PERCENT(Percent.class) { @Override public String getColumnName() { return TabsTransaction.get().columnTransactionProfitPercent(); } @Override public String getColumnToolTip() { return TabsTransaction.get().columnTransactionProfitPercentToolTip(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getTransactionProfitPercent(); } }, CLIENT(String.class) { @Override public String getColumnName() { return TabsTransaction.get().columnClientName(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getClientName(); } }, TYPE(String.class) { @Override public String getColumnName() { return TabsTransaction.get().columnTransactionType(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getTransactionTypeFormatted(); } }, TRANSACTION_FOR(String.class) { @Override public String getColumnName() { return TabsTransaction.get().columnTransactionFor(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getTransactionForFormatted(); } }, ACCOUNT_KEY(Integer.class) { @Override public String getColumnName() { return TabsTransaction.get().columnAccountKey(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getAccountKeyFormatted(); } }, VOLUME(Float.class) { @Override public String getColumnName() { return TabsTransaction.get().columnVolume(); } @Override public Object getColumnValue(final MyTransaction from) { return from.getItem().getVolumePackaged(); } }, TRANSACTION_ID(LongInt.class) { @Override public String getColumnName() { return TabsTransaction.get().columnTransactionID(); } @Override public Object getColumnValue(final MyTransaction from) { return new LongInt(from.getTransactionID()); } @Override public boolean isShowDefault() { return false; } }; private final Class type; private final Comparator comparator; private TransactionTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tree/JTreeTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tree; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Color; import java.awt.Component; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.shared.ColorUtil; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetTableFormat; public class JTreeTable extends JAutoColumnTable { private final DefaultEventTableModel tableModel; public JTreeTable(final Program program, final DefaultEventTableModel tableModel) { super(program, tableModel); this.tableModel = tableModel; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); boolean isSelected = isCellSelected(row, column); TreeAsset treeAsset = tableModel.getElementAt(row); String columnName = (String) this.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); //Tree if (!isSelected && treeAsset.isParent()) { if (treeAsset.getDepth() == 0) { if (ColorUtil.isBrightColor(getBackground())) { //Light background color component.setBackground(new Color(170, 170, 170)); } else { //Dark background color component.setBackground(Color.DARK_GRAY.darker().darker().darker()); } return component; } else if (treeAsset.getDepth() == 1) { if (ColorUtil.isBrightColor(getBackground())) { //Light background color component.setBackground(new Color(190, 190, 190)); } else { //Dark background color component.setBackground(Color.DARK_GRAY.darker().darker()); } return component; } else if (treeAsset.getDepth() == 2) { if (ColorUtil.isBrightColor(getBackground())) { //Light background color component.setBackground(new Color(210, 210, 210)); } else { //Dark background color component.setBackground(Color.DARK_GRAY.darker()); } return component; } else if (treeAsset.getDepth() > 2) { if (ColorUtil.isBrightColor(getBackground())) { //Light background color component.setBackground(new Color(235, 235, 235)); } else { //Dark background color component.setBackground(Color.DARK_GRAY); } return component; } } //User set price if (treeAsset.isUserPrice() && columnName.equals(AssetTableFormat.PRICE.getColumnName())) { ColorSettings.configCell(component, ColorEntry.CUSTOM_PRICE, isSelected); return component; } //User set name if (treeAsset.isUserName() && columnName.equals(AssetTableFormat.NAME.getColumnName())) { ColorSettings.configCell(component, ColorEntry.CUSTOM_ASSET_NAME, isSelected); return component; } //User set location if (treeAsset.getLocation().isUserLocation() && columnName.equals(AssetTableFormat.LOCATION.getColumnName())) { ColorSettings.configCell(component, ColorEntry.CUSTOM_USER_LOCATION, isSelected); return component; } //Blueprint Original if (treeAsset.isBPO() && treeAsset.getItem().isBlueprint() && (columnName.equals(AssetTableFormat.PRICE.getColumnName()) || columnName.equals(AssetTableFormat.PRICE_SELL_MIN.getColumnName()) || columnName.equals(AssetTableFormat.PRICE_BUY_MAX.getColumnName()) || columnName.equals(AssetTableFormat.NAME.getColumnName()))) { ColorSettings.configCell(component, ColorEntry.GLOBAL_BPO, isSelected); return component; } //Blueprint Copy if (treeAsset.isBPC() && treeAsset.getItem().isBlueprint() && (columnName.equals(AssetTableFormat.PRICE.getColumnName()) || columnName.equals(AssetTableFormat.PRICE_SELL_MIN.getColumnName()) || columnName.equals(AssetTableFormat.PRICE_BUY_MAX.getColumnName()) || columnName.equals(AssetTableFormat.NAME.getColumnName()))) { ColorSettings.configCell(component, ColorEntry.GLOBAL_BPC, isSelected); return component; } //Reprocessing Colors if (Settings.get().isReprocessColors() && !isSelected) { //Zero price (White) if (treeAsset.getPriceReprocessed() == 0 || treeAsset.getDynamicPrice() == 0) { return component; } //Equal price (Yellow) boolean rowSelection = (this.isRowSelected(row) && Settings.get().isHighlightSelectedRows()); if (treeAsset.getPriceReprocessed() == treeAsset.getDynamicPrice()) { ColorSettings.configCell(component, ColorEntry.ASSETS_REPROCESSING_EQUAL, rowSelection, true); return component; } //Reprocessed highest (Red) if (treeAsset.getPriceReprocessed() > treeAsset.getDynamicPrice()) { ColorSettings.configCell(component, ColorEntry.ASSETS_REPROCESSING_REPROCES, rowSelection, true); return component; } //Price highest (Green) if (treeAsset.getPriceReprocessed() < treeAsset.getDynamicPrice()) { ColorSettings.configCell(component, ColorEntry.ASSETS_REPROCESSING_SELL, rowSelection, true); return component; } } //Reproccessed is greater then price if (treeAsset.getPriceReprocessed() > treeAsset.getDynamicPrice() && columnName.equals(AssetTableFormat.PRICE_REPROCESSED.getColumnName())) { ColorSettings.configCell(component, ColorEntry.ASSETS_REPROCESS, isSelected); return component; } return component; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tree/TreeAsset.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tree; import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.Icon; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.table.containers.HierarchyColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.gui.shared.table.containers.Runs; import net.nikr.eve.jeveasset.gui.shared.table.containers.Security; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetTableFormat; public class TreeAsset extends MyAsset { public enum TreeType { CATEGORY, LOCATION, } public static final String SPACE = " "; private static final Object NULL_PLACEHOLDER = new Object(); private static final Security EMPTY_SECURITY = Security.create(""); private static final Map columns = new EnumMap<>(TreeTableFormat.class); private final List tree; private final String compare; private final String ownerName; private final boolean parent; private final boolean item; private final int depthOffset; private final Icon icon; private final Set items = new HashSet<>(); private final Map values = new HashMap<>(); private final Map calcTotals = new HashMap<>(); private final Map calcAverages = new HashMap<>(); private String treeName; private HierarchyColumn hierarchyColumn; public TreeAsset(final MyAsset asset, final TreeType treeType, final List tree, final String compare, final boolean parent) { super(asset); this.treeName = createSpace(tree.size()) + asset.getName(); this.tree = new ArrayList<>(tree); //Copy this.compare = compare + asset.getName() + " #" + asset.getItemID(); this.ownerName = asset.getOwnerName(); this.parent = parent; this.item = true; this.depthOffset = 0; if (treeType == TreeType.LOCATION && parent) { if (asset.getItem().isContainer()) { this.icon = Images.LOC_CONTAINER.getIcon(); } else if (asset.getItem().isShip()) { this.icon = Images.LOC_SHIP.getIcon(); } else if (asset.getItem().getTypeID() == 27) { //Office this.icon = Images.LOC_OFFICE.getIcon(); } else if (asset.getItem().getCategory().equals(Item.CATEGORY_PLANETARY_INDUSTRY)) { switch (asset.getItem().getGroup()) { case Item.GROUP_COMMAND_CENTERS: this.icon = Images.LOC_PIN_COMMAND.getIcon(); break; case Item.GROUP_EXTRACTOR_CONTROL_UNITS: this.icon = Images.LOC_PIN_EXTRACTOR.getIcon(); break; case Item.GROUP_PROCESSORS: this.icon = Images.LOC_PIN_PROCESSOR.getIcon(); break; case Item.GROUP_SPACEPORTS: this.icon = Images.LOC_PIN_SPACEPORT.getIcon(); break; case Item.GROUP_STORAGE_FACILITIES: this.icon = Images.LOC_PIN_STORAGE.getIcon(); break; default: this.icon = null; break; } } else { this.icon = null; } } else { //Never happens this.icon = null; } this.hierarchyColumn = new HierarchyColumn(this.treeName, this.parent); } public TreeAsset(final MyLocation location, final String treeName, final String compare, final Icon icon, List tree) { this(location, treeName, compare, icon, tree, 0); } public TreeAsset(final MyLocation location, final String treeName, final String compare, final Icon icon, List tree, final int depthOffset) { super(location); this.treeName = createSpace(tree.size()) + treeName; this.tree = new ArrayList<>(tree); //Copy this.compare = compare; this.ownerName = ""; this.icon = icon; this.depthOffset = depthOffset; this.parent = true; this.item = false; this.hierarchyColumn = new HierarchyColumn(this.treeName, this.parent); } private String createSpace(int size) { String space = ""; for (int i = 0; i < size; i++) { space = space + SPACE; } return space; } public String getCompare() { return compare; } public int getDepth() { return tree.size() + depthOffset; } public HierarchyColumn getHierarchyColumn() { return hierarchyColumn; } public Icon getIcon() { return icon; } public List getTree() { return tree; } public String getTreeName() { return treeName; } public boolean isItem() { return item; } public boolean isParent() { return parent; } @Override public void setName(UserItem customeItem, String eveName) { super.setName(customeItem, eveName); this.treeName = createSpace(tree.size()) + getName(); this.hierarchyColumn = new HierarchyColumn(this.treeName, this.parent); } public Integer getMeta() { if (isItem()) { return super.getItem().getMeta(); } else { return null; } } @Override public String getOwnerName() { return ownerName; } public Double getPriceMarketLatest() { if (isItem()) { return super.getMarketPriceData().getLatest(); } else { return null; } } public Double getPriceMarketAverage() { if (isItem()) { return super.getMarketPriceData().getAverage(); } else { return null; } } public Double getPriceMarketMaximum() { if (isItem()) { return super.getMarketPriceData().getMaximum(); } else { return null; } } public Double getPriceMarketMinimum() { if (isItem()) { return super.getMarketPriceData().getMinimum(); } else { return null; } } public Security getSecurity() { if (!getLocation().isEmpty() && !getLocation().isRegion()) { return getLocation().getSecurityObject(); } else { return EMPTY_SECURITY; } } @Override public String getSingleton() { if (isItem()) { return super.getSingleton(); } else { return ""; } } public Object getTotal(TreeTableFormat column) { return getValue(column, calcTotals); } public Object getAverage(TreeTableFormat column) { return getValue(column, calcAverages); } public Object getValue(TreeTableFormat column, Map calc) { Object object = values.get(column); if (object == null) { //Create data if (!isParent()) { object = getValue(column, this); if (object == null) { values.put(column, NULL_PLACEHOLDER); return null; } else { values.put(column, object); return object; } } else if (Percent.class.isAssignableFrom(column.getType())) { DoubleValue value = calc.get(column); if (value == null) { values.put(column, NULL_PLACEHOLDER); return null; } Double t = value.getDouble(); if (t == null) { values.put(column, NULL_PLACEHOLDER); return null; } Percent percent = Percent.create(t); values.put(column, percent); return percent; } else if (Runs.class.isAssignableFrom(column.getType())) { DoubleValue value = calc.get(column); if (value == null) { values.put(column, NULL_PLACEHOLDER); return null; } Double t = value.getDouble(); if (t == null) { values.put(column, NULL_PLACEHOLDER); return null; } Runs runs = new Runs(t.intValue()); values.put(column, runs); return runs; } else if (Number.class.isAssignableFrom(column.getType())) { DoubleValue value = calc.get(column); if (value == null) { values.put(column, NULL_PLACEHOLDER); return null; } Double t = value.getDouble(); if (t == null) { values.put(column, NULL_PLACEHOLDER); return null; } if (Double.class.isAssignableFrom(column.getType())) { values.put(column, t); return t; } else if (Long.class.isAssignableFrom(column.getType())) { values.put(column, t.longValue()); return t.longValue(); } else if (Integer.class.isAssignableFrom(column.getType())) { values.put(column, t.intValue()); return t.intValue(); } else if (Float.class.isAssignableFrom(column.getType())) { values.put(column, t.floatValue()); return t.floatValue(); } else { throw new RuntimeException(column.getType() + " not supported by TreeAsset"); } } else { return null; } } else if (object.equals(NULL_PLACEHOLDER)) { return null; } else { return object; } } private Object getValue(TreeTableFormat column, TreeAsset asset) { try { AssetTableFormat assetColumn = columns.get(column); if (assetColumn == null) { assetColumn = AssetTableFormat.valueOf(column.name()); columns.put(column, assetColumn); } return assetColumn.getColumnValue(asset); } catch (IllegalArgumentException ex) { return null; } } private void add(TreeTableFormat column, Percent percent, Number count) { Average average = calcAverages.get(column); if (average == null) { average = new Average(); calcAverages.put(column, average); } Total total = calcTotals.get(column); if (total == null) { total = new Total(); calcTotals.put(column, total); } Double d = percent.getDouble() / 100.0; average.add(d, count); total.add(d); } private void add(TreeTableFormat column, Runs runs, Number count) { Average average = calcAverages.get(column); if (average == null) { average = new Average(); calcAverages.put(column, average); } Total total = calcTotals.get(column); if (total == null) { total = new Total(); calcTotals.put(column, total); } Long l = runs.getLong(); average.add(l, count); total.add(l); } private void add(TreeTableFormat column, Number value, Number count) { Average average = calcAverages.get(column); if (average == null) { average = new Average(); calcAverages.put(column, average); } Total total = calcTotals.get(column); if (total == null) { total = new Total(); calcTotals.put(column, total); } average.add(value, count); total.add(value); } public Set getItems() { return items; } public void resetValues() { items.clear(); values.clear(); calcAverages.clear(); calcTotals.clear(); } public void updateParents() { Object objCount = getValue(TreeTableFormat.COUNT, this); //Ignore null if (objCount == null || !(objCount instanceof Number)) { return; } Number count = (Number) objCount; for (TreeTableFormat column : TreeTableFormat.values()) { if (!Percent.class.isAssignableFrom(column.getType()) && !Runs.class.isAssignableFrom(column.getType()) && !Number.class.isAssignableFrom(column.getType()) ) { continue; } Object objValue = getValue(column, this); //Ignore null if (objValue == null) { continue; } if (objValue instanceof Percent) { //Add this to parents for (TreeAsset treeAsset : tree) { treeAsset.add(column, (Percent) objValue, count); } //Include ship in value if (getItem().isShip()) { add(column, (Percent) objValue, count); } } else if (objValue instanceof Runs) { //Add this to parents for (TreeAsset treeAsset : tree) { treeAsset.add(column, (Runs) objValue, count); } //Include ship in value if (getItem().isShip()) { add(column, (Runs) objValue, count); } } else if (Number.class.isAssignableFrom(objValue.getClass())) { //Add this to parents for (TreeAsset treeAsset : tree) { treeAsset.add(column, (Number) objValue, count); } //Include ship in value if (getItem().isShip()) { add(column, (Number) objValue, count); } } } for (TreeAsset treeAsset : tree) { treeAsset.items.add(this); } } @Override public int compareTo(MyAsset o) { if (o instanceof TreeAsset) { TreeAsset treeAsset = (TreeAsset) o; return this.getCompare().compareTo(treeAsset.getCompare()); } else { return super.compareTo(o); } } @Override public int hashCode() { int hash = 5; hash = 47 * hash + (this.compare != null ? this.compare.hashCode() : 0); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final TreeAsset other = (TreeAsset) obj; return !((this.compare == null) ? (other.compare != null) : !this.compare.equals(other.compare)); } private static interface DoubleValue { public Double getDouble(); } private static class Total implements DoubleValue { private Double total = null; public void add(Number value) { if (value != null) { if (total == null) { total = 0.0; } this.total = this.total + value.doubleValue(); } } @Override public Double getDouble() { return total; } } private static class Average implements DoubleValue { private Double total = null; private Long count = null; public void add(Number value, Number count) { if (value != null && count != null) { if (total == null) { total = 0.0; } if (this.count == null) { this.count = 0L; } this.count = this.count + count.longValue(); this.total = this.total + (value.doubleValue() * count.longValue()); } } @Override public Double getDouble() { if (total == null || count == null) { return null; } else if (total > 0 && count > 0) { return total / count; } else { return 0.0; } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tree/TreeData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tree; import ca.odell.glazedlists.EventList; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.TreeSet; import javax.swing.Icon; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.data.profile.TableData; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.i18n.TabsTree; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class TreeData extends TableData { private final Set locationsExport = new TreeSet<>(new TreeTab.AssetTreeComparator()); private final Set locations = new TreeSet<>(new TreeTab.AssetTreeComparator()); private final Set categoriesExport = new TreeSet<>(new TreeTab.AssetTreeComparator()); private final Set categories = new TreeSet<>(new TreeTab.AssetTreeComparator()); public TreeData(Program program) { super(program); } public TreeData(ProfileManager profileManager, ProfileData profileData) { super(profileManager, profileData); } public void updateData() { locations.clear(); categories.clear(); locationsExport.clear(); categoriesExport.clear(); Map> flagsNames = new HashMap<>(); Flag shipHangar = new Flag(TabsTree.get().locationShipHangar(), Images.LOC_HANGAR_SHIPS.getIcon()); flagsNames.put(new Flag(TabsTree.get().locationAssetSafety(), Images.LOC_SAFTY.getIcon()), Collections.singleton(ApiIdConverter.getFlag(36).getFlagName())); //FlagName AssetSafety (Asset Safety) flagsNames.put(new Flag(TabsTree.get().locationItemHangar(), Images.LOC_HANGAR_ITEMS.getIcon()), Collections.singleton(ApiIdConverter.getFlag(4).getFlagName())); //FlagName Hangar Set deliveries = new HashSet<>(); deliveries.add(ApiIdConverter.getFlag(173).getFlagName()); //FlagName Deliveries deliveries.add(ApiIdConverter.getFlag(62).getFlagName()); //FlagName CorpMarket (Corporation Deliveries) flagsNames.put(new Flag(TabsTree.get().locationDeliveries(), Images.LOC_DELIVERIES.getIcon()), deliveries); Set industryJobs = new HashSet<>(); industryJobs.add(General.get().industryJobFlag()); industryJobs.add(MyIndustryJob.IndustryActivity.ACTIVITY_MANUFACTURING.toString()); //industry job manufacturing industryJobs.add(MyIndustryJob.IndustryActivity.ACTIVITY_REACTIONS.toString()); //industry job reactions flagsNames.put(new Flag(General.get().industryJobFlag(), Images.LOC_INDUSTRY.getIcon()), industryJobs); Set contracts = new HashSet<>(); contracts.add(General.get().contractExcluded()); contracts.add(General.get().contractIncluded()); flagsNames.put(new Flag(TabsTree.get().locationContracts(), Images.LOC_CONTRACTS.getIcon()), contracts); Set marketOrders = new HashSet<>(); marketOrders.add(General.get().marketOrderBuyFlag()); marketOrders.add(General.get().marketOrderSellFlag()); flagsNames.put(new Flag(TabsTree.get().locationMarketOrders(), Images.LOC_MARKET.getIcon()), marketOrders); Set clones = new HashSet<>(); clones.add(ApiIdConverter.getFlag(89).getFlagName()); clones.add(General.get().jumpClone()); flagsNames.put(new Flag(TabsTree.get().locationClones(), Images.LOC_CLONEBAY.getIcon()), clones); MyLocation emptyLocation = new MyLocation(0, "", 0, "", 0, "", 0, "", ""); Map categoryCache = new HashMap<>(); Map locationCache = new HashMap<>(); for (MyAsset asset : profileData.getAssetsList()) { //LOCATION List locationTree = new ArrayList<>(); MyLocation location = asset.getLocation(); //Region String regionKey = location.getRegion(); TreeAsset regionAsset = locationCache.get(location.getRegion()); if (regionAsset == null) { regionAsset = new TreeAsset(ApiIdConverter.getLocation(location.getRegionID()), location.getRegion(), regionKey, Images.LOC_REGION.getIcon(), locationTree); locationCache.put(regionKey, regionAsset); locationsExport.add(regionAsset); } locationTree.add(regionAsset); //System String systemKey = location.getRegion() + location.getSystem(); TreeAsset systemAsset = locationCache.get(systemKey); if (systemAsset == null) { systemAsset = new TreeAsset(ApiIdConverter.getLocation(location.getSystemID()), location.getSystem(), systemKey, Images.LOC_SYSTEM.getIcon(), locationTree); locationCache.put(systemKey, systemAsset); locationsExport.add(systemAsset); } locationTree.add(systemAsset); String fullLocation = location.getRegion()+location.getSystem(); //Station if (location.isStation() || location.isPlanet()) { //Station or Planet String stationKey = location.getRegion() + location.getSystem() + location.getLocation(); TreeAsset stationAsset = locationCache.get(stationKey); if (stationAsset == null) { if (asset.getLocation().isPlanet()) { stationAsset = new TreeAsset(asset.getLocation(), location.getLocation(), stationKey, Images.LOC_PLANET.getIcon(), locationTree); } else { stationAsset = new TreeAsset(asset.getLocation(), location.getLocation(), stationKey, Images.LOC_STATION.getIcon(), locationTree); } locationCache.put(stationKey, stationAsset); locationsExport.add(stationAsset); } locationTree.add(stationAsset); fullLocation = location.getRegion()+location.getSystem()+location.getLocation(); } //Add parent item(s) String parentKey = fullLocation; List list = new ArrayList<>(asset.getParents()); //Copy if (asset.getAssets().isEmpty()) { list.add(asset); } if (!list.isEmpty()) { for (MyAsset parentAsset : list) { //Office MyAsset parent = parentAsset.getParent(); if (parent != null && parent.getTypeID() == 27) { //Office divisions String cacheKey = parentAsset.getFlagName() + " #" + parent.getItemID(); TreeAsset divisionAsset = locationCache.get(cacheKey); if (divisionAsset == null) { divisionAsset = new TreeAsset(location, parentAsset.getFlagName(), parentKey + cacheKey, Images.LOC_DIVISION.getIcon(), locationTree); locationCache.put(cacheKey, divisionAsset); locationsExport.add(divisionAsset); } parentKey = parentKey + cacheKey; locationTree.add(divisionAsset); } //Flags if (parent == null) { for (Map.Entry> entry: flagsNames.entrySet()) { if (entry.getValue().contains(parentAsset.getFlag())) { final Flag flag; if (entry.getKey().getName().equals("Item Hangar") && parentAsset.getItem().isShip()) { flag = shipHangar; } else { flag = entry.getKey(); } String cacheKey = flag.getName() + "#" + parentAsset.getLocationID(); TreeAsset hangarAsset = locationCache.get(cacheKey); if (hangarAsset == null) { hangarAsset = new TreeAsset(location, flag.getName(), parentKey + cacheKey, flag.getIcon(), locationTree); locationCache.put(cacheKey, hangarAsset); locationsExport.add(hangarAsset); } parentKey = parentKey + cacheKey; locationTree.add(hangarAsset); } } } //Item String cacheKey = parentAsset.getName() + " #" + parentAsset.getItemID(); TreeAsset parentTreeAsset = locationCache.get(cacheKey); if (parentTreeAsset == null) { parentTreeAsset = new TreeAsset(parentAsset, TreeAsset.TreeType.LOCATION, locationTree, parentKey, !parentAsset.getAssets().isEmpty()); locationCache.put(cacheKey, parentTreeAsset); locations.add(parentTreeAsset); locationsExport.add(parentTreeAsset); } parentKey = parentKey + parentAsset.getName() + " #" + parentAsset.getItemID(); locationTree.add(parentTreeAsset); } } //CATEGORY List categoryTree = new ArrayList<>(); //Category String categoryKey = asset.getItem().getCategory(); TreeAsset categoryAsset = categoryCache.get(categoryKey); if (categoryAsset == null) { categoryAsset = new TreeAsset(emptyLocation, asset.getItem().getCategory(), categoryKey, null, categoryTree, 1); categoryCache.put(categoryKey, categoryAsset); } categoryTree.add(categoryAsset); categoriesExport.add(categoryAsset); //Group String groupKey = categoryKey + asset.getItem().getGroup(); TreeAsset groupAsset = categoryCache.get(groupKey); if (groupAsset == null) { groupAsset = new TreeAsset(emptyLocation, asset.getItem().getGroup(), groupKey, null, categoryTree, 1); categoryCache.put(groupKey, groupAsset); } categoryTree.add(groupAsset); categoriesExport.add(groupAsset); //Item TreeAsset category = new TreeAsset(asset, TreeAsset.TreeType.CATEGORY, categoryTree, groupKey, false); categories.add(category); categoriesExport.add(category); } } public Set getLocationsExport() { return locationsExport; } public Set getLocations() { return locations; } public Set getCategoriesExport() { return categoriesExport; } public Set getCategories() { return categories; } public EventList getDataCategories() { updateData(); return EventListManager.create(categoriesExport); } public EventList getDataLocations() { updateData(); return EventListManager.create(locationsExport); } private static class Flag implements Comparable { private final String name; private final Icon icon; public Flag(String name, Icon icon) { this.name = name; this.icon = icon; } public String getName() { return name; } public Icon getIcon() { return icon; } @Override public int hashCode() { int hash = 3; hash = 61 * hash + Objects.hashCode(this.name); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Flag other = (Flag) obj; if (!Objects.equals(this.name, other.name)) { return false; } return true; } @Override public int compareTo(Flag o) { return this.name.compareTo(o.name); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tree/TreeTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tree; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.TreeList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import ca.odell.glazedlists.swing.TreeNodeData; import ca.odell.glazedlists.swing.TreeTableCellEditor; import ca.odell.glazedlists.swing.TreeTableCellRenderer; import ca.odell.glazedlists.swing.TreeTableSupport; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JToggleButton; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.tag.TagUpdate; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.frame.StatusPanel.JStatusLabel; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.AutoNumberFormat; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData.AssetMenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.gui.shared.table.containers.HierarchyColumn; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTab.AssetTreeExpansionModel.ExpandedState; import net.nikr.eve.jeveasset.i18n.TabsAssets; import net.nikr.eve.jeveasset.i18n.TabsTree; public class TreeTab extends JMainTabSecondary implements TagUpdate { private enum TreeAction { TYPE, COLLAPSE, EXPAND, REPROCESS_COLORS } private final int INDENT = 10; //GUI private final JTreeTable jTable; private final JStatusLabel jValue; private final JStatusLabel jReprocessed; private final JStatusLabel jCount; private final JStatusLabel jAverage; private final JStatusLabel jVolume; private final JToggleButton jCategories; private final JToggleButton jReprocessColors; //Table private final DefaultEventTableModel tableModel; private final EventList eventList; private final EventList exportEventList; private final SortedList sortedList; private final SortedList emptySortedList; private final FilterList filterList; private final TreeList treeList; private final TreeFilterControl filterControl; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventSelectionModel selectionModel; private final AssetTreeExpansionModel expansionModel; public static final String NAME = "treeassets"; //Not to be changed! private final TreeData treeData; public TreeTab(final Program program) { super(program, NAME, TabsTree.get().title(), Images.TOOL_TREE.getIcon(), true); treeData = new TreeData(program); layout.setAutoCreateGaps(true); ListenerClass listener = new ListenerClass(); JFixedToolBar jToolBar = new JFixedToolBar(); ButtonGroup buttonGroup = new ButtonGroup(); jCategories = new JToggleButton(TabsTree.get().categories(), Images.LOC_GROUPS.getIcon()); jCategories.setActionCommand(TreeAction.TYPE.name()); jCategories.addActionListener(listener); buttonGroup.add(jCategories); jToolBar.addButton(jCategories); JToggleButton jLocation = new JToggleButton(TabsTree.get().locations(), Images.LOC_LOCATIONS.getIcon()); jLocation.setActionCommand(TreeAction.TYPE.name()); jLocation.addActionListener(listener); jLocation.setSelected(true); buttonGroup.add(jLocation); jToolBar.addButton(jLocation); jToolBar.addSeparator(); jReprocessColors = new JToggleButton(TabsAssets.get().reprocessColors(), Images.TOOL_REPROCESSED.getIcon()); jReprocessColors.setToolTipText(TabsAssets.get().reprocessColorsToolTip()); jReprocessColors.setSelected(Settings.get().isReprocessColors()); jReprocessColors.setActionCommand(TreeAction.REPROCESS_COLORS.name()); jReprocessColors.addActionListener(listener); jToolBar.addButton(jReprocessColors); jToolBar.addGlue(); JButton jCollapse = new JButton(TabsTree.get().collapse(), Images.MISC_COLLAPSED.getIcon()); jCollapse.setActionCommand(TreeAction.COLLAPSE.name()); jCollapse.addActionListener(listener); jToolBar.addButton(jCollapse); JButton jExpand = new JButton(TabsTree.get().expand(), Images.MISC_EXPANDED.getIcon()); jExpand.setActionCommand(TreeAction.EXPAND.name()); jExpand.addActionListener(listener); jToolBar.addButton(jExpand); jVolume = StatusPanel.createLabel(TabsAssets.get().totalVolume(), Images.ASSETS_VOLUME.getIcon(), AutoNumberFormat.DOUBLE); this.addStatusbarLabel(jVolume); jCount = StatusPanel.createLabel(TabsAssets.get().totalCount(), Images.EDIT_ADD.getIcon(), AutoNumberFormat.ITEMS); this.addStatusbarLabel(jCount); jAverage = StatusPanel.createLabel(TabsAssets.get().average(), Images.ASSETS_AVERAGE.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jAverage); jReprocessed = StatusPanel.createLabel(TabsAssets.get().totalReprocessed(), Images.SETTINGS_REPROCESSING.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jReprocessed); jValue = StatusPanel.createLabel(TabsAssets.get().totalValue(), Images.TOOL_VALUES.getIcon(), AutoNumberFormat.ISK); this.addStatusbarLabel(jValue); //Table Format tableFormat = TableFormatFactory.treeTableFormat(); //Backend eventList = EventListManager.create(); exportEventList = EventListManager.create(); //Filter (must be done before sorting for totals to match up - for reason beyond my comprehension) eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Sorting EventList emptyEventList = EventListManager.create(); emptyEventList.getReadWriteLock().readLock().lock(); emptySortedList = new SortedList<>(emptyEventList); emptyEventList.getReadWriteLock().readLock().unlock(); eventList.getReadWriteLock().readLock().lock(); sortedList = new SortedList<>(filterList); eventList.getReadWriteLock().readLock().unlock(); //Tree expansionModel = new AssetTreeExpansionModel(); treeList = new TreeList<>(sortedList, new AssetTreeFormat(sortedList), expansionModel); //Table Model tableModel = EventModels.createTableModel(treeList, tableFormat); //Table jTable = new JTreeTable(program, tableModel); jTable.setCellSelectionEnabled(true); jTable.disableColumnResizeCache(TreeTableFormat.NAME); jTable.setRowHeight(22); jTable.addMouseListener(listener); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, emptySortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); comparatorChooser.addSortActionListener(new ListenerSorter()); //Tree TreeTableSupport install = TreeTableSupport.install(jTable, treeList, 0); TreeTableCellEditor editor = new AssetTreeTableCellEditor(install.getDelegateEditor(), treeList, tableModel, INDENT, 6); TreeTableCellRenderer renderer = new AssetTreeTableCellRenderer(install.getDelegateRenderer(), treeList, tableModel, INDENT, 6); install.setEditor(editor); install.setRenderer(renderer); jTable.setDefaultRenderer(HierarchyColumn.class, renderer); jTable.setDefaultEditor(HierarchyColumn.class, editor); //Selection Model selectionModel = EventModels.createSelectionModel(treeList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new TreeFilterControl(); //Menu installTableTool(new TreeTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, TreeAsset.class); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, jToolBar.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void updateTags() { beforeUpdateData(); tableModel.fireTableDataChanged(); filterControl.refilter(); afterUpdateData(); } @Override public void updateData() { //Update Data treeData.updateData(); //Update GUI updateTableFull(); } @Override public void clearData() { try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); } finally { eventList.getReadWriteLock().writeLock().unlock(); } filterControl.clearCache(); expansionModel.clearCache(); } @Override public void updateCache() { filterControl.createCache(); } @Override public Collection getLocations() { try { eventList.getReadWriteLock().readLock().lock(); return new ArrayList<>(eventList); } finally { eventList.getReadWriteLock().readLock().unlock(); } } public EventList getEventList() { return eventList; } public void updateTableFull() { beforeUpdateData(); updateTable(true); updateTotals(); updateStatusbar(); afterUpdateData(); } public void resetTable() { beforeUpdateDataKeepCache(); updateTable(false); afterUpdateData(); } public void updateTable(boolean export) { final Set treeAssets; final Set treeAssetsExport; if (jCategories.isSelected()) { treeAssets = treeData.getCategories(); treeAssetsExport = treeData.getCategoriesExport(); } else { treeAssets = treeData.getLocations(); treeAssetsExport = treeData.getLocationsExport(); } //Update Jumps eventList.getReadWriteLock().writeLock().lock(); try { eventList.clear(); eventList.addAll(treeAssets); } finally { eventList.getReadWriteLock().writeLock().unlock(); } if (export) { exportEventList.getReadWriteLock().writeLock().lock(); try { exportEventList.clear(); exportEventList.addAll(treeAssetsExport); } finally { exportEventList.getReadWriteLock().writeLock().unlock(); } } } public void updateReprocessColors() { jReprocessColors.setSelected(Settings.get().isReprocessColors()); } private void updateTotals() { //Reset if (jCategories.isSelected()) { for (TreeAsset treeAsset : treeData.getCategoriesExport()) { treeAsset.resetValues(); } } else { for (TreeAsset treeAsset : treeData.getLocationsExport()) { treeAsset.resetValues(); } } //Calculate try { filterList.getReadWriteLock().readLock().lock(); for (TreeAsset treeAsset : filterList) { if (treeAsset.isItem()) { treeAsset.updateParents(); } } } finally { filterList.getReadWriteLock().readLock().unlock(); } } private void updateStatusbar() { double averageValue = 0; double totalValue = 0; long totalCount = 0; double totalVolume = 0; double totalReprocessed = 0; try { filterList.getReadWriteLock().readLock().lock(); for (TreeAsset asset : filterList) { if (!asset.isItem()) { continue; } totalValue = totalValue + asset.getValue(); totalCount = totalCount + asset.getCount(); totalVolume = totalVolume + asset.getVolumeTotal(); totalReprocessed = totalReprocessed + asset.getValueReprocessed(); } } finally { filterList.getReadWriteLock().readLock().unlock(); } if (totalCount > 0 && totalValue > 0) { averageValue = totalValue / totalCount; } jVolume.setNumber(totalVolume); jCount.setNumber(totalCount); jAverage.setNumber(averageValue); jReprocessed.setNumber(totalReprocessed); jValue.setNumber(totalValue); } private class TreeTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new AssetMenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { JMenuInfo.treeAsset(jPopupMenu, selectionModel.getSelected()); } @Override public void addToolMenu(JComponent jComponent) { } } private class ListenerClass implements ActionListener, MouseListener { private final int WIDTH = UIManager.getIcon("Tree.expandedIcon").getIconWidth(); @Override public void actionPerformed(ActionEvent e) { if (TreeAction.TYPE.name().equals(e.getActionCommand())) { expansionModel.setState(ExpandedState.LOAD); updateTableFull(); } else if (TreeAction.COLLAPSE.name().equals(e.getActionCommand())) { expansionModel.setState(ExpandedState.COLLAPSE); resetTable(); expansionModel.setState(ExpandedState.LOAD); } else if (TreeAction.EXPAND.name().equals(e.getActionCommand())) { expansionModel.setState(ExpandedState.EXPAND); resetTable(); expansionModel.setState(ExpandedState.LOAD); } else if (TreeAction.REPROCESS_COLORS.name().equals(e.getActionCommand())) { boolean oldValue = Settings.get().isReprocessColors(); boolean newValue = jReprocessColors.isSelected(); if (oldValue != newValue) { Settings.lock("Reprocess Colors"); Settings.get().setReprocessColors(newValue); Settings.unlock("Reprocess Colors"); program.saveSettings("Reprocess Colors"); jTable.repaint(); program.getAssetsTab().updateReprocessColors(); } } } @Override public void mouseClicked(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() % 2 == 0) { int row = jTable.rowAtPoint(e.getPoint()); int depth = treeList.depth(row); final int min = INDENT + (depth * WIDTH); final int max = min + WIDTH; if (e.getPoint().x < min || e.getPoint().x > max) { treeList.setExpanded(row, !treeList.isExpanded(row)); } } } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } } private class ListenerSorter implements ActionListener { @Override public void actionPerformed(ActionEvent e) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { expansionModel.setState(ExpandedState.LOAD); try { jTable.lock(); emptySortedList.getReadWriteLock().readLock().lock(); sortedList.getReadWriteLock().writeLock().lock(); sortedList.setComparator(emptySortedList.getComparator()); } finally { emptySortedList.getReadWriteLock().readLock().unlock(); sortedList.getReadWriteLock().writeLock().unlock(); jTable.unlock(); } } }); } } public static class AssetTreeExpansionModel implements TreeList.ExpansionModel { public enum ExpandedState { EXPAND, COLLAPSE, LOAD } private final Map cache = new HashMap<>(); private ExpandedState state = ExpandedState.LOAD; @Override public boolean isExpanded(TreeAsset element, List path) { if (state == ExpandedState.EXPAND) { return saveExpanded(element, true); } else if (state == ExpandedState.COLLAPSE) { return saveExpanded(element, false); } else { return loadExpanded(element); } } @Override public void setExpanded(TreeAsset element, List path, boolean expanded) { saveExpanded(element, expanded); } private boolean loadExpanded(final TreeAsset element) { Boolean expanded = cache.get(getElementKey(element)); if (expanded != null) { return expanded; } else { return false; // default to collapsed } } private boolean saveExpanded(final TreeAsset element, final boolean expanded) { cache.put(getElementKey(element), expanded); return expanded; } private String getElementKey(TreeAsset element) { return element.getCompare(); } public void clearCache() { cache.clear(); } public void setState(ExpandedState expandeState) { this.state = expandeState; } } public static class AssetTreeComparator implements Comparator { @Override public int compare(TreeAsset o1, TreeAsset o2) { return o1.getCompare().compareTo(o2.getCompare()); } } public static class AssetTreeSortedComparator implements Comparator { private final SortedList sortedList; public AssetTreeSortedComparator(SortedList sortedList) { this.sortedList = sortedList; } @Override public int compare(TreeAsset o1, TreeAsset o2) { if (o1.getCompare().equals(o2.getCompare())) { return 0; //Equal item } else { if (o1.getTree().size() == o2.getTree().size()) { //Compare equal depth for (int i = 0; i < o1.getTree().size(); i++) { TreeAsset tree1 = o1.getTree().get(i); TreeAsset tree2 = o2.getTree().get(i); int result = tree1.getCompare().compareTo(tree2.getCompare()); if (result != 0) { return result; //Parent not equal } } //Parents equal - compare items //Use sorted comparator Comparator comparator = sortedList.getComparator(); if (comparator != null) { int result = comparator.compare(o1, o2); if (result != 0) { //Not equal return result; } } //Fallback (Sorted comparator equal or null) return o1.getCompare().compareTo(o2.getCompare()); } else { //Should never happen (depth not equal) return -1; } } } } public static class AssetTreeFormat implements TreeList.Format { private final AssetTreeSortedComparator comparator; public AssetTreeFormat(SortedList sortedList) { this.comparator = new AssetTreeSortedComparator(sortedList); } @Override public void getPath(List path, TreeAsset element) { path.addAll(element.getTree()); path.add(element); } @Override public boolean allowsChildren(TreeAsset element) { return true; } @Override public Comparator getComparator(int depth) { return comparator; } } private class TreeFilterControl extends FilterControl { public TreeFilterControl() { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override protected void updateFilters() { if (program != null) { OverviewTab overviewTab = program.getOverviewTab(false); if (overviewTab != null) { overviewTab.updateFilters(); } } } @Override protected void beforeFilter() { beforeUpdateData(); } @Override protected void afterFilter() { updateTotals(); updateStatusbar(); afterUpdateData(); } @Override public void saveSettings(final String msg) { program.saveSettings("Tree Table: " + msg); //Save Tree Filters and Export Settings } } public static class AssetTreeTableCellEditor extends TreeTableCellEditor { private int indent; private int spacer; private DefaultEventTableModel tableModel; public AssetTreeTableCellEditor(TableCellEditor delegate, TreeList treeList, DefaultEventTableModel tableModel, int indent, int spacer) { super(delegate, treeList); if (indent == spacer) { throw new IllegalArgumentException("indent and spacer may not be equal - that invalidates indent"); } this.tableModel = tableModel; this.indent = indent; this.spacer = spacer; } @Override protected int getIndent(TreeNodeData treeNodeData, boolean showExpanderForEmptyParent) { return super.getIndent(treeNodeData, showExpanderForEmptyParent) + indent; } @Override protected int getSpacer(TreeNodeData treeNodeData, boolean showExpanderForEmptyParent) { return spacer; } @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { JPanel jPanel = (JPanel) super.getTableCellEditorComponent(table, value, isSelected, row, column); //To change body of generated methods, choose Tools | Templates. TreeAsset treeAsset = tableModel.getElementAt(row); JLabel jLabel = (JLabel) jPanel.getComponent(3); jLabel.setIcon(treeAsset.getIcon()); return jPanel; } } public static class AssetTreeTableCellRenderer extends TreeTableCellRenderer { private int indent; private int spacer; private DefaultEventTableModel tableModel; public AssetTreeTableCellRenderer(TableCellRenderer delegate, TreeList treeList, DefaultEventTableModel tableModel, int indent, int spacer) { super(delegate, treeList); if (indent == spacer) { throw new IllegalArgumentException("indent and spacer may not be equal - that invalidates indent"); } this.tableModel = tableModel; this.indent = indent; this.spacer = spacer; } @Override protected int getIndent(TreeNodeData treeNodeData, boolean showExpanderForEmptyParent) { return super.getIndent(treeNodeData, showExpanderForEmptyParent) + indent; } @Override protected int getSpacer(TreeNodeData treeNodeData, boolean showExpanderForEmptyParent) { return spacer; } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { JPanel jPanel = (JPanel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); TreeAsset treeAsset = tableModel.getElementAt(row); JLabel jLabel = (JLabel) jPanel.getComponent(3); jLabel.setIcon(treeAsset.getIcon()); return jPanel; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/tree/TreeTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.tree; import java.util.Comparator; import java.util.Date; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.AssetContainer; import net.nikr.eve.jeveasset.gui.shared.table.containers.HierarchyColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.LongInt; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.gui.shared.table.containers.Runs; import net.nikr.eve.jeveasset.gui.shared.table.containers.YesNo; import net.nikr.eve.jeveasset.i18n.TabsAssets; public enum TreeTableFormat implements EnumTableColumn { NAME(HierarchyColumn.class) { @Override public String getColumnName() { return TabsAssets.get().columnName(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getHierarchyColumn(); } }, NAME_TYPE(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnNameType(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getTypeName(); } @Override public boolean isShowDefault() { return false; } }, NAME_CUSTOM(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnNameCustom(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getItemName(); } @Override public boolean isShowDefault() { return false; } }, TAGS(Tags.class) { @Override public String getColumnName() { return TabsAssets.get().columnTags(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getTags(); } }, GROUP(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnGroup(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getItem().getGroup(); } }, CATEGORY(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnCategory(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getItem().getCategory(); } }, SLOT(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnSlot(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getItem().getSlot(); } }, CHARGE_SIZE(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnChargeSize(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getItem().getChargeSize(); } }, OWNER(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnOwner(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getOwnerName(); } }, LOCATION(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnLocation(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getLocation().getLocation(); } }, SECURITY(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnSecurity(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getSecurity(); } }, SYSTEM(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnSystem(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getLocation().getSystem(); } }, CONSTELLATION(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnConstellation(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getLocation().getConstellation(); } }, REGION(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnRegion(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getLocation().getRegion(); } }, FACTION_WARFARE_SYSTEM_OWNER(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnFactionWarfareSystemOwner(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnFactionWarfareSystemOwnerToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getLocation().getFactionWarfareSystemOwner(); } }, CONTAINER(AssetContainer.class) { @Override public String getColumnName() { return TabsAssets.get().columnContainer(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getAssetContainer(); } }, FLAG(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnFlag(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getFlagName(); } }, PRICE(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnPrice(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getAverage(this); } }, PRICE_SELL_MIN(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnPriceSellMin(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceSellMinToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getAverage(this); } }, PRICE_BUY_MAX(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnPriceBuyMax(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceBuyMaxToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getAverage(this); } }, PRICE_REPROCESSED(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnPriceReprocessed(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceReprocessedToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getAverage(this); } }, PRICE_MANUFACTURING(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnPriceManufacturing(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceManufacturingToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getItem().getPriceManufacturing(); } }, TRANSACTION_PRICE_LATEST(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnTransactionPriceLatest(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnTransactionPriceLatestToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getAverage(this); } }, TRANSACTION_PRICE_AVERAGE(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnTransactionPriceAverage(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnTransactionPriceAverageToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getAverage(this); } }, TRANSACTION_PRICE_MAXIMUM(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnTransactionPriceMaximum(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnTransactionPriceMaximumToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getAverage(this); } }, TRANSACTION_PRICE_MINIMUM(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnTransactionPriceMinimum(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnTransactionPriceMinimumToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getAverage(this); } }, PRICE_BASE(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnPriceBase(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceBaseToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getAverage(this); } }, VALUE_REPROCESSED(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnValueReprocessed(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnValueReprocessedToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getTotal(this); } }, VALUE(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnValue(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnValueToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getTotal(this); } }, PRICE_REPROCESSED_DIFFERENCE(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnPriceReprocessedDifference(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceReprocessedDifferenceToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getTotal(this); } }, PRICE_REPROCESSED_PERCENT(Percent.class) { @Override public String getColumnName() { return TabsAssets.get().columnPriceReprocessedPercent(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnPriceReprocessedPercentToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getAverage(this); } }, COUNT(Long.class) { @Override public String getColumnName() { return TabsAssets.get().columnCount(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getTotal(this); } }, COUNT_TYPE(Long.class) { @Override public String getColumnName() { return TabsAssets.get().columnTypeCount(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnTypeCountToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getTypeCount(); } }, META(Integer.class) { @Override public String getColumnName() { return TabsAssets.get().columnMeta(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getMeta(); } }, TECH(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnTech(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getItem().getTech(); } }, VOLUME(Float.class) { @Override public String getColumnName() { return TabsAssets.get().columnVolume(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getAverage(this); } }, VOLUME_TOTAL(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnVolumeTotal(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnVolumeTotalToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getTotal(this); } }, VOLUME_PACKAGED(Float.class) { @Override public String getColumnName() { return TabsAssets.get().columnVolumePackaged(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnVolumePackagedToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getItem().getVolumePackaged(); } }, VALUE_PER_VOLUME(Double.class) { @Override public String getColumnName() { return TabsAssets.get().columnValuePerVolume(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getAverage(this); } }, SINGLETON(String.class) { @Override public String getColumnName() { return TabsAssets.get().columnSingleton(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getSingleton(); } }, ADDED(Date.class) { @Override public String getColumnName() { return TabsAssets.get().columnAdded(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnAddedToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getAdded(); } @Override public boolean isShowDefault() { return false; } }, MATERIAL_EFFICIENCY(Integer.class) { @Override public String getColumnName() { return TabsAssets.get().columnMaterialEfficiency(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnMaterialEfficiencyToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getMaterialEfficiency(); } }, TIME_EFFICIENCY(Integer.class) { @Override public String getColumnName() { return TabsAssets.get().columnTimeEfficiency(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnTimeEfficiencyToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getTimeEfficiency(); } }, RUNS(Runs.class) { @Override public String getColumnName() { return TabsAssets.get().columnRuns(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnRunsToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getTotal(this); } }, CITADEL(YesNo.class) { @Override public String getColumnName() { return TabsAssets.get().columnStructure(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnStructureToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return YesNo.get(from.getLocation().isCitadel()); } @Override public boolean isShowDefault() { return false; } }, ITEM_ID(LongInt.class) { @Override public String getColumnName() { return TabsAssets.get().columnItemID(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnItemIDToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return new LongInt(from.getItemID()); } }, LOCATION_ID(LongInt.class) { @Override public String getColumnName() { return TabsAssets.get().columnLocationID(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnLocationIDToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return new LongInt(from.getLocationID()); } }, TYPE_ID(Integer.class) { @Override public String getColumnName() { return TabsAssets.get().columnTypeID(); } @Override public String getColumnToolTip() { return TabsAssets.get().columnTypeIDToolTip(); } @Override public Object getColumnValue(final TreeAsset from) { return from.getItem().getTypeID(); } }; private final Class type; private final Comparator comparator; private TreeTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/values/AssetValue.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.values; import java.util.HashMap; import java.util.Map; import java.util.Objects; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.TrackerData; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class AssetValue implements Comparable { private final static Map CACHE = new HashMap<>(); private static final String UNKNOWN_LOCATION = General.get().emptyLocation("(\\d+)").replace("[", "\\[").replace("]", "\\]"); private static final String CITADEL_MATCH = "\\[Citadel #(\\d+)\\]"; private static final String CITADEL_REPLACE = General.get().emptyLocation("$1").replace("[", "\\[").replace("]", "\\]"); private final String flag; private String location; private Long locationID; private String id; public static AssetValue create(String id) { return get(new AssetValue(id)); } public static AssetValue create(String location, String flag, Long locationID) { return get(new AssetValue(location, flag, locationID)); } public static void updateData() { try { TrackerData.writeLock(); for (AssetValue assetValue : CACHE.values()) { assetValue.update(); } } finally { TrackerData.writeUnlock(); } TrackerData.save("Asset values updated", true); } private static AssetValue get(final AssetValue add) { AssetValue cached = CACHE.get(add.getKey()); if (cached != null) { return cached; } else { CACHE.put(add.getKey(), add); return add; } } private AssetValue(String id) { String[] ids = id.split(" > "); if (ids.length == 2) { location = ids[0]; //Location flag = ids[1]; //Flag } else { location = id; flag = null; //Never used } locationID = null; update(); } private AssetValue(String location, String flag, Long locationID) { this.location = location; this.locationID = locationID; this.flag = flag; update(); } public String getLocation() { return location; } public String getFlag() { return flag; } public Long getLocationID() { return locationID; } public String getID() { return id; } private void update() { if (locationID == null) { locationID = updateLocationID(location); } this.location = updateLocationName(location, locationID); if (flag != null) { id = location + " > " + flag; } else { id =location; } } private Long updateLocationID(String name) { //Unknown Locations Long locationIDvalue = resolveUnknownLocationID(name, UNKNOWN_LOCATION); //Citadel if (locationIDvalue == null) { locationIDvalue = resolveUnknownLocationID(name.replace(",", ""), CITADEL_MATCH); } //Existing Locations if (locationIDvalue == null) { locationIDvalue = resolveExistingLocationID(name); } return locationIDvalue; } private String updateLocationName(String locationValue, Long locationIDvalue) { if (locationIDvalue == null) { return locationValue; } else { MyLocation myLocation = ApiIdConverter.getLocation(locationIDvalue); if (!myLocation.isEmpty()) { return myLocation.getLocation(); } else { if (locationValue.replace(",", "").matches(CITADEL_MATCH)) { return locationValue.replace(",", "").replaceAll(CITADEL_MATCH, CITADEL_REPLACE); } else { return locationValue; } } } } private Long resolveExistingLocationID(String locationValue) { for (MyLocation myLocation : StaticData.get().getLocations()) { if (myLocation.getLocation().equals(locationValue)) { return myLocation.getLocationID(); } } return null; } private Long resolveUnknownLocationID(String locationValue, String match) { String number = locationValue.replaceAll(match, "$1"); //Try to resolve unknown location try { return Long.valueOf(number); } catch (NumberFormatException ex) { return null; } } public String getKey() { return this.location + " " + this.flag; } @Override public int hashCode() { int hash = 3; hash = 29 * hash + Objects.hashCode(this.location); hash = 29 * hash + Objects.hashCode(this.flag); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final AssetValue other = (AssetValue) obj; if (!Objects.equals(this.location, other.location)) { return false; } if (!Objects.equals(this.flag, other.flag)) { return false; } return true; } @Override public int compareTo(AssetValue o) { return this.getID().compareTo(o.getID()); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/values/DataSetCreator.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.values; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyAccountBalance; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawClone; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.TrackerData; import net.nikr.eve.jeveasset.i18n.TabsValues; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class DataSetCreator { private static DataSetCreator creator; protected DataSetCreator() { } public static void createTrackerDataPoint(ProfileData profileData, Date date) { getCreator().createTrackerDataPointInner(profileData, date); } public static Map createDataSet(ProfileData profileData, Date date) { return getCreator().createDataSetInner(profileData, date); } public static Value getValue(Map values, String owner, Date date) { return getCreator().getValueInner(values, owner, date); } public static void purgeInvalidTrackerAssetValues() { try { Calendar calendar = Calendar.getInstance(); calendar.set(2019, 1, 1); Date issues943fixed = calendar.getTime(); //Deleted PI structures: https://github.com/esi/esi-issues/issues/943 TrackerData.writeLock(); for (List values : TrackerData.get().values()) { for (Value value : values) { List assetValues = new ArrayList<>(value.getAssetsFilter().keySet()); //Copy to allow modification of original during the loop for (AssetValue assetValue : assetValues) { Long locationID = assetValue.getLocationID(); if (locationID != null && (locationID > 9000000000000000000L //9e18 locations: https://github.com/ccpgames/esi-issues/issues/684 || ((locationID > 40000000 && locationID < 50000000) && value.getDate().before(issues943fixed)) //Deleted PI structures: https://github.com/esi/esi-issues/issues/943 )) { value.getAssetsFilter().remove(assetValue); Settings.get().getTrackerSettings().getFilters().remove(assetValue.getID()); } } } } } finally { TrackerData.writeUnlock(); } } private static DataSetCreator getCreator() { if (creator == null) { creator = new DataSetCreator(); } return creator; } private void createTrackerDataPointInner(ProfileData profileData, Date date) { Map data = createDataSetInner(profileData, date); //Add everything for (Map.Entry entry : data.entrySet()) { String owner = entry.getKey(); Value value = entry.getValue(); if (owner.equals(TabsValues.get().grandTotal())) { continue; } TrackerData.add(owner, value); } purgeInvalidTrackerAssetValues(); } private Map createDataSetInner(ProfileData profileData, Date date) { Map values = new HashMap<>(); Value total = new Value(TabsValues.get().grandTotal(), date); values.put(total.getName(), total); //Asset try { profileData.getAssetsEventList().getReadWriteLock().readLock().lock(); for (MyAsset asset : profileData.getAssetsEventList()) { if (asset.isGenerated()) { //Skip generated assets continue; } Value value = getValueInner(values, asset.getOwnerName(), date); //Location/Flag logic AssetValue id = createAssetID(asset); value.addAssets(id, asset); total.addAssets(id, asset); } } finally { profileData.getAssetsEventList().getReadWriteLock().readLock().unlock(); } //Implants for (Map.Entry> entry : profileData.getClonesList().entrySet()) { Value value = getValueInner(values, entry.getKey().getOwnerName(), date); double implants = 0; for (RawClone rawClone : entry.getValue()) { for (int typeID : rawClone.getImplants()) { implants += ApiIdConverter.getPrice(typeID, false); } } value.addImplants(implants); } //Account Balance try { profileData.getAccountBalanceEventList().getReadWriteLock().readLock().lock(); for (MyAccountBalance accountBalance : profileData.getAccountBalanceEventList()) { Value value = getValueInner(values, accountBalance.getOwnerName(), date); String id; if (accountBalance.isCorporation()) { //Corporation Wallets id = "" + (accountBalance.getAccountKey() - 999); } else { id = "0"; //Character Wallet } value.addBalance(id, accountBalance.getBalance()); total.addBalance(id, accountBalance.getBalance()); } } finally { profileData.getAccountBalanceEventList().getReadWriteLock().readLock().unlock(); } //Market Orders try { profileData.getMarketOrdersEventList().getReadWriteLock().readLock().lock(); addMarketOrders(profileData.getMarketOrdersEventList(), values, total, date); } finally { profileData.getMarketOrdersEventList().getReadWriteLock().readLock().unlock(); } //Industrys Job: Manufacturing try { profileData.getIndustryJobsEventList().getReadWriteLock().readLock().lock(); for (MyIndustryJob industryJob : profileData.getIndustryJobsEventList()) { //Manufacturing and not completed if (industryJob.isManufacturing() && industryJob.isNotDeliveredToAssets()) { Value value = getValueInner(values, industryJob.getOwnerName(), date); double manufacturingTotal = industryJob.getProductQuantity() * industryJob.getRuns() * ApiIdConverter.getPrice(industryJob.getProductTypeID(), false); value.addManufacturing(manufacturingTotal); total.addManufacturing(manufacturingTotal); } } } finally { profileData.getIndustryJobsEventList().getReadWriteLock().readLock().unlock(); } //Contract try { profileData.getContractEventList().getReadWriteLock().readLock().lock(); addContracts(profileData.getContractEventList(), values, profileData.getOwners(), total, date); } finally { profileData.getContractEventList().getReadWriteLock().readLock().unlock(); } //Contract Items try { profileData.getContractItemEventList().getReadWriteLock().readLock().lock(); addContractItems(profileData.getContractItemEventList(), values, profileData.getOwners(), total, date); } finally { profileData.getContractItemEventList().getReadWriteLock().readLock().unlock(); } //Skills for (Map.Entry entry : profileData.getSkillPointsTotal().entrySet()) { final String owner = entry.getKey(); final Long totalSkillPoints = entry.getValue(); Value value = getValueInner(values, owner, date); value.setSkillPoints(totalSkillPoints); total.addSkillPointValue(totalSkillPoints, 0); } return values; } protected void addMarketOrders(List marketOrders, Map values, Value total, Date date) { final boolean useAssetPriceForSellOrders = Settings.get().isTrackerUseAssetPriceForSellOrders(); for (MyMarketOrder marketOrder : marketOrders) { if (marketOrder.isActive()) { Value value; if (marketOrder.isCorp() && !marketOrder.isCorporation() && marketOrder.getOwner().getCorporationName() != null) { value = getValueInner(values, marketOrder.getOwner().getCorporationName(), date); } else { value = getValueInner(values, marketOrder.getOwnerName(), date); } if (marketOrder.isBuyOrder()) { //Buy Orders value.addEscrows(marketOrder.getEscrow()); value.addEscrowsToCover((marketOrder.getPrice() * marketOrder.getVolumeRemain()) - marketOrder.getEscrow()); total.addEscrows(marketOrder.getEscrow()); total.addEscrowsToCover((marketOrder.getPrice() * marketOrder.getVolumeRemain()) - marketOrder.getEscrow()); } else { //Sell Orders if (assetsUpdated(marketOrder.getCreatedOrIssued(), marketOrder.getOwner())) { //To avoid duplicating the value: //Only add sell orders value that was created before the last asset update final double price; if (useAssetPriceForSellOrders) { price = marketOrder.getDynamicPrice(); } else { price = marketOrder.getPrice(); } value.addSellOrders(price * marketOrder.getVolumeRemain()); total.addSellOrders(price * marketOrder.getVolumeRemain()); } } } } } protected void addContracts(List contractItems, Map values, Map owners, Value total, Date date) { for (MyContract contract : contractItems) { OwnerType issuer; if (contract.isForCorp()) { issuer = owners.get(contract.getIssuerCorpID()); } else { issuer = owners.get(contract.getIssuerID()); } OwnerType acceptor = owners.get(contract.getAcceptorID()); //Contract Collateral if (contract.isCourierContract()) { //Shipping cargo (will get collateral or cargo back) //We can not get the assets in courier contracts, so we use only available value: collateral if (issuer != null) { //Issuer //Not Done & Assets Updated = Add Collateral //If Assets are not updated. nothing to counter... //OR //Done & Assets not updated = Add Collateral //If assets is updated, so are all the values if (assetsUpdated(contract.getDateIssued(), issuer) && (contract.isInProgress() || contract.isOpen())) { addContractCollateral(contract, values, total, date, issuer.getOwnerName()); //OK } else if (assetsNotUpdated(contract.getDateCompleted(), issuer) && contract.isCompletedSuccessful()) { addContractCollateral(contract, values, total, date, issuer.getOwnerName()); //NOT TESTED } } //Transporting cargo (will get collateral back) if (acceptor != null) { //Not Done & Balance Updated = Add Collateral //If balance is not updated, there is nothing to counter... if (balanceUpdated(contract.getDateIssued(), acceptor) && contract.isInProgress()) { addContractCollateral(contract, values, total, date, acceptor.getOwnerName()); //OK } } } //Contract Isk if (issuer != null) { //Issuer if (contract.isOpen()) { //Not Completed //Not Done & Balance Updated = Add Reward (We still own the isk, until the contract is completed) //If balance is not updated, there is nothing to counter... if (balanceUpdated(contract.getDateIssued(), issuer)) { //Buying: +Reward addContractValue(values, total, date, issuer.getOwnerName(), contract.getReward()); //OK } // else: Selling: we do not own the price isk, until the contract is completed } else if (contract.isCompletedSuccessful()) { //Completed //Done & Balance not updated yet = Add Price + Remove Reward (Contract completed, update with the current values) //If balance is updated, so are all the values if (balanceNotUpdated(contract.getDateCompleted(), issuer)) { //NOT TESTED //Sold: +Price addContractValue(values, total, date, issuer.getOwnerName(), contract.getPrice()); //Bought: -Reward addContractValue(values, total, date, issuer.getOwnerName(), -contract.getReward()); } } } if (acceptor != null && contract.isCompletedSuccessful()) { //Completed //Done & Balance not updated yet = Remove Price & Add Reward (Contract completed, update with the current values) //If balance is updated, so are all the values if (balanceNotUpdated(contract.getDateCompleted(), acceptor)) { //NOT TESTED //Bought: -Price addContractValue(values, total, date, acceptor.getOwnerName(), -contract.getPrice()); //Sold: +Reward addContractValue(values, total, date, acceptor.getOwnerName(), contract.getReward()); } } } } protected void addContractItems(List contractItems, Map values, Map owners, Value total, Date date) { //Contract Items for (MyContractItem contractItem : contractItems) { MyContract contract = contractItem.getContract(); if (contract.isIgnoreContract()) { continue; //Ignore courier contracts } if (contractItem.getItem() != null && contractItem.getItem().isBlueprint() && contractItem.getBlueprint() == null) { continue; //Ignore blueprints value - as we do not know if it's a BPO or BPC. Feels like assuming BPC (zero value) is the better option } //Else: Not a blueprint or we have data from the public contract items endpoints, so we do know if it's a BPC or PBO :) OwnerType issuer; if (contract.isForCorp()) { issuer = owners.get(contract.getIssuerCorpID()); } else { issuer = owners.get(contract.getIssuerID()); } OwnerType acceptor = owners.get(contract.getAcceptorID()); //Issuer if (issuer != null) { if (contract.isOpen()) { //Not Completed if (contractItem.isIncluded()) { //Item are being sold //Not Done & Assets Updated = Add Item Value (We still own the item, until the contract is completed) //If Assets is not updated, nothing to counter if (assetsUpdated(contract.getDateIssued(), issuer)) { //Selling: +Item addContractValue(values, total, date, issuer.getOwnerName(), contractItem.getDynamicPrice() * contractItem.getQuantity()); } } // else: Item is being bought - nothing have changed until the contract is done } else if (contract.isCompletedSuccessful()) { //Completed //Done & Assets not updated yet = Add Bought Item & Remove Sold Item (Contract completed, update with the current values) //If Assets is updated, so are all the values if (assetsNotUpdated(contract.getDateCompleted(), issuer)) { if (contractItem.isIncluded()) { //Item is being sold: remove item value //Sold: -Item addContractValue(values, total, date, issuer.getOwnerName(), (-contractItem.getDynamicPrice() * contractItem.getQuantity())); } else { //Item are being bought: Add item value //Bought: +Item addContractValue(values, total, date, issuer.getOwnerName(), contractItem.getDynamicPrice() * contractItem.getQuantity()); } } } } if (acceptor != null && contract.isCompletedSuccessful()) { //Completed //Done & Assets not updated yet = Add Bought Item & Remove Sold Item (Contract completed, update with the current values) //If Assets is updated, so are all the values if (assetsNotUpdated(contract.getDateCompleted(), acceptor)) { if (contractItem.isIncluded()) { //Items are being bought: Add items value //Bought: +Item addContractValue(values, total, date, acceptor.getOwnerName(), contractItem.getDynamicPrice() * contractItem.getQuantity()); } else { //Items are being sold: remove items value //Sold: -Item addContractValue(values, total, date, acceptor.getOwnerName(), (-contractItem.getDynamicPrice() * contractItem.getQuantity())); } } } } } private boolean assetsUpdated(Date date, OwnerType owner) { if (date == null) { return false; } if (owner.getAssetLastUpdate() == null) { //Not updated owner or old profile data return false; } return owner.getAssetLastUpdate().after(date); } private boolean assetsNotUpdated(Date date, OwnerType owner) { if (date == null) { return false; } if (owner.getAssetLastUpdate() == null) { //Not updated owner or old profile data return false; } return owner.getAssetLastUpdate().before(date); } private boolean balanceUpdated(Date date, OwnerType owner) { if (date == null) { return false; } if (owner.getBalanceLastUpdate() == null) { //Not updated owner or old profile data return false; } return owner.getBalanceLastUpdate().after(date); } private boolean balanceNotUpdated(Date date, OwnerType owner) { if (date == null) { return false; } if (owner.getBalanceLastUpdate() == null) { //Not updated owner or old profile data return false; } return owner.getBalanceLastUpdate().before(date); } private void addContractCollateral(MyContract contract, Map values, Value total, Date date, String owner) { double contractCollateral = contract.getCollateral(); Value value = getValueInner(values, owner, date); value.addContractCollateral(contractCollateral); total.addContractCollateral(contractCollateral); } private void addContractValue(Map values, Value total, Date date, String owner, double change) { Value value = getValueInner(values, owner, date); value.addContractValue(change); total.addContractValue(change); } private AssetValue createAssetID(MyAsset asset) { String flagID = null; if (asset.isCorporation()) { for (MyAsset parent : asset.getParents()) { //check if in office if (parent.getTypeID() == 27) { //Office flagID = getAssetFlag(asset); break; } } } return AssetValue.create(asset.getLocation().getLocation(), flagID, asset.getLocation().getLocationID()); } private String getAssetFlag(MyAsset asset) { if (asset == null) { return null; } if (asset.getFlag().contains("CorpSAG")) { return asset.getFlag(); } else { return getAssetFlag(asset.getParent()); } } private Value getValueInner(Map values, String owner, Date date) { Value value = values.get(owner); if (value == null) { value = new Value(owner, date); values.put(owner, value); } return value; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/values/IskData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.values; import ca.odell.glazedlists.EventList; import java.util.Map; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.profile.TableData; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerSkillPointFilter; import net.nikr.eve.jeveasset.i18n.TabsValues; public class IskData extends TableData { public IskData(Program program) { super(program); } public IskData(ProfileManager profileManager, ProfileData profileData) { super(profileManager, profileData); } public EventList getData() { EventList eventList = EventListManager.create(); updateData(eventList); return eventList; } public void updateData(EventList eventList) { Map values = DataSetCreator.createDataSet(profileData, Settings.getNow()); Value total = values.get(TabsValues.get().grandTotal()); total.setSkillPoints(0); for (Value value : values.values()) { TrackerSkillPointFilter skillPointFilter = Settings.get().getTrackerSettings().getSkillPointFilters().get(value.getName()); if (skillPointFilter != null) { if (skillPointFilter.isEnabled()) { value.setSkillPointsMinimum(skillPointFilter.getMinimum()); total.addSkillPointValue(value.getSkillPoints(), skillPointFilter.getMinimum()); } else { value.setSkillPoints(0); } } else { total.addSkillPointValue(value.getSkillPoints(), 0); } } try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(values.values()); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/values/JValueTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.values; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.Component; import java.awt.Font; import javax.swing.table.TableCellRenderer; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.i18n.TabsValues; public class JValueTable extends JAutoColumnTable { private final DefaultEventTableModel tableModel; public JValueTable(final Program program, final DefaultEventTableModel tableModel) { super(program, tableModel); this.tableModel = tableModel; } @Override public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) { Component component = super.prepareRenderer(renderer, row, column); boolean isSelected = isCellSelected(row, column); Value value = tableModel.getElementAt(row); String columnName = (String) this.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); Object object = getValueAt(row, column); boolean string; if (object instanceof String) { string = true; } else { string = false; } //Grand Total if (value.isGrandTotal()) { ColorSettings.configCell(component, ColorEntry.GLOBAL_GRAND_TOTAL, isSelected); return component; } //Best Asset: none if (string && TabsValues.get().none().equals(value.getBestAssetName()) && columnName.equals(ValueTableFormat.BEST_ASSET_NAME.getColumnName())) { Font font = component.getFont(); component.setFont(new Font(font.getName(), Font.ITALIC, font.getSize())); } //Best Module: none if (string && TabsValues.get().none().equals(value.getBestModuleName()) && columnName.equals(ValueTableFormat.BEST_MODULE_NAME.getColumnName())) { Font font = component.getFont(); component.setFont(new Font(font.getName(), Font.ITALIC, font.getSize())); } //Best Ship (Fitted): none if (string && TabsValues.get().none().equals(value.getBestShipFittedName()) && columnName.equals(ValueTableFormat.BEST_SHIP_FITTED_NAME.getColumnName())) { Font font = component.getFont(); component.setFont(new Font(font.getName(), Font.ITALIC, font.getSize())); } //Best Ship: none if (string && TabsValues.get().none().equals(value.getBestShipName()) && columnName.equals(ValueTableFormat.BEST_SHIP_NAME.getColumnName())) { Font font = component.getFont(); component.setFont(new Font(font.getName(), Font.ITALIC, font.getSize())); } return component; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/values/Value.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.values; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.Map; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyShip; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.i18n.TabsValues; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; public class Value implements Comparable, LocationType { public static final Comparator DATE_COMPARATOR = new ValueDateComparator(); private final static long MINIMUM_SKILL_POINTS = 5000000; private final static double SKILL_EXTRACTOR_SIZE = 500000.0; private final String name; private final Date date; private final String compare; private double assets = 0; private double implants = 0; private final Map assetsFilter = new HashMap<>(); private boolean assetsContainersFixed = true; //New data is fixed private double sellOrders = 0; private double escrows = 0; private double escrowsToCover = 0; private double balance = 0; private final Map balanceFilter = new HashMap<>(); private double manufacturing; private double contractCollateral; private double contractValue = 0; private long skillPoints = 0; private double skillPointValue = 0; private MyAsset bestAsset = null; private MyAsset bestShip = null; private MyAsset bestShipFitted = null; private MyAsset bestModule = null; private MyShip activeShip = null; public Value(Date date) { this("", date); } public Value(String name, Date date) { this.name = name; this.date = date; this.compare = name + Formatter.simpleDate(date); } public void addAssets(double assets) { this.assets = this.assets + assets; } public void addAssets(AssetValue id, Double assets) { this.assets = this.assets + assets; Double now = this.assetsFilter.get(id); if (now == null) { now = 0.0; } this.assetsFilter.put(id, now + assets); } public void addAssets(AssetValue id, MyAsset asset) { double total = asset.getDynamicPrice() * asset.getCount(); addAssets(id, total); setBestAsset(asset); setBestShip(asset); setBestShipFitted(asset); setBestModule(asset); setCurrentShip(asset); } public void removeAssets(AssetValue id) { Double oldAssets = this.assetsFilter.get(id); //Get value this.assets = this.assets - oldAssets; //Removing value from total this.assetsFilter.remove(id); //Removing item } public void addSellOrders(double sellOrders) { this.sellOrders = this.sellOrders + sellOrders; } public void addImplants(double implants) { this.implants = this.implants + implants; } public void addEscrows(double escrows) { this.escrows = this.escrows + escrows; } public void addEscrowsToCover(double escrowsToCover) { this.escrowsToCover = this.escrowsToCover + escrowsToCover; } public void addBalance(double balance) { this.balance = this.balance + balance; } public void addBalance(String id, double balance) { this.balance = this.balance + balance; Double now = this.balanceFilter.get(id); if (now == null) { now = 0.0; } this.balanceFilter.put(id, now + balance); } public void removeBalance(String id) { Double oldBalance = this.balanceFilter.get(id); //Get value this.balance = this.balance - oldBalance; //Removing value from total this.balanceFilter.remove(id); //Removing item } public void addManufacturing(double manufacturing) { this.manufacturing = this.manufacturing + manufacturing; } public void addContractCollateral(double contractCollateral) { this.contractCollateral = this.contractCollateral + contractCollateral; } public void addContractValue(double contractValue) { this.contractValue = this.contractValue + contractValue; } public void addSkillPointValue(long skillPoints, long minimum) { skillPointValue = skillPointValue + calcSkillPointValue(skillPoints, minimum); } public Date getDate() { return date; } public String getName() { return name; } public Map getAssetsFilter() { return assetsFilter; } public boolean isAssetsContainersFixed() { return assetsContainersFixed; } public double getAssetsTotal() { return assets; } public double getImplants() { return implants; } public double getSellOrders() { return sellOrders; } public double getEscrows() { return escrows; } public double getEscrowsToCover() { return escrowsToCover; } public Map getBalanceFilter() { return balanceFilter; } public double getBalanceTotal() { return balance; } public double getManufacturing() { return manufacturing; } public double getContractCollateral() { return contractCollateral; } public double getContractValue() { return contractValue; } public long getSkillPoints() { return skillPoints; } public double getSkillPointValue() { return skillPointValue; } private double calcSkillPointValue(long totalSkillPoints, long mimimum) { double extractorPrice = ApiIdConverter.getPrice(40519, false); //Skill Extractor double injectorPrice = ApiIdConverter.getPrice(40520, false); //Large Skill Injector if (totalSkillPoints < MINIMUM_SKILL_POINTS) { return 0; } long extractableSkillPoints = totalSkillPoints - Math.max(MINIMUM_SKILL_POINTS, mimimum); double injecters = Math.floor(extractableSkillPoints / SKILL_EXTRACTOR_SIZE); if (injecters < 1) { return 0; } return injecters * (injectorPrice - extractorPrice); } public String getBestAssetName() { return getName(bestAsset); } public String getBestShipName() { return getName(bestShip); } public String getBestShipFittedName() { return getName(bestShipFitted); } public String getBestModuleName() { return getName(bestModule); } public double getBestAssetValue() { return getDynamicPrice(bestAsset); } public double getBestShipValue() { return getDynamicPrice(bestShip); } public double getBestShipFittedValue() { if (bestShipFitted != null) { return getShipFittedValue(bestShipFitted); } else { return 0; } } public double getBestModuleValue() { return getDynamicPrice(bestModule); } @Override public MyLocation getLocation() { if (activeShip != null) { return activeShip.getLocation(); } else { return ApiIdConverter.getLocation(0); } } public String getActiveShip() { if (activeShip != null) { return activeShip.getName(); } return TabsValues.get().empty(); } public String getCurrentStation() { if (activeShip != null) { return activeShip.getLocation().getStation(); } return TabsValues.get().empty(); } public String getCurrentSystem() { if (activeShip != null) { return activeShip.getLocation().getSystem(); } return TabsValues.get().empty(); } public String getCurrentConstellation() { if (activeShip != null) { return activeShip.getLocation().getConstellation(); } return TabsValues.get().empty(); } public String getCurrentRegion() { if (activeShip != null) { return activeShip.getLocation().getRegion(); } return TabsValues.get().empty(); } private String getName(MyAsset asset) { if (asset != null) { return asset.getName(); } else { return TabsValues.get().none(); } } private double getDynamicPrice(MyAsset asset) { if (asset != null) { return asset.getDynamicPrice(); } else { return 0; } } public boolean isGrandTotal() { return TabsValues.get().grandTotal().equals(name); } public double getTotal() { return getAssetsTotal() + getImplants() + getBalanceTotal() + getEscrows() + getSellOrders() + getManufacturing() + getContractCollateral() + getContractValue() + getSkillPointValue(); } public void setAssetsTotal(double assets) { this.assets = assets; } public void setImplants(double implants) { this.implants = implants; } public void setAssetsContainersFixed(boolean assetsContainersFixed) { this.assetsContainersFixed = assetsContainersFixed; } public void setSellOrders(double sellOrders) { this.sellOrders = sellOrders; } public void setEscrows(double escrows) { this.escrows = escrows; } public void setEscrowsToCover(double escrowsToCover) { this.escrowsToCover = escrowsToCover; } public void setBalanceTotal(double balance) { this.balance = balance; } public void setManufacturing(double manufacturing) { this.manufacturing = manufacturing; } public void setContractCollateral(double contractCollateral) { this.contractCollateral = contractCollateral; } public void setContractValue(double contractValue) { this.contractValue = contractValue; } public void setSkillPoints(long skillPoints) { this.skillPoints = skillPoints; skillPointValue = calcSkillPointValue(skillPoints, 0); } public void setSkillPointsMinimum(long minimum) { skillPointValue = calcSkillPointValue(skillPoints, minimum); } private void setBestAsset(MyAsset bestAsset) { if (this.bestAsset == null) { //First this.bestAsset = bestAsset; } else if (bestAsset.getDynamicPrice() > this.bestAsset.getDynamicPrice()) { //Higher this.bestAsset = bestAsset; } } private void setBestShip(MyAsset bestShip) { if (!bestShip.getItem().isShip()) { return; //Not a ship } if (this.bestShip == null) { //First this.bestShip = bestShip; } else if (bestShip.getDynamicPrice() > this.bestShip.getDynamicPrice()) { //Higher this.bestShip = bestShip; } } private void setBestShipFitted(MyAsset bestShipFitted) { if (!bestShipFitted.getItem().isShip()) { return; //Not a ship } if (this.bestShipFitted == null) { //First this.bestShipFitted = bestShipFitted; } else if (getShipFittedValue(bestShipFitted) > getShipFittedValue(this.bestShipFitted)) { //Higher this.bestShipFitted = bestShipFitted; } } private void setBestModule(MyAsset bestModule) { if (!bestModule.getItem().getCategory().equals(Item.CATEGORY_MODULE)) { return; //Not a Module } if (this.bestModule == null) { //First this.bestModule = bestModule; } else if (bestModule.getDynamicPrice() > this.bestModule.getDynamicPrice()) { //Higher this.bestModule = bestModule; } } private void setCurrentShip(MyAsset asset) { if (!isGrandTotal() && this.activeShip == null) { this.activeShip = asset.getOwner().getActiveShip(); } } private double getShipFittedValue(MyAsset patentAsset) { if (patentAsset.getCount() > 1) { //Stack of ships - only count the price of a single ship (not value of all the ships) return patentAsset.getDynamicPrice(); } else { return getShipFittedValueInner(patentAsset); } } private double getShipFittedValueInner(MyAsset patentAsset) { double value = (patentAsset.getDynamicPrice() * patentAsset.getCount()); for (MyAsset asset : patentAsset.getAssets()) { value = value + getShipFittedValue(asset); } return value; } @Override public int hashCode() { int hash = 7; hash = 79 * hash + (this.compare != null ? this.compare.hashCode() : 0); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Value other = (Value) obj; if ((this.compare == null) ? (other.compare != null) : !this.compare.equals(other.compare)) { return false; } return true; } @Override public int compareTo(Value o) { return this.getName().compareToIgnoreCase(o.getName()); } private static class ValueDateComparator implements Comparator { @Override public int compare(Value o1, Value o2) { return Formatter.simpleDate(o1.date).compareTo(Formatter.simpleDate(o2.date)); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/values/ValueRetroTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.values; import java.awt.Color; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.GroupLayout; import javax.swing.JComboBox; import javax.swing.JEditorPane; import javax.swing.JLabel; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.settings.Colors; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.i18n.TabsValues; public class ValueRetroTab extends JMainTabSecondary { private enum ValueRetroAction { OWNER_SELECTED, CORP_SELECTED } //GUI private final JComboBox jCharacters; private final JEditorPane jCharacter; private final JComboBox jCorporations; private final JEditorPane jCorporation; private final JEditorPane jTotal; //Data private Map characters; private Map corporations; private Value total; private String backgroundHexColor; private String gridHexColor; private String valueHexColor; public static final String NAME = "valueretro"; //Not to be changed! public ValueRetroTab(final Program program) { super(program, NAME, TabsValues.get().oldTitle(), Images.TOOL_VALUES.getIcon(), true); ListenerClass listener = new ListenerClass(); backgroundHexColor = Integer.toHexString(jPanel.getBackground().getRGB()); backgroundHexColor = backgroundHexColor.substring(2, backgroundHexColor.length()); gridHexColor = Integer.toHexString(jPanel.getBackground().darker().getRGB()); gridHexColor = gridHexColor.substring(2, gridHexColor.length()); valueHexColor = Integer.toHexString(Colors.TEXTFIELD_BACKGROUND.getColor().getRGB()); valueHexColor = valueHexColor.substring(2, valueHexColor.length()); jCharacters = new JComboBox<>(); jCharacters.setActionCommand(ValueRetroAction.OWNER_SELECTED.name()); jCharacters.addActionListener(listener); jCharacter = new JEditorPane("text/html", ""); jCharacter.setEditable(false); jCharacter.setOpaque(false); jCharacter.setBackground(Colors.COMPONENT_TRANSPARENT.getColor()); jCharacter.setBorder(null); JScrollPane jCharacterScroll = new JScrollPane(jCharacter); jCharacterScroll.setBorder(null); jCorporations = new JComboBox<>(); jCorporations.setActionCommand(ValueRetroAction.CORP_SELECTED.name()); jCorporations.addActionListener(listener); jCorporation = new JEditorPane("text/html", ""); jCorporation.setEditable(false); jCorporation.setOpaque(false); jCorporation.setBackground(Colors.COMPONENT_TRANSPARENT.getColor()); jCorporation.setBorder(null); JScrollPane jCorporationScroll = new JScrollPane(jCorporation); jCorporationScroll.setBorder(null); JLabel jTotalLabel = new JLabel(" " + TabsValues.get().grandTotal()); jTotalLabel.setBackground(new Color(34, 34, 34)); jTotalLabel.setForeground(Color.WHITE); Font font = jTotalLabel.getFont(); jTotalLabel.setFont(new Font(font.getName(), Font.BOLD, font.getSize() + 2)); jTotalLabel.setOpaque(true); jTotal = new JEditorPane("text/html", ""); jTotal.setEditable(false); jTotal.setOpaque(false); jTotal.setBackground(Colors.COMPONENT_TRANSPARENT.getColor()); jTotal.setBorder(null); JScrollPane jTotalScroll = new JScrollPane(jTotal); jTotalScroll.setBorder(null); layout.setHorizontalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jTotalScroll, 10, 10, Short.MAX_VALUE) .addComponent(jTotalLabel, 10, 10, Short.MAX_VALUE) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jCharacterScroll, 10, 10, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addGap(3) .addComponent(jCharacters, 10, 10, Short.MAX_VALUE) .addGap(3) ) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jCorporationScroll, 10, 10, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addGap(3) .addComponent(jCorporations, 10, 10, Short.MAX_VALUE) .addGap(3) ) ) ) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(jTotalLabel, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCharacters, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) .addComponent(jCorporations, Program.getButtonsHeight(), Program.getButtonsHeight(), Program.getButtonsHeight()) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(jTotalScroll, 0, 0, Short.MAX_VALUE) .addComponent(jCharacterScroll, 0, 0, Short.MAX_VALUE) .addComponent(jCorporationScroll, 0, 0, Short.MAX_VALUE) ) ); } @Override public void updateData() { calcTotal(); jCharacters.removeAllItems(); List characterNames = new ArrayList<>(characters.keySet()); Collections.sort(characterNames, StringComparators.CASE_INSENSITIVE); for (String owner : characterNames) { jCharacters.addItem(owner); } if (jCharacters.getModel().getSize() > 0) { jCharacters.setEnabled(true); } else { jCharacters.addItem(TabsValues.get().oldNoCharacter()); jCharacters.setEnabled(false); } jCharacters.setSelectedIndex(0); jCorporations.removeAllItems(); List corporationNames = new ArrayList<>(corporations.keySet()); Collections.sort(corporationNames, StringComparators.CASE_INSENSITIVE); for (String corp : corporationNames) { jCorporations.addItem(corp); } if (jCorporations.getModel().getSize() > 0) { jCorporations.setEnabled(true); } else { jCorporations.addItem(TabsValues.get().oldNoCorporation()); jCorporations.setEnabled(false); } jCorporations.setSelectedIndex(0); setData(jTotal, total); } @Override public void clearData() { } @Override public void updateCache() {} @Override public Collection getLocations() { return new ArrayList<>(); //No Location } private boolean calcTotal() { Date date = Settings.getNow(); Map values = DataSetCreator.createDataSet(program.getProfileData(), Settings.getNow()); characters = new HashMap<>(); corporations = new HashMap<>(); total = values.get(TabsValues.get().grandTotal()); for (OwnerType owner : program.getOwnerTypes()) { Value value = DataSetCreator.getValue(values, owner.getOwnerName(), date); if (owner.isCorporation()) { corporations.put(value.getName(), value); } else { characters.put(value.getName(), value); if (owner.getCorporationName() != null) { Value corpValue = values.get(owner.getCorporationName()); if (corpValue != null) { corporations.put(corpValue.getName(), corpValue); } } } } return !EventListManager.isEmpty(program.getProfileData().getAssetsEventList()); } private void setData(JEditorPane jEditorPane, Value value) { if (value == null) { value = new Value("", Settings.getNow()); //Create empty } Output output = new Output(); output.addHeading(TabsValues.get().columnTotal()); output.addValue(value.getTotal()); output.addNone(); output.addHeading(TabsValues.get().columnWalletBalance()); output.addValue(value.getBalanceTotal()); output.addNone(); output.addHeading(TabsValues.get().columnAssets()); output.addValue(value.getAssetsTotal()); output.addNone(); output.addHeading(TabsValues.get().columnSellOrders()); output.addValue(value.getSellOrders()); output.addNone(); output.addHeading(TabsValues.get().columnEscrowsToCover()); output.addValue(value.getEscrows(), value.getEscrowsToCover()); output.addNone(); output.addHeading(TabsValues.get().columnBestAsset()); output.addValue(value.getBestAssetName(), value.getBestAssetValue()); output.addNone(2); output.addHeading(TabsValues.get().columnBestShip()); output.addValue(value.getBestShipName(), value.getBestShipValue()); output.addNone(2); /* //FIXME - No room for Best Ship Fitted output.addHeading(TabsValues.get().columnBestShipFitted()); output.addValue(value.getBestShipFittedName(), value.getBestShipFittedValue()); output.addNone(2); */ output.addHeading(TabsValues.get().columnBestModule()); output.addValue(value.getBestModuleName(), value.getBestModuleValue()); output.addNone(2); jEditorPane.setText(output.getOutput()); jEditorPane.setCaretPosition(0); } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (ValueRetroAction.OWNER_SELECTED.name().equals(e.getActionCommand())) { String s = (String) jCharacters.getSelectedItem(); setData(jCharacter, characters.get(s)); } if (ValueRetroAction.CORP_SELECTED.name().equals(e.getActionCommand())) { //String output = ""; String s = (String) jCorporations.getSelectedItem(); setData(jCorporation, corporations.get(s)); } } } private class Output { private String output; private String moduleOutput; public Output() { output = "" + "
" + ""; moduleOutput = ""; } public void addHeading(final String heading) { output = output + ""; moduleOutput = ""; } public void addValue(final double value1, final double value2) { if (value1 != 0 && value2 != 0) { addValue(Formatter.iskFormat(value1), " (" + Formatter.iskFormat(value2) + ")"); } else if (value1 != 0) { addValue(Formatter.iskFormat(value1), null); } } public void addValue(final double value) { if (value != 0) { addValue(Formatter.iskFormat(value), null); } } public void addValue(final String value1, final double value2) { if (value1 != null && value2 != 0) { addValue(value1, "
" + Formatter.iskFormat(value2)); } } private void addValue(final String value1, final String value2) { if (value1 != null || value2 != null) { moduleOutput = moduleOutput + ""; } } public void addNone(final int count) { if (moduleOutput.isEmpty()) { String temp = ""; for (int i = 1; i < count; i++) { temp = temp + "
"; } addValue("" + TabsValues.get().none() + "
", temp); } output = output + moduleOutput; } public void addNone() { addNone(1); } public String getOutput() { return output + "
" + heading + "
"; } if (value1 != null) { moduleOutput = moduleOutput + value1; } if (value2 != null) { moduleOutput = moduleOutput + value2; } if (value1 != null || value2 != null) { moduleOutput = moduleOutput + "
"; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/values/ValueTableFormat.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.values; import java.util.Comparator; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.i18n.TabsValues; public enum ValueTableFormat implements EnumTableColumn { NAME(String.class) { @Override public String getColumnName() { return TabsValues.get().columnOwner(); } @Override public Object getColumnValue(final Value from) { return from.getName(); } }, TOTAL(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnTotal(); } @Override public Object getColumnValue(final Value from) { return from.getTotal(); } }, BALANCE(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnWalletBalance(); } @Override public Object getColumnValue(final Value from) { return from.getBalanceTotal(); } }, DIVISION_1(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnWalletDivision1(); } @Override public Object getColumnValue(final Value from) { return from.getBalanceFilter().get("1"); } }, DIVISION_2(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnWalletDivision2(); } @Override public Object getColumnValue(final Value from) { return from.getBalanceFilter().get("2"); } }, DIVISION_3(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnWalletDivision3(); } @Override public Object getColumnValue(final Value from) { return from.getBalanceFilter().get("3"); } }, DIVISION_4(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnWalletDivision4(); } @Override public Object getColumnValue(final Value from) { return from.getBalanceFilter().get("4"); } }, DIVISION_5(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnWalletDivision5(); } @Override public Object getColumnValue(final Value from) { return from.getBalanceFilter().get("5"); } }, DIVISION_6(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnWalletDivision6(); } @Override public Object getColumnValue(final Value from) { return from.getBalanceFilter().get("6"); } }, DIVISION_7(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnWalletDivision7(); } @Override public Object getColumnValue(final Value from) { return from.getBalanceFilter().get("7"); } }, ASSETS(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnAssets(); } @Override public Object getColumnValue(final Value from) { return from.getAssetsTotal(); } }, SELL_ORDERS(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnSellOrders(); } @Override public Object getColumnValue(final Value from) { return from.getSellOrders(); } }, ESCROWS(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnEscrows(); } @Override public Object getColumnValue(final Value from) { return from.getEscrows(); } }, ESCROWS_TO_COVER(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnEscrowsToCover(); } @Override public Object getColumnValue(final Value from) { return from.getEscrowsToCover(); } }, MANUFACTURING(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnManufacturing(); } @Override public Object getColumnValue(final Value from) { return from.getManufacturing(); } }, CONTRACT_COLLATERAL(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnContractCollateral(); } @Override public Object getColumnValue(final Value from) { return from.getContractCollateral(); } }, CONTRACT_VALUE(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnContractValue(); } @Override public Object getColumnValue(final Value from) { return from.getContractValue(); } }, SKILL_POINT_VALUE(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnSkillPointValue(); } @Override public Object getColumnValue(final Value from) { return from.getSkillPointValue(); } }, BEST_ASSET_NAME(String.class) { @Override public String getColumnName() { return TabsValues.get().columnBestAsset(); } @Override public Object getColumnValue(final Value from) { return from.getBestAssetName(); } }, BEST_ASSET_VALUE(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnBestAsset(); } @Override public Object getColumnValue(final Value from) { return from.getBestAssetValue(); } }, BEST_SHIP_FITTED_NAME(String.class) { @Override public String getColumnName() { return TabsValues.get().columnBestShipFitted(); } @Override public Object getColumnValue(final Value from) { return from.getBestShipFittedName(); } }, BEST_SHIP_FITTED_VALUE(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnBestShipFitted(); } @Override public Object getColumnValue(final Value from) { return from.getBestShipFittedValue(); } }, BEST_SHIP_NAME(String.class) { @Override public String getColumnName() { return TabsValues.get().columnBestShip(); } @Override public Object getColumnValue(final Value from) { return from.getBestShipName(); } }, BEST_SHIP_VALUE(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnBestShip(); } @Override public Object getColumnValue(final Value from) { return from.getBestShipValue(); } }, BEST_MODULE_NAME(String.class) { @Override public String getColumnName() { return TabsValues.get().columnBestModule(); } @Override public Object getColumnValue(final Value from) { return from.getBestModuleName(); } }, BEST_MODULE_VALUE(Double.class) { @Override public String getColumnName() { return TabsValues.get().columnBestModule(); } @Override public Object getColumnValue(final Value from) { return from.getBestModuleValue(); } }, CURRENT_SHIP(String.class) { @Override public String getColumnName() { return TabsValues.get().columnCurrentShip(); } @Override public Object getColumnValue(final Value from) { return from.getActiveShip(); } }, CURRENT_STATION(String.class) { @Override public String getColumnName() { return TabsValues.get().columnCurrentStation(); } @Override public Object getColumnValue(final Value from) { return from.getCurrentStation(); } }, CURRENT_SYSTEM(String.class) { @Override public String getColumnName() { return TabsValues.get().columnCurrentSystem(); } @Override public Object getColumnValue(final Value from) { return from.getCurrentSystem(); } }, CURRENT_CONSTELLATION(String.class) { @Override public String getColumnName() { return TabsValues.get().columnCurrentConstellation(); } @Override public Object getColumnValue(final Value from) { return from.getCurrentConstellation(); } }, CURRENT_REGION(String.class) { @Override public String getColumnName() { return TabsValues.get().columnCurrentRegion(); } @Override public Object getColumnValue(final Value from) { return from.getCurrentRegion(); } }; private final Class type; private final Comparator comparator; private ValueTableFormat(final Class type) { this.type = type; this.comparator = EnumTableColumn.getComparator(type); } @Override public Class getType() { return type; } @Override public Comparator getComparator() { return comparator; } @Override public String toString() { return getColumnName(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/gui/tabs/values/ValueTableTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.values; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import ca.odell.glazedlists.swing.TableComparatorChooser; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.filter.FilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuColumns; import net.nikr.eve.jeveasset.gui.shared.menu.MenuData; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JAutoColumnTable; import net.nikr.eve.jeveasset.gui.shared.table.PaddingTableCellRenderer; import net.nikr.eve.jeveasset.gui.shared.table.TableFormatFactory; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerSkillPointFilter; import net.nikr.eve.jeveasset.i18n.TabsValues; public class ValueTableTab extends JMainTabSecondary { //GUI private final JAutoColumnTable jTable; private final JButton jSkillPointsFilters; //Table private final ValueFilterControl filterControl; private final DefaultEventTableModel tableModel; private final EventList eventList; private final FilterList filterList; private final EnumTableFormatAdaptor tableFormat; private final DefaultEventSelectionModel selectionModel; public static final String NAME = "value"; //Not to be changed! private final IskData iskData; public ValueTableTab(final Program program) { super(program, NAME, TabsValues.get().title(), Images.TOOL_VALUE_TABLE.getIcon(), true); iskData = new IskData(program); JFixedToolBar jToolBar = new JFixedToolBar(); jSkillPointsFilters = new JButton(TabsValues.get().skillPointFilters(), Images.LOC_INCLUDE.getIcon()); jSkillPointsFilters.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { program.getTrackerTab(true).showSkillPointsFilter(); } }); jToolBar.addButton(jSkillPointsFilters); //Table Format tableFormat = TableFormatFactory.valueTableFormat(); //Backend eventList = EventListManager.create(); //Sorting (per column) eventList.getReadWriteLock().readLock().lock(); SortedList columnSortedList = new SortedList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Sorting Total eventList.getReadWriteLock().readLock().lock(); SortedList totalSortedList = new SortedList<>(columnSortedList, new TotalComparator()); eventList.getReadWriteLock().readLock().unlock(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(totalSortedList); eventList.getReadWriteLock().readLock().unlock(); //Table Model tableModel = EventModels.createTableModel(filterList, tableFormat); //Table jTable = new JValueTable(program, tableModel); jTable.setCellSelectionEnabled(true); jTable.setRowSelectionAllowed(true); jTable.setColumnSelectionAllowed(true); PaddingTableCellRenderer.install(jTable, 3); //Sorting TableComparatorChooser comparatorChooser = TableComparatorChooser.install(jTable, columnSortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE, tableFormat); //Selection Model selectionModel = EventModels.createSelectionModel(filterList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Table Filter filterControl = new ValueFilterControl(totalSortedList); //Menu installTableTool(new ValueTableMenu(), tableFormat, comparatorChooser, tableModel, jTable, filterControl, Value.class); layout.setHorizontalGroup( layout.createParallelGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, jToolBar.getMinimumSize().width, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(filterControl.getPanel()) .addComponent(jToolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void updateData() { boolean isAll = true; for (TrackerSkillPointFilter filter : Settings.get().getTrackerSettings().getSkillPointFilters().values()) { if (!filter.isEmpty()) { isAll = false; break; } } if (isAll) { jSkillPointsFilters.setIcon(Images.LOC_INCLUDE.getIcon()); } else { jSkillPointsFilters.setIcon(Images.EDIT_EDIT_WHITE.getIcon()); } //Update Data iskData.updateData(eventList); } @Override public void clearData() { try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); } finally { eventList.getReadWriteLock().writeLock().unlock(); } filterControl.clearCache(); } @Override public void updateCache() { filterControl.createCache(); } @Override public Collection getLocations() { try { eventList.getReadWriteLock().readLock().lock(); return new ArrayList<>(eventList); } finally { eventList.getReadWriteLock().readLock().unlock(); } } private class ValueTableMenu implements TableMenu { @Override public MenuData getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return filterControl.getMenu(jTable, selectionModel.getSelected()); } @Override public JMenu getColumnMenu() { return new JMenuColumns<>(program, tableFormat, tableModel, jTable, NAME); } @Override public void addInfoMenu(JPopupMenu jPopupMenu) { } @Override public void addToolMenu(JComponent jComponent) { } } private class ValueFilterControl extends FilterControl { public ValueFilterControl(EventList exportEventList) { super(program.getMainWindow().getFrame(), NAME, tableFormat, eventList, exportEventList, filterList ); } @Override public void saveSettings(final String msg) { program.saveSettings("ISK Table: " + msg); //Save ISK Filters and Export Settings } } public static class TotalComparator implements Comparator { @Override public int compare(final Value o1, final Value o2) { if (o1.isGrandTotal() && o2.isGrandTotal()) { return 0; //Equal (both StockpileTotal) } else if (o1.isGrandTotal()) { return 1; //After } else if (o2.isGrandTotal()) { return -1; //Before } else { return 0; //Equal (not StockpileTotal) } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/BundleServiceFactory.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.conf.DefaultBundleConfiguration; import uk.me.candle.translations.service.BasicBundleService; import uk.me.candle.translations.service.BundleService; public class BundleServiceFactory { private static BundleService bundleService; public static BundleService getBundleService() { //XXX - Workaround for default language if (bundleService == null) { bundleService = new BasicBundleService(new DefaultBundleConfiguration(), Locale.ENGLISH); } return bundleService; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/DataColors.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class DataColors extends Bundle { public static DataColors get() { return BundleServiceFactory.getBundleService().get(DataColors.class); } public DataColors(final Locale locale) { super(locale); } public abstract String assetsNew(); public abstract String assetsReprocessingEqual(); public abstract String assetsReprocessingReproces(); public abstract String assetsReprocessingSell(); public abstract String assetsReprocess(); public abstract String customPrice(); public abstract String customAssetName(); public abstract String customUserLocation(); public abstract String contractsCourier(); public abstract String contractsIncluded(); public abstract String contractsExcluded(); public abstract String extractionsDays(); public abstract String extractionsWeek(); public abstract String extractionsWeeks(); public abstract String overviewGroupedLocations(); public abstract String stockpileTableBelowThreshold(); public abstract String stockpileIconBelowThreshold(); public abstract String stockpileTableBelowThreshold2nd(); public abstract String stockpileIconBelowThreshold2nd(); public abstract String stockpileTableOverThreshold(); public abstract String stockpileIconOverThreshold(); public abstract String marketOrdersOutbidNotBest(); public abstract String marketOrdersOutbidNotBestOwned(); public abstract String marketOrdersOutbidBest(); public abstract String marketOrdersOutbidUnknown(); public abstract String marketOrdersExpired(); public abstract String marketOrdersNearExpired(); public abstract String marketOrdersNearFilled(); public abstract String marketOrdersNew(); public abstract String industryJobsDelivered(); public abstract String industryJobsDone(); public abstract String industryJobsManufacturing(); public abstract String industryJobsResearchingTechnology(); public abstract String industryJobsResearchingTimeProductivity(); public abstract String industryJobsResearchingMeterialProductivity(); public abstract String industryJobsCopying(); public abstract String industryJobsDuplicating(); public abstract String industryJobsReverseEngineering(); public abstract String industryJobsReverseInvention(); public abstract String industryJobsReactions(); public abstract String slotsFree(); public abstract String slotsDone(); public abstract String slotsFull(); public abstract String journalNew(); public abstract String transactionsBought(); public abstract String transactionsSold(); public abstract String transactionsNew(); public abstract String npcStandingNegative(); public abstract String npcStandingPositive(); public abstract String npcStandingNegativeMiddle(); public abstract String npcStandingPositiveMiddle(); public abstract String globalBPC(); public abstract String globalBPO(); public abstract String globalValueNegative(); public abstract String globalValuePositive(); public abstract String globalEntryInvalid(); public abstract String globalEntryWarning(); public abstract String globalEntryValid(); public abstract String globalGrandTotal(); public abstract String globalSelectedRowHighlighting(); public abstract String filterOrGroup1(); public abstract String filterOrGroup2(); public abstract String filterOrGroup3(); public abstract String filterOrGroup4(); public abstract String filterOrGroup5(); public abstract String filterOrGroup6(); public abstract String filterOrGroup7(); public abstract String reprocessedSell(); public abstract String reprocessedReprocess(); public abstract String reprocessedEqual(); public abstract String groupAssets(); public abstract String groupCustom(); public abstract String groupContracts(); public abstract String groupExtractions(); public abstract String groupOverview(); public abstract String groupMarketOrders(); public abstract String groupIndustryJobs(); public abstract String groupSlots(); public abstract String groupJournal(); public abstract String groupTransactions(); public abstract String groupNpcStanding(); public abstract String groupGlobal(); public abstract String groupFilters(); public abstract String groupReprocessed(); public abstract String groupStockpile(); public abstract String colorThemeDark(); public abstract String colorThemeDefault(); public abstract String colorThemeStrong(); public abstract String colorThemeColorblind(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/DataModelAsset.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; /** * * @author Candle */ public abstract class DataModelAsset extends Bundle { public static DataModelAsset get() { return BundleServiceFactory.getBundleService().get(DataModelAsset.class); } public DataModelAsset(final Locale locale) { super(locale); } public abstract String unpackaged(); public abstract String packaged(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/DataModelIndustryJob.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; /** * * @author Candle */ public abstract class DataModelIndustryJob extends Bundle { public static DataModelIndustryJob get() { return BundleServiceFactory.getBundleService().get(DataModelIndustryJob.class); } public DataModelIndustryJob(final Locale locale) { super(locale); } public abstract String statusPaused(); public abstract String statusActive(); public abstract String statusDone(); public abstract String statusReverted(); public abstract String statusCancelled(); public abstract String statusDelivered(); public abstract String statusArchived(); public abstract String statusUnknown(); public abstract String activityAll(); public abstract String activityNone(); public abstract String activityManufacturing(); public abstract String activityResearchingTechnology(); public abstract String activityResearchingTimeProductivity(); public abstract String activityResearchingMeterialProductivity(); public abstract String activityCopying(); public abstract String activityDuplicating(); public abstract String activityReverseEngineering(); public abstract String activityReverseInvention(); public abstract String activityReactions(); public abstract String activityUnknown(); public abstract String descriptionCopying(String blueprintName, int copyCount, int copyRuns); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/DataModelPriceDataSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; /** * * @author Candle */ public abstract class DataModelPriceDataSettings extends Bundle { public static DataModelPriceDataSettings get() { return BundleServiceFactory.getBundleService().get(DataModelPriceDataSettings.class); } public DataModelPriceDataSettings(final Locale locale) { super(locale); } public abstract String sourceFuzzwork(); public abstract String sourceEveTycoon(); public abstract String sourceJanice(); public abstract String priceSellMax(); public abstract String priceSellAvg(); public abstract String priceSellMedian(); public abstract String priceSellMin(); public abstract String priceSellPercentile(); public abstract String priceMidpoint(); public abstract String priceBuyMax(); public abstract String priceBuyAvg(); public abstract String priceBuyMedian(); public abstract String priceBuyPercentile(); public abstract String priceBuyMin(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/DialoguesAbout.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; /** * * @author Andrew */ public abstract class DialoguesAbout extends Bundle { public static DialoguesAbout get() { return BundleServiceFactory.getBundleService().get(DialoguesAbout.class); } public DialoguesAbout(final Locale locale) { super(locale); } public abstract String about(); public abstract String close(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/DialoguesAccount.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; /** * * @author Candle */ public abstract class DialoguesAccount extends Bundle { public static DialoguesAccount get() { return BundleServiceFactory.getBundleService().get(DialoguesAccount.class); } public DialoguesAccount(final Locale locale) { super(locale); } public abstract String dialogueNameAccountExport(); public abstract String dialogueNameAccountImport(); public abstract String previousArrow(); public abstract String nextArrow(); public abstract String cancel(); public abstract String ok(); public abstract String failApiError(); public abstract String failApiErrorText(String s); public abstract String failNotEnoughPrivileges(); public abstract String failNotEnoughPrivilegesText(); public abstract String failNotValid(); public abstract String failNotValidText(); public abstract String failWrongEntry(); public abstract String failWrongEntryText(); public abstract String okUpdate(); public abstract String okUpdateLimitedText(); public abstract String okUpdateText(); public abstract String okLimited(); public abstract String okLimitedExportText(); public abstract String okLimitedText(); public abstract String okValid(); public abstract String okValidText(); public abstract String authCode(); public abstract String authorize(); public abstract String accountType(); public abstract String accessKey(); public abstract String esiHelpText(); public abstract String authCodeHelpText(); public abstract String browseHelpText(); public abstract String validatingMessage(); public abstract String scopes(); public abstract String corporation(); public abstract String character(); public abstract String workaroundLabel(); public abstract String workaroundCheckbox(); public abstract String scopeAssets(); public abstract String scopeClones(); public abstract String scopeImplants(); public abstract String scopeWallet(); public abstract String scopeBlueprints(); public abstract String scopeIndustryJobs(); public abstract String scopeMarketOrders(); public abstract String scopeMarketStructures(); public abstract String scopeContracts(); public abstract String scopeRoles(); public abstract String scopeStructures(); public abstract String scopeShipType(); public abstract String scopeShipLocation(); public abstract String scopeOpenWindows(); public abstract String scopePlanetaryInteraction(); public abstract String scopeAutopilot(); public abstract String scopeDivisions(); public abstract String scopeSkills(); public abstract String scopeMining(); public abstract String scopeLoyaltyPoints(); public abstract String scopeNpcStanding(); public abstract String dialogueNameAccountManagement(); public abstract String accountExpired(); public abstract String accountInvalid(); public abstract String add(); public abstract String revalidate(); public abstract String revalidateMsgAll(int total); public abstract String revalidateMsgNone(int total); public abstract String revalidateMsgSome(int total, int done, int failed); public abstract String collapse(); public abstract String expand(); public abstract String showAssets(); public abstract String checkAll(); public abstract String uncheckAll(); public abstract String checkSelected(); public abstract String uncheckSelected(); public abstract String share(); public abstract String shareExport(); public abstract String shareExportClipboard(); public abstract String shareExportFail(); public abstract String shareExportFile(); public abstract String shareExportHelp(); public abstract String shareImport(); public abstract String shareImportClipboard(); public abstract String shareImportFile(); public abstract String shareImportHelpText(); public abstract String close(); public abstract String noOwners(); public abstract String deleteAccountQuestion(); public abstract String deleteAccount(); public abstract String delete(); public abstract String edit(); public abstract String tableFormatName(); public abstract String tableFormatClones(); public abstract String tableFormatImplants(); public abstract String tableFormatCorporation(); public abstract String tableFormatAssetList(); public abstract String tableFormatAccountBalance(); public abstract String tableFormatIndustryJobs(); public abstract String tableFormatMarketOrders(); public abstract String tableFormatJournal(); public abstract String tableFormatTransactions(); public abstract String tableFormatContracts(); public abstract String tableFormatLocations(); public abstract String tableFormatStructures(); public abstract String tableFormatMarketStructures(); public abstract String tableFormatBlueprints(); public abstract String tableFormatDivisions(); public abstract String tableFormatShip(); public abstract String tableFormatPlanetaryInteraction(); public abstract String tableFormatOpenWindows(); public abstract String tableFormatAutopilot(); public abstract String tableFormatSkills(); public abstract String tableFormatLoyaltyPoints(); public abstract String tableFormatNpcStanding(); public abstract String tableFormatMining(); public abstract String tableFormatYes(); public abstract String tableFormatNo(); public abstract String tableFormatExpires(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/DialoguesExport.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; /** * * @author Candle */ public abstract class DialoguesExport extends Bundle { public static DialoguesExport get() { return BundleServiceFactory.getBundleService().get(DialoguesExport.class); } public DialoguesExport(final Locale locale) { super(locale); } public abstract String cancel(); public abstract String columns(); public abstract String comma(); public abstract String createTable(); public abstract String csv(); public abstract String currentFilter(); public abstract String decimalSeparator(); public abstract String defaultSettings(); public abstract String dot(); public abstract String dropTable(); public abstract String export(); public abstract String extendedInserts(); public abstract String failedToSave(); public abstract String filters(); public abstract String format(); public abstract String html(); public abstract String htmlHeaderRepeat(); public abstract String htmlIGB(); public abstract String htmlStyled(); public abstract String lineEndingsMac(); public abstract String lineEndingsUnix(); public abstract String lineEndingsWindows(); public abstract String linesTerminated(); public abstract String noColumnsSelected(); public abstract String noFilter(); public abstract String noSavedFilter(); public abstract String ok(); public abstract String savedFilter(); public abstract String semicolon(); public abstract String sql(); public abstract String tableName(); public abstract String viewCurrent(); public abstract String viewNoSaved(); public abstract String viewSaved(); public abstract String viewSelect(); public abstract String viewSelectAll(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/DialoguesProfiles.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; /** * * @author Andrew */ public abstract class DialoguesProfiles extends Bundle { public static DialoguesProfiles get() { return BundleServiceFactory.getBundleService().get(DialoguesProfiles.class); } public DialoguesProfiles(final Locale locale) { super(locale); } public abstract String ok(); public abstract String cancel(); public abstract String profiles(); public abstract String load(); public abstract String newP(); public abstract String rename(); public abstract String delete(); public abstract String defaultP(); public abstract String close(); public abstract String loadProfile(); public abstract String loadingProfile(); public abstract String profileLoaded(); public abstract String newProfile(); public abstract String typeName(); public abstract String nameAlreadyExists(); public abstract String creatingProfile(); public abstract String renameProfile(); public abstract String enterNewName(); public abstract String cannotDeleteActive(); public abstract String cannotDeleteDefault(); public abstract String deleteProfileConfirm(String name); public abstract String deleteProfile(); public abstract String clearFilter(); public abstract String profileLoadedMsg(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/DialoguesSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; /** * * @author Candle */ public abstract class DialoguesSettings extends Bundle { public static DialoguesSettings get() { return BundleServiceFactory.getBundleService().get(DialoguesSettings.class); } public DialoguesSettings(final Locale locale) { super(locale); } // used in GeneralSettingsPanel public abstract String general(); public abstract String loadToolsBackground(); public abstract String loadToolsOpen(); public abstract String loadToolsStartup(); public abstract String enterFilter(); public abstract String highlightSelectedRow(); public abstract String focusEveOnline(); public abstract String focusEveOnlineLinuxCmd(); public abstract String focusEveOnlineLinuxHelp(); public abstract String focusEveOnlineLinuxHelp2(); public abstract String copyDecimalSeparator(); public abstract String transactionsMargin(); public abstract String transactionsPrice(); public abstract String transactionsPriceAverage(); public abstract String transactionsPriceLatest(); public abstract String transactionsPriceMaximum(); public abstract String transactionsPriceMinimum(); public abstract String transactionsProfit(); public abstract String includeDays(); public abstract String days(); // used in ShowToolSettingsPanel public abstract String show(); public abstract String saveTools(); public abstract String selectTools(); public abstract String toolsOrderHelp(); // used in AssetsToolSettingsPanel public abstract String assets(); public abstract String includeSellContracts(); public abstract String includeSellOrders(); public abstract String includeBuyContracts(); public abstract String includeBuyOrders(); public abstract String includeManufacturing(); public abstract String includeCopying(); public abstract String includeJumpClones(); public abstract String includePluggedInImplants(); public abstract String showContainerItemID(); public abstract String contractAssetsBoth(); public abstract String contractAssetsCharacter(); public abstract String contractAssetsCorporation(); public abstract String contractAssetsLabel(); public abstract String contractAssetsLabelWarn(); // used in OverviewToolSettingsPanel public abstract String overview(); public abstract String ignoreContainers(); // used in StockpileToolSettingsPanel public abstract String stockpile(); public abstract String stockpileColors(); public abstract String stockpileSwitchTab(); public abstract String stockpileTwoGroups(); public abstract String stockpileThreeGroups(); public abstract String percentPlusSymbol(); public abstract String saveHistoryWarning(); //Transactions & Journal & Market Orders // used in MarketOrdersToolSettingsPanel public abstract String marketOrders(); public abstract String marketOrdersSaveHistory(); public abstract String expireWarnDays(); public abstract String remainingWarnPercent(); // used in TransactionsToolSettingsPanel public abstract String transactions(); public abstract String transactionsSaveHistory(); // used in TransactionsToolSettingsPanel public abstract String journal(); public abstract String journalSaveHistory(); // used in IndustryJobsToolSettingsPanel public abstract String industryJobs(); public abstract String industryJobsSaveHistory(); // used in ContractToolSettingsPanel public abstract String contracts(); public abstract String contractsSaveHistory(); // used in TrackerToolSettingsPanel public abstract String tracker(); public abstract String useAssetPriceForSellOrders(); // used in PriceHistoryToolSettingsPanel public abstract String priceHistory(); public abstract String clearBlacklist(); public abstract String clearBlacklistMsg(); public abstract String clearBlacklistTitle(); // used in MiningToolSettingsPanel public abstract String mining(); public abstract String miningSaveHistory(); // used in JumpsSettingsPanel public abstract String jumps(); public abstract String eveGatecampCheck(); public abstract String eveGatecampCheckOpenOptions(); public abstract String eveGatecampCheckRouteOptions(); // used in ColorSettingsPanel public abstract String chartColors(); public abstract String colors(); public abstract String collapse(); public abstract String expand(); public abstract String columnName(); public abstract String columnBackground(); public abstract String columnForeground(); public abstract String columnPreview(); public abstract String columnSelected(); public abstract String testText(); public abstract String testSelectedText(); public abstract String overwriteMsg(); public abstract String overwriteTitle(); public abstract String theme(); public abstract String lookAndFeel(); public abstract String lookAndFeelDefault(); public abstract String lookAndFeelDefaultName(String name); public abstract String lookAndFeelFlatLight(); public abstract String lookAndFeelFlatDark(); public abstract String lookAndFeelFlatIntelliJ(); public abstract String lookAndFeelFlatDarcula(); public abstract String lookAndFeelNimbusDark(); public abstract String lookAndFeelMsg(); public abstract String lookAndFeelTitle(); //used in SoundSettingsPanel public abstract String sounds(); public abstract String soundsBeep(); public abstract String soundsEveArmor(); public abstract String soundsEveCapacitor(); public abstract String soundsEveCargo(); public abstract String soundsEveCharacterSelection(); public abstract String soundsEveLogin(); public abstract String soundsEveNotificationPing(); public abstract String soundsEveShield(); public abstract String soundsEveSkill(); public abstract String soundsEveStart(); public abstract String soundsEveStructure(); public abstract String soundsIndustryJobCompleted(); public abstract String soundsMp3Add(); public abstract String soundsMp3DeleteMsg(String id); public abstract String soundsMp3DeleteTitle(); public abstract String soundsMp3ImportCopy(); public abstract String soundsMp3ImportExist(); public abstract String soundsMp3ImportTitle(); public abstract String soundsMp3NoFilesAdded(); public abstract String soundsNone(); public abstract String soundsOutbidUpdateCompleted(); public abstract String soundsOutbidUpdateAvailable(); // used in PriceDataSettingsPanel public abstract String changeSourceWarning(); public abstract String includeRegions(); public abstract String includeStations(); public abstract String includeSystems(); public abstract String notConfigurable(); public abstract String price(); public abstract String priceBase(); public abstract String priceData(); public abstract String priceReprocessed(); public abstract String priceManufacturing(); public abstract String priceTech1(); public abstract String priceTech2(); public abstract String manufacturingDefault(); public abstract String source(); public abstract String janiceApiKey(); public abstract String janiceApiKeyMsg(); public abstract String janiceApiKeyTitle(); // used in ProxySettingsPanel public abstract String proxy(); public abstract String type(); public abstract String address(); public abstract String port(); public abstract String auth(); public abstract String username(); public abstract String password(); // used in ReprocessingSettingsPanel public abstract String reprocessing(); public abstract String reprocessingWarning(); public abstract String stationEquipment(); public abstract String fiftyPercent(); public abstract String percentSymbol(); public abstract String reprocessingLevel(); public abstract String reprocessingEfficiencyLevel(); public abstract String oreProcessingLevel(); public abstract String scrapmetalProcessingLevel(); public abstract String zero(); public abstract String one(); public abstract String two(); public abstract String three(); public abstract String four(); public abstract String five(); // used in ManufacturingSettingsPanel public abstract String manufacturing(); public abstract String manufacturingFacility(); public abstract String manufacturingFacilityStation(); public abstract String manufacturingFacilityMedium(); public abstract String manufacturingFacilityLarge(); public abstract String manufacturingFacilityXLarge(); public abstract String manufacturingME(); public abstract String manufacturingPercent(); public abstract String manufacturingRigs(); public abstract String manufacturingRigsNone(); public abstract String manufacturingRigsT1(); public abstract String manufacturingRigsT2(); public abstract String manufacturingSecurity(); public abstract String manufacturingSecurityHighSec(); public abstract String manufacturingSecurityLowSec(); public abstract String manufacturingSecurityNullSec(); public abstract String manufacturingSystems(); public abstract String manufacturingSystemsWarning(); public abstract String manufacturingTax(); // used in SettingsDialog public abstract String settings(String programName); public abstract String root(); public abstract String ok(); public abstract String apply(); public abstract String cancel(); public abstract String tools(); public abstract String values(); // used in UserItemNameSettingsPanel public abstract String names(); public abstract String name(); public abstract String namesInstruction(); // used in JUserListPanel public abstract String badInput(); public abstract String deleteItem(); public abstract String deleteTypeTitle(String type); public abstract String editItem(); public abstract String editTypeTitle(String type); public abstract String inputNotValid(); public abstract String itemEmpty(); public abstract String items(int size); // used in UserPriceSettingsPanel public abstract String pricePrices(); public abstract String pricePrice(); public abstract String priceInstructions(); // used in UserLocationSettingsPanel public abstract String locationsInstructions(); // used in WindowSettingsPanel public abstract String windowWindow(); public abstract String windowSaveOnExit(); public abstract String windowAlwaysOnTop(); public abstract String windowFixed(); public abstract String windowWidth(); public abstract String windowHeight(); public abstract String windowX(); public abstract String windowY(); public abstract String windowMaximised(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/DialoguesStructure.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class DialoguesStructure extends Bundle { public static DialoguesStructure get() { return BundleServiceFactory.getBundleService().get(DialoguesStructure.class); } public DialoguesStructure(final Locale locale) { super(locale); } public abstract String eta(String time); public abstract String invalid(); public abstract String locationsAll(); public abstract String locationsItem(); public abstract String locationsSelected(); public abstract String locationsTracker(); public abstract String nextUpdate(String updatableIn); public abstract String ownersAll(); public abstract String ownersSingle(); public abstract String title(); public abstract String updateTitle(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/DialoguesUpdate.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; /** * * @author Andrew */ public abstract class DialoguesUpdate extends Bundle { public static DialoguesUpdate get() { return BundleServiceFactory.getBundleService().get(DialoguesUpdate.class); } public DialoguesUpdate(final Locale locale) { super(locale); } public abstract String updating(); public abstract String ok(); public abstract String cancel(); public abstract String cancelQuestion(); public abstract String cancelQuestionTitle(); public abstract String minimize(); // used in UpdateDialog public abstract String firstAccount(); public abstract String allAccounts(); public abstract String update(); public abstract String contracts(); public abstract String marketOrders(); public abstract String industryJobs(); public abstract String accounts(); public abstract String accountBalance(); public abstract String assets(); public abstract String priceData(); public abstract String priceDataNew(); public abstract String priceDataNone(); public abstract String nextUpdate(); public abstract String noAccounts(); public abstract String now(); public abstract String balance(); public abstract String journal(); public abstract String transactions(); public abstract String names(); public abstract String blueprints(); public abstract String skills(); public abstract String loyaltyPoints(); public abstract String npcStanding(); public abstract String mining(); public abstract String structures(); public abstract String publicMarketOrders(); public abstract String step1(); public abstract String step2(); public abstract String step3(); public abstract String step4(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/General.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; /** * * @author Candle */ public abstract class General extends Bundle { public static General get() { return BundleServiceFactory.getBundleService().get(General.class); } public General(final Locale locale) { super(locale); } public abstract String uncaughtErrorMessage(); public abstract String error(); public abstract String contractIncluded(); public abstract String contractExcluded(); public abstract String industryJobFlag(); public abstract String marketOrderSellFlag(); public abstract String marketOrderBuyFlag(); public abstract String jumpClone(); public abstract String activeClone(); public abstract String none(); public abstract String all(); public abstract String fileLockTitle(); public abstract String fileLockMsg(String s); public abstract String singleInstanceTitle(); public abstract String singleInstanceMsg(); public abstract String emptyLocation(String locationID); public abstract String assetSafety(); public abstract String journalContract(); public abstract String journalIndustryJob(); public abstract String journalMarketTransaction(); public abstract String journalSystemTransaction(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/GuiFrame.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class GuiFrame extends Bundle { public static GuiFrame get() { return BundleServiceFactory.getBundleService().get(GuiFrame.class); } public GuiFrame(final Locale locale) { super(locale); } public abstract String about(); public abstract String accounts(); public abstract String agents(); public abstract String business(); public abstract String change(); public abstract String clickToShow(String text); public abstract String clickToApply(String text); public abstract String close(); public abstract String contracts(); public abstract String credits(); public abstract String eve(); public abstract String exit(); public abstract String exitMsg(int size); public abstract String exitTitle(int size); public abstract String extractions(); public abstract String file(); public abstract String help(); public abstract String inventory(); public abstract String items(); public abstract String industry(); public abstract String journal(); public abstract String license(); public abstract String linkDiscord(); public abstract String linkFeedbackAndHelp(); public abstract String linkWiki(); public abstract String lock(); public abstract String loyaltyPoints(); public abstract String market(); public abstract String materials(); public abstract String mining(); public abstract String miningAll(); public abstract String miningLog(); public abstract String miningGraph(); public abstract String misc(); public abstract String netWorth(); public abstract String not(); public abstract String npcStanding(); public abstract String options(); public abstract String options1(); public abstract String overview(); public abstract String owners(); public abstract String priceChanges(); public abstract String priceHistory(); public abstract String profiles(); public abstract String programUpdateText(); public abstract String programUpdateTip(); public abstract String readme(); public abstract String reprocessed(); public abstract String routing(); public abstract String ship(); public abstract String skills(); public abstract String skillsOverview(); public abstract String slots(); public abstract String stockpile(); public abstract String table(); public abstract String tools(); public abstract String tracker(); public abstract String transaction(); public abstract String tree(); public abstract String updatable(); public abstract String update(); public abstract String update1(); public abstract String updateStructure(); public abstract String updatingInProgressMsg(); public abstract String updatingInProgressTitle(); public abstract String values(); public abstract String valueTable(); public abstract String windowTitle(String programName, String programVersion, int portable, int profileCount, String activeProfileName); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/GuiShared.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class GuiShared extends Bundle { public static GuiShared get() { return BundleServiceFactory.getBundleService().get(GuiShared.class); } public GuiShared(final Locale locale) { super(locale); } public abstract String agentDivisionResearchAndDevelopment(); public abstract String agentDivisionDistribution(); public abstract String agentDivisionMining(); public abstract String agentDivisionSecurity(); public abstract String agentDivisionIndustrialistEntrepreneur(); public abstract String agentDivisionExplorer(); public abstract String agentDivisionIndustrialistProducer(); public abstract String agentDivisionEnforcer(); public abstract String agentDivisionSoldierOfFortune(); public abstract String agentDivisionInterBus(); public abstract String agentTypeNonAgent(); public abstract String agentTypeBasicAgent(); public abstract String agentTypeTutorialAgent(); public abstract String agentTypeResearchAgent(); public abstract String agentTypeConcordAgent(); public abstract String agentTypeGenericStorylineMissionAgent(); public abstract String agentTypeStorylineMissionAgent(); public abstract String agentTypeEventMissionAgent(); public abstract String agentTypeFactionalWarfareAgent(); public abstract String agentTypeEpicArcAgent(); public abstract String agentTypeAuraAgent(); public abstract String agentTypeCareerAgent(); public abstract String adam4eve(); public abstract String add(); public abstract String addFilter(); public abstract String addTransactionFilter(); public abstract String all(); public abstract String background(); public abstract String cellAverage(); public abstract String cellAverageToolTip(); public abstract String cellInformation(); public abstract String cellInformationToolTip(); public abstract String cellInformationColumn(); public abstract String cellInformationColumnToolTip(); public abstract String cellCount(); public abstract String cellCountToolTip(); public abstract String cellMaximum(); public abstract String cellMaximumToolTip(); public abstract String cellMinimum(); public abstract String cellMinimumToolTip(); public abstract String cellSum(); public abstract String cellSumToolTip(); public abstract String checkAll(); public abstract String chruker(); public abstract String clickToCopyGroup(); public abstract String clickToCopySelectionInfo(); public abstract String clickToCopyWrap(String toolTip); public abstract String constellation(); public abstract String containerDelete(); public abstract String containerEdit(); public abstract String containerText(); public abstract String contractCorporationOwner(String corporation, String character); public abstract String copy(); public abstract String copyEveMultiBuy(); public abstract String copyPlus(); public abstract String corporation(); public abstract String custom(); public abstract String cut(); public abstract String delete(); public abstract String dotlan(); public abstract String durationDone(); public abstract String durationNever(); public abstract String edit(); public abstract String emptyString(); public abstract String errorLoadingSettingsMsg(); public abstract String errorLoadingSettingsTitle(); public abstract String errorLoadingProfileMsg(); public abstract String errorLoadingProfileTitle(); public abstract String eveCookbook(); public abstract String eveInfo(); public abstract String eveMarketBrowser(); public abstract String eveMissioneer(); public abstract String eveRef(); public abstract String eveTycoon(); public abstract String eveconomy(); public abstract String foreground(); public abstract String formulaColumns(); public abstract String formulaDateToolTip(); public abstract String formulaFunctions(); public abstract String formulaMenu(); public abstract String formulaName(); public abstract String formulaOperations(); public abstract String formulaString(); public abstract String formulaTitle(); public abstract String fuzzworkBlueprints(); public abstract String fuzzworkItems(); public abstract String fuzzworkLP(); public abstract String fuzzworkLPBuy(); public abstract String fuzzworkLPSell(); public abstract String fuzzworkMarket(); public abstract String helpFilter(); public abstract String helpSettings(); public abstract String helpStockpile(); public abstract String helpOpenManual(String title); public abstract String helpOpenManualTitle(); public abstract String importEft(); public abstract String importEveMultibuy(); public abstract String importIskPerHour(); public abstract String importOptions(); public abstract String importOptionsMerge(); public abstract String importOptionsOverwrite(); public abstract String importOptionsRename(); public abstract String importOptionsSkip(); public abstract String importStockpilesShoppingList(); public abstract String industry(); public abstract String invalidMsg(); public abstract String invalidTitle(); public abstract String item(); public abstract String itemDatabase(); public abstract String itemDelete(); public abstract String itemEdit(); public abstract String itemNameTitle(); public abstract String itemPriceTitle(); public abstract String jitaSpace(); public abstract String jumps(); public abstract String jumpsAddCustom(); public abstract String jumpsAddSelected(); public abstract String jumpsClear(); public abstract String jumpsColumnToolTip(String systemName); public abstract String jumpsSettings(); public abstract String loadout(); public abstract String loadoutOpen(); public abstract String loadoutSelectShip(); public abstract String location(); public abstract String locationClear(); public abstract String locationClearConfirm(String location); public abstract String locationClearConfirmAll(int size); public abstract String locationEmpty(); public abstract String locationID(); public abstract String locationName(); public abstract String locationRename(); public abstract String locationSystem(); public abstract String lookup(); public abstract String loyaltyPointsStore(); public abstract String market(); public abstract String newStockpile(); public abstract String none(); public abstract String ok(); public abstract String openLinks(int size); public abstract String openLinksTitle(); public abstract String overwrite(); public abstract String overwriteTitle(); public abstract String overwriteFile(); public abstract String paste(); public abstract String planet(); public abstract String priceHistory(); public abstract String quantumAnomaly(); public abstract String region(); public abstract String reprocessed(); public abstract String routing(); public abstract String selectionAverage(); public abstract String selectionContractsBought(); public abstract String selectionContractsBoughtToolTip(); public abstract String selectionContractsBuying(); public abstract String selectionContractsBuyingToolTip(); public abstract String selectionContractsCollateralAcceptor(); public abstract String selectionContractsCollateralAcceptorToolTip(); public abstract String selectionContractsCollateralIssuer(); public abstract String selectionContractsCollateralIssuerToolTip(); public abstract String selectionContractsSellingAssets(); public abstract String selectionContractsSellingAssetsToolTip(); public abstract String selectionContractsSellingPrice(); public abstract String selectionContractsSellingPriceToolTip(); public abstract String selectionContractsSold(); public abstract String selectionContractsSoldToolTip(); public abstract String selectionCount(); public abstract String selectionInventionSuccess(); public abstract String selectionManufactureJobsValue(); public abstract String selectionOrdersCount(); public abstract String selectionOrdersCountValue(String volumeRemain, String volumeTotal); public abstract String selectionOrdersSellTotal(); public abstract String selectionOrdersBuyTotal(); public abstract String selectionOrdersBuyEscrow(); public abstract String selectionOrdersBuyToCover(); public abstract String selectionOrdersBrokersFee(); public abstract String selectionTransactionsSellCount(); public abstract String selectionTransactionsSellTotal(); public abstract String selectionTransactionsSellAvg(); public abstract String selectionTransactionsSellTax(); public abstract String selectionTransactionsBothCount(); public abstract String selectionTransactionsBothTotal(); public abstract String selectionTransactionsBothAvg(); public abstract String selectionTransactionsBuyCount(); public abstract String selectionTransactionsBuyAvg(); public abstract String selectionTransactionsBuyTotal(); public abstract String selectionCopiedToClipboard(); public abstract String selectionTitle(); public abstract String selectionTitleBoth(); public abstract String selectionTitleBuy(); public abstract String selectionTitleCollateral(); public abstract String selectionTitleNeeded(); public abstract String selectionTitleNow(); public abstract String selectionTitleSell(); public abstract String selectionValue(); public abstract String selectionValueNeeded(); public abstract String selectionValueNow(); public abstract String selectionValueReprocessed(); public abstract String selectionVolume(); public abstract String selectionVolumeNeeded(); public abstract String selectionVolumeNow(); public abstract String selectionShortAverage(); public abstract String selectionShortBrokerFees(); public abstract String selectionShortBuy(); public abstract String selectionShortCount(); public abstract String selectionShortEscrow(); public abstract String selectionShortGroup(String text); public abstract String selectionShortInventionSuccess(); public abstract String selectionShortIskToCover(); public abstract String selectionShortOutputValue(); public abstract String selectionShortReprocessedValue(); public abstract String selectionShortSell(); public abstract String selectionShortTax(); public abstract String selectionShortValue(); public abstract String selectionShortVolume(); public abstract String selectionSlotsContractCharacter(); public abstract String selectionSlotsContractCharacterFree(); public abstract String selectionSlotsContractCharacterActive(); public abstract String selectionSlotsContractCharacterMax(); public abstract String selectionSlotsContractCharacterFreeToolTip(); public abstract String selectionSlotsContractCharacterActiveToolTip(); public abstract String selectionSlotsContractCharacterMaxToolTip(); public abstract String selectionSlotsContractCorporation(); public abstract String selectionSlotsContractCorporationFree(); public abstract String selectionSlotsContractCorporationActive(); public abstract String selectionSlotsContractCorporationMax(); public abstract String selectionSlotsContractCorporationFreeToolTip(); public abstract String selectionSlotsContractCorporationActiveToolTip(); public abstract String selectionSlotsContractCorporationMaxToolTip(); public abstract String selectionSlotsManufacturing(); public abstract String selectionSlotsManufacturingDone(); public abstract String selectionSlotsManufacturingFree(); public abstract String selectionSlotsManufacturingActive(); public abstract String selectionSlotsManufacturingMax(); public abstract String selectionSlotsManufacturingDoneToolTip(); public abstract String selectionSlotsManufacturingFreeToolTip(); public abstract String selectionSlotsManufacturingActiveToolTip(); public abstract String selectionSlotsManufacturingMaxToolTip(); public abstract String selectionSlotsMarketOrders(); public abstract String selectionSlotsMarketOrdersFree(); public abstract String selectionSlotsMarketOrdersActive(); public abstract String selectionSlotsMarketOrdersMax(); public abstract String selectionSlotsMarketOrdersFreeToolTip(); public abstract String selectionSlotsMarketOrdersActiveToolTip(); public abstract String selectionSlotsMarketOrdersMaxToolTip(); public abstract String selectionSlotsReactions(); public abstract String selectionSlotsReactionsDone(); public abstract String selectionSlotsReactionsFree(); public abstract String selectionSlotsReactionsActive(); public abstract String selectionSlotsReactionsMax(); public abstract String selectionSlotsReactionsDoneToolTip(); public abstract String selectionSlotsReactionsFreeToolTip(); public abstract String selectionSlotsReactionsActiveToolTip(); public abstract String selectionSlotsReactionsMaxToolTip(); public abstract String selectionSlotsResearch(); public abstract String selectionSlotsResearchDone(); public abstract String selectionSlotsResearchFree(); public abstract String selectionSlotsResearchActive(); public abstract String selectionSlotsResearchMax(); public abstract String selectionSlotsResearchDoneToolTip(); public abstract String selectionSlotsResearchFreeToolTip(); public abstract String selectionSlotsResearchActiveToolTip(); public abstract String selectionSlotsResearchMaxToolTip(); public abstract String set(); public abstract String station(); public abstract String stockpile(); public abstract String system(); public abstract String systemRegion(); public abstract String tableColumns(); public abstract String tableColumnsReset(); public abstract String tableColumnsTip(); public abstract String tableColumnsTitle(); public abstract String tableResizeText(); public abstract String tableResizeWindow(); public abstract String tableResizeNone(); public abstract String tableSettings(); public abstract String tags(); public abstract String tagsEditTitle(); public abstract String tagsName(String name, Integer count); public abstract String tagsNew(); public abstract String tagsNewMsg(); public abstract String tagsNewTitle(); public abstract String toolsUpdateTitle(); public abstract String ui(); public abstract String uiWaypoint(); public abstract String uiWaypointBeginning(); public abstract String uiWaypointClear(); public abstract String uiWaypointEveGatecampCheck(); public abstract String uiWaypointEveGatecampCheckAsk(); public abstract String uiWaypointEveGatecampCheckAlwaysOpen(); public abstract String uiWaypointEveGatecampCheckDefault(); public abstract String uiWaypointEveGatecampCheckNeverOpen(); public abstract String uiWaypointEveGatecampCheckUnsecure(); public abstract String uiWaypointEveGatecampCheckOptions(); public abstract String uiWaypointEveGatecampCheckSecure(); public abstract String uiWaypointEveGatecampCheckShortest(); public abstract String uiWaypointFail(); public abstract String uiWaypointOk(); public abstract String uiWaypointTitle(); public abstract String uiCharacterInvalidMsg(); public abstract String uiCharacterMsg(); public abstract String uiCharacterTitle(); public abstract String uiContract(); public abstract String uiContractFail(); public abstract String uiContractOk(); public abstract String uiContractTitle(); public abstract String uiLocationTitle(); public abstract String uiMarket(); public abstract String uiMarketFail(); public abstract String uiMarketOk(); public abstract String uiMarketTitle(); public abstract String uiOwner(); public abstract String uiOwnerFail(); public abstract String uiOwnerMsg(); public abstract String uiOwnerOk(); public abstract String uiOwnerTitle(); public abstract String uiStation(); public abstract String uiSystem(); public abstract String unknownFaction(); public abstract String unknownOwner(); public abstract String updateStructures(); public abstract String updating(); public abstract String zKillboard(); public abstract String today(Object arg0); public abstract String files(Object arg0); public abstract String deleteView(); public abstract String deleteViews(int size); public abstract String editViews(); public abstract String enterViewName(); public abstract String loadView(); public abstract String manageViews(); public abstract String overwriteView(); public abstract String renameView(); public abstract String saveView(); public abstract String saveViewMsg(); //Filters public abstract String saveFilter(); public abstract String saveFilterToolTip(); public abstract String enterFilterName(); public abstract String save(); public abstract String cancel(); public abstract String noFilterName(); public abstract String overwriteDefaultFilter(); public abstract String overwriteFilter(); public abstract String addField(); public abstract String addFieldToolTip(); public abstract String clearField(); public abstract String clearFieldToolTip(); public abstract String loadFilter(); public abstract String loadFilterToolTip(); public abstract String showFilters(); public abstract String showFiltersToolTip(); public abstract String manageFilters(); public abstract String nothingToSave(); public abstract String filterManager(); public abstract String managerExport(); public abstract String managerImport(); public abstract String managerImportFailMsg(); public abstract String managerImportFailTitle(); public abstract String managerLoad(); public abstract String managerRename(); public abstract String managerDelete(); public abstract String managerEdit(); public abstract String managerCopy(); public abstract String managerClose(); public abstract String renameFilter(); public abstract String deleteFilter(); public abstract String deleteFilters(int size); public abstract String mergeFilters(); public abstract String managerMerge(); public abstract String filterAll(); public abstract String filterAnd(); public abstract String filterOr(); public abstract String filterContains(); public abstract String filterContainsNot(); public abstract String filterEquals(); public abstract String filterEqualsNot(); public abstract String filterRegex(); public abstract String filterGreaterThan(); public abstract String filterLastDays(); public abstract String filterNextDays(); public abstract String filterLastHours(); public abstract String filterNextHours(); public abstract String filterLessThan(); public abstract String filterBefore(); public abstract String filterAfter(); public abstract String filterEqualsDate(); public abstract String filterEqualsNotDate(); public abstract String filterContainsColumn(); public abstract String filterContainsNotColumn(); public abstract String filterEqualsColumn(); public abstract String filterEqualsNotColumn(); public abstract String filterGreaterThanColumn(); public abstract String filterLessThanColumn(); public abstract String filterBeforeColumn(); public abstract String filterAfterColumn(); public abstract String filterUntitled(); public abstract String filterEmpty(); public abstract String filterShowing(int rowCount, int size, String filterName); public abstract String popupMenuAddField(); public abstract String popupMenuAddFieldMsg(int count); public abstract String export(); public abstract String exportToolTip(); public abstract String exportTableData(); //Text Dialog public abstract String textLoadFailMsg(); public abstract String textLoadFailTitle(); public abstract String textSaveFailMsg(); public abstract String textSaveFailTitle(); public abstract String textToClipboard(); public abstract String textToFile(); public abstract String textFromClipboard(); public abstract String textFromFile(); public abstract String textClose(); public abstract String textImport(); public abstract String textInvalid(); public abstract String textEmpty(); public abstract String textExport(); //JSimpleColorPicker public abstract String colorDefault(); public abstract String colorNone(); public abstract String colorCustom(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsAgents.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsAgents extends Bundle { public static TabsAgents get() { return BundleServiceFactory.getBundleService().get(TabsAgents.class); } public TabsAgents(final Locale locale) { super(locale); } public abstract String agents(); public abstract String columnName(); public abstract String columnCorporation(); public abstract String columnFaction(); public abstract String columnLevel(); public abstract String columnLocation(); public abstract String columnSecurity(); public abstract String columnSystem(); public abstract String columnConstellation(); public abstract String columnRegion(); public abstract String columnDivision(); public abstract String columnType(); public abstract String columnLocator(); public abstract String columnAgentID(); public abstract String columnCorporationID(); public abstract String columnFactionID(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsAssets.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsAssets extends Bundle { public static TabsAssets get() { return BundleServiceFactory.getBundleService().get(TabsAssets.class); } public TabsAssets(final Locale locale) { super(locale); } public abstract String assets(); public abstract String average(); public abstract String reprocessColors(); public abstract String reprocessColorsToolTip(); public abstract String treemap(); public abstract String treemapToolTip(); public abstract String totalCount(); public abstract String totalReprocessed(); public abstract String totalValue(); public abstract String totalVolume(); public abstract String clearNew(); public abstract String columnName(); public abstract String columnNameType(); public abstract String columnNameCustom(); public abstract String columnTags(); public abstract String columnGroup(); public abstract String columnCategory(); public abstract String columnSlot(); public abstract String columnChargeSize(); public abstract String columnOwner(); public abstract String columnLocation(); public abstract String columnSecurity(); public abstract String columnSystem(); public abstract String columnConstellation(); public abstract String columnRegion(); public abstract String columnFactionWarfareSystemOwner(); public abstract String columnFactionWarfareSystemOwnerToolTip(); public abstract String columnContainer(); public abstract String columnFlag(); public abstract String columnPrice(); public abstract String columnPriceToolTip(); public abstract String columnPriceSellMin(); public abstract String columnPriceSellMinToolTip(); public abstract String columnPriceBuyMax(); public abstract String columnPriceBuyMaxToolTip(); public abstract String columnPriceReprocessed(); public abstract String columnPriceReprocessedToolTip(); public abstract String columnPriceManufacturing(); public abstract String columnPriceManufacturingToolTip(); public abstract String columnTransactionPriceLatest(); public abstract String columnTransactionPriceLatestToolTip(); public abstract String columnTransactionPriceAverage(); public abstract String columnTransactionPriceAverageToolTip(); public abstract String columnTransactionPriceMaximum(); public abstract String columnTransactionPriceMaximumToolTip(); public abstract String columnTransactionPriceMinimum(); public abstract String columnTransactionPriceMinimumToolTip(); public abstract String columnPriceBase(); public abstract String columnPriceBaseToolTip(); public abstract String columnPriceReprocessedDifference(); public abstract String columnPriceReprocessedDifferenceToolTip(); public abstract String columnPriceReprocessedPercent(); public abstract String columnPriceReprocessedPercentToolTip(); public abstract String columnValueReprocessed(); public abstract String columnValueReprocessedToolTip(); public abstract String columnValue(); public abstract String columnValueToolTip(); public abstract String columnValuePerVolume(); public abstract String columnCount(); public abstract String columnTypeCount(); public abstract String columnTypeCountToolTip(); public abstract String columnMeta(); public abstract String columnTech(); public abstract String columnVolume(); public abstract String columnVolumeTotal(); public abstract String columnVolumeTotalToolTip(); public abstract String columnVolumePackaged(); public abstract String columnVolumePackagedToolTip(); public abstract String columnSingleton(); public abstract String columnAdded(); public abstract String columnAddedToolTip(); public abstract String columnMaterialEfficiency(); public abstract String columnMaterialEfficiencyToolTip(); public abstract String columnTimeEfficiency(); public abstract String columnTimeEfficiencyToolTip(); public abstract String columnRuns(); public abstract String columnRunsToolTip(); public abstract String columnStructure(); public abstract String columnStructureToolTip(); public abstract String columnItemID(); public abstract String columnItemIDToolTip(); public abstract String columnLocationID(); public abstract String columnLocationIDToolTip(); public abstract String columnTypeID(); public abstract String columnTypeIDToolTip(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsContracts.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsContracts extends Bundle { public static TabsContracts get() { return BundleServiceFactory.getBundleService().get(TabsContracts.class); } public TabsContracts(final Locale locale) { super(locale); } public abstract String auction(); public abstract String availabilityPrivate(); public abstract String availabilityPublic(); public abstract String bought(); public abstract String buying(); public abstract String collapse(); public abstract String collateralAcceptor(); public abstract String collateralIssuer(); public abstract String columnAccepted(); public abstract String columnAcceptor(); public abstract String columnAssignee(); public abstract String columnAvailability(); public abstract String columnBuyout(); public abstract String columnCollateral(); public abstract String columnCompleted(); public abstract String columnContractID(); public abstract String columnEndStation(); public abstract String columnExpired(); public abstract String columnIncluded(); public abstract String columnIssued(); public abstract String columnForCorp(); public abstract String columnIssuer(); public abstract String columnIssuerCorp(); public abstract String columnItemID(); public abstract String columnMarketPrice(); public abstract String columnPriceReprocessed(); public abstract String columnPriceReprocessedToolTip(); public abstract String columnPriceManufacturing(); public abstract String columnPriceManufacturingToolTip(); public abstract String columnMarketValue(); public abstract String columnMarketValueToolTip(); public abstract String columnValueReprocessed(); public abstract String columnValueReprocessedToolTip(); public abstract String columnValueManufacturing(); public abstract String columnValueManufacturingToolTip(); public abstract String columnMaterialEfficiency(); public abstract String columnMaterialEfficiencyToolTip(); public abstract String columnName(); public abstract String columnNumDays(); public abstract String columnOwned(); public abstract String columnOwnedToolTip(); public abstract String columnPrice(); public abstract String columnQuantity(); public abstract String columnRecordID(); public abstract String columnReward(); public abstract String columnRuns(); public abstract String columnRunsToolTip(); public abstract String columnSingleton(); public abstract String columnStartStation(); public abstract String columnStatus(); public abstract String columnTimeEfficiency(); public abstract String columnTimeEfficiencyToolTip(); public abstract String columnTitle(); public abstract String columnType(); public abstract String columnTypeID(); public abstract String columnVolume(); public abstract String contractCount(); public abstract String courier(); public abstract String excluded(); public abstract String expand(); public abstract String included(); public abstract String itemExchange(); public abstract String loan(); public abstract String missing(); public abstract String notAccepted(); public abstract String packaged(); public abstract String publicContract(); public abstract String sellingPrice(); public abstract String sellingAssets(); public abstract String sold(); public abstract String status(); public abstract String statusArchived(); public abstract String statusCancelled(); public abstract String statusCompleted(); public abstract String statusCompletedByContractor(); public abstract String statusCompletedByIssuer(); public abstract String statusDeleted(); public abstract String statusFailed(); public abstract String statusInProgress(); public abstract String statusOutstanding(); public abstract String statusRejected(); public abstract String statusReversed(); public abstract String statusUnknown(); public abstract String title(); public abstract String type(); public abstract String unknown(); public abstract String unpackaged(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsItems.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsItems extends Bundle { public static TabsItems get() { return BundleServiceFactory.getBundleService().get(TabsItems.class); } public TabsItems(final Locale locale) { super(locale); } public abstract String items(); public abstract String columnName(); public abstract String columnGroup(); public abstract String columnCategory(); public abstract String columnSlot(); public abstract String columnChargeSize(); public abstract String columnPriceBase(); public abstract String columnPriceReprocessed(); public abstract String columnPriceManufacturing(); public abstract String columnPriceManufacturingToolTip(); public abstract String columnMeta(); public abstract String columnTech(); public abstract String columnVolume(); public abstract String columnVolumePackaged(); public abstract String columnTypeID(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsJobs.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsJobs extends Bundle { public static TabsJobs get() { return BundleServiceFactory.getBundleService().get(TabsJobs.class); } public TabsJobs(final Locale locale) { super(locale); } public abstract String active(); public abstract String all(); public abstract String bpc(); public abstract String bpo(); public abstract String completed(); public abstract String count(); public abstract String industry(); public abstract String install(); public abstract String inventionSuccess(); public abstract String manufactureJobsValue(); public abstract String no(); public abstract String status(); public abstract String columnState(); public abstract String columnActivity(); public abstract String columnName(); public abstract String columnGroup(); public abstract String columnOwner(); public abstract String columnInstaller(); public abstract String columnOwned(); public abstract String columnOwnedToolTip(); public abstract String columnCompletedCharacter(); public abstract String columnLocation(); public abstract String columnSystem(); public abstract String columnConstellation(); public abstract String columnRegion(); public abstract String columnStartDate(); public abstract String columnEndDate(); public abstract String columnCompletedDate(); public abstract String columnTimeLeft(); public abstract String columnPauseDate(); public abstract String columnRuns(); public abstract String columnOutputCount(); public abstract String columnOutputValue(); public abstract String columnOutputVolume(); public abstract String columnOutputVolumeToolTip(); public abstract String columnOutputType(); public abstract String columnOutputGroup(); public abstract String columnOutputCategory(); public abstract String columnBPO(); public abstract String columnMaterialEfficiency(); public abstract String columnTimeEfficiency(); public abstract String columnCost(); public abstract String columnJobID(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsJournal.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsJournal extends Bundle { public static TabsJournal get() { return BundleServiceFactory.getBundleService().get(TabsJournal.class); } public TabsJournal(final Locale locale) { super(locale); } public abstract String clearNew(); public abstract String contextAllianceID(); public abstract String contextCharacterID(); public abstract String contextContractID(); public abstract String contextCorporationID(); public abstract String contextEveID(); public abstract String contextIndustryJobID(); public abstract String contextPlanetID(); public abstract String contextStationID(); public abstract String contextStructureID(); public abstract String contextSystemID(); public abstract String contextTransactionID(); public abstract String contextTypeID(); public abstract String contracts(); public abstract String chart(); public abstract String chartTotal(); public abstract String chartTitle(); public abstract String close(); public abstract String findIn(); public abstract String industryJobs(); public abstract String noDataFound(); public abstract String rattingIncome(); public abstract String title(); public abstract String total(); public abstract String totalNegative(); public abstract String totalPositive(); public abstract String transactions(); public abstract String columnAccountKey(); public abstract String columnAmount(); public abstract String columnBalance(); public abstract String columnDate(); public abstract String columnOwner(); public abstract String columnOwnerName1(); public abstract String columnOwnerName2(); public abstract String columnReason(); public abstract String columnRefType(); public abstract String columnTags(); public abstract String columnTaxAmount(); public abstract String columnAdded(); public abstract String columnAddedToolTip(); public abstract String columnContextName(); public abstract String columnContextType(); public abstract String columnContextID(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsLoadout.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsLoadout extends Bundle { public static TabsLoadout get() { return BundleServiceFactory.getBundleService().get(TabsLoadout.class); } public TabsLoadout(final Locale locale) { super(locale); } public abstract String cancel(); public abstract String collapse(); public abstract String columnLocation(); public abstract String columnName(); public abstract String columnOwner(); public abstract String columnSlot(); public abstract String columnValue(); public abstract String columnShip(); public abstract String description(); public abstract String empty(); public abstract String expand(); public abstract String export(); public abstract String exportEft(); public abstract String exportEveXml(); public abstract String exportEveXmlAll(); public abstract String exportEveXmlSelected(); public abstract String exportTableData(); public abstract String flagCargo(); public abstract String flagDroneBay(); public abstract String flagHighSlot(); public abstract String flagLowSlot(); public abstract String flagMediumSlot(); public abstract String flagOther(); public abstract String flagRigSlot(); public abstract String flagSubSystem(); public abstract String flagTotalValue(); public abstract String name(); public abstract String name1(); public abstract String no(); public abstract String no1(); public abstract String oK(); public abstract String owner(); public abstract String ship(); public abstract String ship1(); public abstract String totalAll(); public abstract String totalModules(); public abstract String totalShip(); public abstract String whitespace10(Object arg0); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsLoyaltyPoints.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsLoyaltyPoints extends Bundle { public static TabsLoyaltyPoints get() { return BundleServiceFactory.getBundleService().get(TabsLoyaltyPoints.class); } public TabsLoyaltyPoints(final Locale locale) { super(locale); } public abstract String loyaltyPoints(); public abstract String columnOwner(); public abstract String columnCorporationName(); public abstract String columnLoyaltyPoints(); public abstract String total(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsMaterials.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsMaterials extends Bundle { public static TabsMaterials get() { return BundleServiceFactory.getBundleService().get(TabsMaterials.class); } public TabsMaterials(final Locale locale) { super(locale); } public abstract String all(); public abstract String collapse(); public abstract String columnCount(); public abstract String columnGroup(); public abstract String columnLocation(); public abstract String columnName(); public abstract String columnPrice(); public abstract String columnValue(); public abstract String columnTypeID(); public abstract String expand(); public abstract String grandTotal(); public abstract String includeCommodity(); public abstract String includeMaterials(); public abstract String includeOre(); public abstract String includePI(); public abstract String materials(); public abstract String no(); public abstract String summary(); public abstract String total(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsMining.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsMining extends Bundle { public static TabsMining get() { return BundleServiceFactory.getBundleService().get(TabsMining.class); } public TabsMining(final Locale locale) { super(locale); } public abstract String average(); public abstract String character(); public abstract String corporation(); public abstract String count(); public abstract String extractions(); public abstract String extractionsActiveSoon(); public abstract String from(); public abstract String grandTotal(); public abstract String graphToolTip(Comparable name, String isk, String date); public abstract String groupBasic(String group); public abstract String groupName(String group, String type); public abstract String groupTotal(String group); public abstract String includeZero(); public abstract String miningGraph(); public abstract String miningLog(); public abstract String scaleLinear(); public abstract String scaleLogarithmic(); public abstract String show(); public abstract String to(); public abstract String totalCount(); public abstract String totalReprocessed(); public abstract String totalValue(); public abstract String totalVolume(); public abstract String valueOre(); public abstract String valueReprocessed(); public abstract String valueReprocessedMax(); public abstract String volume(); public abstract String columnDate(); public abstract String columnName(); public abstract String columnGroup(); public abstract String columnCategory(); public abstract String columnOwner(); public abstract String columnLocation(); public abstract String columnCount(); public abstract String columnPriceOre(); public abstract String columnPriceReprocessed(); public abstract String columnPriceReprocessedToolTip(); public abstract String columnPriceReprocessedMax(); public abstract String columnPriceReprocessedMaxToolTip(); public abstract String columnValueOre(); public abstract String columnValueReprocessed(); public abstract String columnValueReprocessedToolTip(); public abstract String columnValueReprocessedMax(); public abstract String columnValueReprocessedMaxToolTip(); public abstract String columnVolume(); public abstract String columnValuePerVolumeOre(); public abstract String columnValuePerVolumeReprocessed(); public abstract String columnValuePerVolumeReprocessedToolTip(); public abstract String columnValuePerVolumeReprocessedMax(); public abstract String columnValuePerVolumeReprocessedMaxToolTip(); public abstract String columnCorporation(); public abstract String columnForCorporation(); public abstract String columnExtractionStartTime(); public abstract String columnMoon(); public abstract String columnChunkArrivalTime(); public abstract String columnNaturalDecayTime(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsNpcStanding.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsNpcStanding extends Bundle { public static TabsNpcStanding get() { return BundleServiceFactory.getBundleService().get(TabsNpcStanding.class); } public TabsNpcStanding(final Locale locale) { super(locale); } public abstract String npcStanding(); public abstract String columnOwner(); public abstract String columnFaction(); public abstract String columnCorporation(); public abstract String columnAgent(); public abstract String columnAgentLevel(); public abstract String columnAgentDivision(); public abstract String columnAgentType(); public abstract String columnType(); public abstract String columnRawStanding(); public abstract String columnRawStandingToolTip(); public abstract String columnStanding(); public abstract String columnStandingToolTip(); public abstract String columnStandingMax(); public abstract String columnStandingMaxToolTip(); public abstract String columnLocation(); public abstract String columnSecurity(); public abstract String columnSystem(); public abstract String columnConstellation(); public abstract String columnRegion(); public abstract String columnID(); public abstract String typeAgent(); public abstract String typeCorporation(); public abstract String typeFaction(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsOrders.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsOrders extends Bundle { public static TabsOrders get() { return BundleServiceFactory.getBundleService().get(TabsOrders.class); } public TabsOrders(final Locale locale) { super(locale); } public abstract String activeBuyOrders(); public abstract String activeSellOrders(); public abstract String buy(); public abstract String clearNew(); public abstract String columnOrderType(); public abstract String columnName(); public abstract String columnGroup(); public abstract String columnCategory(); public abstract String columnVolumeRemain(); public abstract String columnVolumeTotal(); public abstract String columnPrice(); public abstract String columnOutbidPrice(); public abstract String columnOutbidPriceToolTip(); public abstract String columnOutbidCount(); public abstract String columnOutbidCountToolTip(); public abstract String columnOutbidDelta(); public abstract String columnOutbidDeltaToolTip(); public abstract String columnEveUi(); public abstract String columnEveUiToolTip(); public abstract String columnBrokersFee(); public abstract String columnBrokersFeeToolTip(); public abstract String columnEdits(); public abstract String columnEditsToolTip(); public abstract String columnPriceReprocessed(); public abstract String columnPriceManufacturing(); public abstract String columnPriceManufacturingToolTip(); public abstract String columnIssued(); public abstract String columnIssuedToolTip(); public abstract String columnIssuedFirst(); public abstract String columnIssuedFirstToolTip(); public abstract String columnExpires(); public abstract String columnChanged(); public abstract String columnChangedToolTip(); public abstract String columnRange(); public abstract String columnRemainingValue(); public abstract String columnStatus(); public abstract String columnMinimumQuantity(); public abstract String columnOwner(); public abstract String columnIssuedBy(); public abstract String columnOwned(); public abstract String columnOwnedToolTip(); public abstract String columnWalletDivision(); public abstract String columnLocation(); public abstract String columnSystem(); public abstract String columnConstellation(); public abstract String columnRegion(); public abstract String columnTransactionPrice(); public abstract String columnTransactionPriceToolTip(); public abstract String columnTransactionMargin(); public abstract String columnTransactionMarginToolTip(); public abstract String columnTransactionProfitDifference(); public abstract String columnTransactionProfitDifferenceToolTip(); public abstract String columnTransactionProfitPercent(); public abstract String columnTransactionProfitPercentToolTip(); public abstract String columnMarketPrice(); public abstract String columnMarketPriceToolTip(); public abstract String columnMarketPriceSellMin(); public abstract String columnMarketPriceSellMinToolTip(); public abstract String columnMarketPriceBuyMax(); public abstract String columnMarketPriceBuyMaxToolTip(); public abstract String columnMarketMargin(); public abstract String columnMarketMarginToolTip(); public abstract String columnMarketProfit(); public abstract String columnMarketProfitToolTip(); public abstract String columnVolume(); public abstract String columnTypeID(); public abstract String columnOrderID(); public abstract String eveUiOpen(); public abstract String lastEsiUpdateToolTip(); public abstract String lastLogUpdateToolTip(); public abstract String lastClipboardToolTip(); public abstract String market(); public abstract String marketLogTypeToolTip(); public abstract String none(); public abstract String ownerInvalidScopeMsg(); public abstract String ownerInvalidScopeTitle(); public abstract String ownerNotFoundMsg(); public abstract String ownerNotFoundTitle(); public abstract String rangeStation(); public abstract String rangeSolarSystem(); public abstract String rangeRegion(); public abstract String rangeJump(); public abstract String rangeJumps(String range); public abstract String sell(); public abstract String sellOrderRangeToolTip(); public abstract String sellOrderRangeLastToolTip(); public abstract String sellOrderRangeSelcted(String selected); public abstract String status(); public abstract String statusActive(); public abstract String statusClosed(); public abstract String statusFulfilled(); public abstract String statusExpired(); public abstract String statusPartiallyFulfilled(); public abstract String statusCancelled(); public abstract String statusPending(); public abstract String statusCharacterDeleted(); public abstract String statusUnknown(); public abstract String totalSellOrders(); public abstract String totalBuyOrders(); public abstract String totalEscrow(); public abstract String totalToCover(); public abstract String unknownLocationsMsg(); public abstract String unknownLocationsMsgLater(); public abstract String unknownLocationsTitle(); public abstract String updateNoActiveMsg(); public abstract String updateNoActiveTitle(); public abstract String updateOutbidEsi(); public abstract String updateOutbidFileBuy(); public abstract String updateOutbidFileSell(); public abstract String updateOutbidWhen(String time); public abstract String updateOutbidUpdating(); public abstract String updateTitle(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsOverview.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsOverview extends Bundle { public static TabsOverview get() { return BundleServiceFactory.getBundleService().get(TabsOverview.class); } public TabsOverview(final Locale locale) { super(locale); } public abstract String add(); public abstract String addGroup(); public abstract String average(); public abstract String clear(); public abstract String constellations(); public abstract String deleteGroup(); public abstract String deleteTheGroup(Object arg0); public abstract String filterShowing(int rowCount, int size, String filterName); public abstract String groups(); public abstract String groupName(); public abstract String loadFilter(); public abstract String locations(); public abstract String overview(); public abstract String owner(); public abstract String planets(); public abstract String regions(); public abstract String renameGroup(); public abstract String stations(); public abstract String systems(); public abstract String totalCount(); public abstract String totalReprocessed(); public abstract String totalValue(); public abstract String totalVolume(); public abstract String view(); public abstract String treemap(); public abstract String treemapToolTip(); public abstract String columnName(); public abstract String columnSystem(); public abstract String columnConstellation(); public abstract String columnRegion(); public abstract String columnSecurity(); public abstract String columnVolume(); public abstract String columnValue(); public abstract String columnValuePerVolume(); public abstract String columnCount(); public abstract String columnAverageValue(); public abstract String columnReprocessedValue(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsPriceChanges.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsPriceChanges extends Bundle { public static TabsPriceChanges get() { return BundleServiceFactory.getBundleService().get(TabsPriceChanges.class); } public TabsPriceChanges(final Locale locale) { super(locale); } public abstract String title(); public abstract String from(); public abstract String to(); public abstract String resetDates(); public abstract String owned(); public abstract String columnName(); public abstract String columnGroup(); public abstract String columnCategory(); public abstract String columnCount(); public abstract String columnCountToolTip(); public abstract String columnPriceFrom(); public abstract String columnPriceTo(); public abstract String columnChangePercent(); public abstract String columnChangePercentToolTip(); public abstract String columnChange(); public abstract String columnChangeToolTip(); public abstract String columnTotal(); public abstract String columnTotalToolTip(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsPriceHistory.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsPriceHistory extends Bundle { public static TabsPriceHistory get() { return BundleServiceFactory.getBundleService().get(TabsPriceHistory.class); } public TabsPriceHistory(final Locale locale) { super(locale); } public abstract String add(); public abstract String addTitle(); public abstract String clear(); public abstract String deleteHistorySet(); public abstract String deleteHistorySets(int size); public abstract String edit(); public abstract String enterName(); public abstract String from(); public abstract String graphToolTip(Comparable name, String isk, String date); public abstract String includeZero(); public abstract String load(); public abstract String manage(); public abstract String manageTitle(); public abstract String maxItemsMsg(int maxItems); public abstract String merge(); public abstract String mergeMax(int maxItem); public abstract String overwrite(); public abstract String remove(); public abstract String rename(); public abstract String save(); public abstract String saveTitle(); public abstract String scaleLinear(); public abstract String scaleLogarithmic(); public abstract String sourcejEveAssets(); public abstract String sourcezKillboard(); public abstract String title(); public abstract String to(); public abstract String updateTitle(); public abstract String updatingMsg(); public abstract String updatingTitle(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsReprocessed.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsReprocessed extends Bundle { public static TabsReprocessed get() { return BundleServiceFactory.getBundleService().get(TabsReprocessed.class); } public TabsReprocessed(final Locale locale) { super(locale); } public abstract String addItem(); public abstract String batch(); public abstract String removeAll(); public abstract String collapse(); public abstract String columnName(); public abstract String columnPrice(); public abstract String columnQuantity100(); public abstract String columnQuantity100ToolTip(); public abstract String columnQuantityMax(); public abstract String columnQuantityMaxToolTip(); public abstract String columnQuantitySkill(); public abstract String columnQuantitySkillToolTip(); public abstract String columnTotalBatch(); public abstract String columnTotalName(); public abstract String columnTotalPrice(); public abstract String columnTotalValue(); public abstract String columnTypeID(); public abstract String columnValueDifference(); public abstract String columnValueMax(); public abstract String columnValueSkill(); public abstract String expand(); public abstract String grandTotal(); public abstract String importButton(); public abstract String multiplierSign(); public abstract String price(); public abstract String remove(); public abstract String selectItem(); public abstract String title(); public abstract String total(); public abstract String value(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsRouting.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsRouting extends Bundle { public static TabsRouting get() { return BundleServiceFactory.getBundleService().get(TabsRouting.class); } public TabsRouting(final Locale locale) { super(locale); } public abstract String add(); public abstract String addStation(); public abstract String addStationSelect(); public abstract String addStationTitle(); public abstract String addSystem(); public abstract String addSystemSelect(); public abstract String addSystemTitle(); public abstract String algorithm(); public abstract String allowed(Object arg0, Object arg1); public abstract String avoid(); public abstract String avoidAdd(); public abstract String avoidClear(); public abstract String avoidLoad(); public abstract String avoidManage(); public abstract String avoidNone(); public abstract String avoidRemove(); public abstract String avoidSave(); public abstract String calculate(); public abstract String cancel(); public abstract String checked(); public abstract String deleteAvoids(int size); public abstract String deleteAvoid(); public abstract String emptyResult(); public abstract String enterAvoidName(); public abstract String error(); public abstract String filteredAssets(); public abstract String filters(); public abstract String filtersTab(); public abstract String importOptionsAll(int count); public abstract String importOptionsOverwriteHelp(); public abstract String importOptionsRenameHelp(); public abstract String importOptionsSkipHelp(); public abstract String mergeAvoids(); public abstract String manageFiltersTitle(); public abstract String noSystems(); public abstract String noSystemsTitle(); public abstract String ok(); public abstract String overviewGroup(Object arg0); public abstract String overwriteAvoid(); public abstract String remove(); public abstract String renameAvoid(); public abstract String resultArrow(); public abstract String resultEdit(); public abstract String resultEditAvoid(String avoid); public abstract String resultEditHelp(); public abstract String resultEditJumps(int jumps); public abstract String resultEditSecurity(String security); public abstract String resultEditTitle(); public abstract String resultEdited(); public abstract String resultEmpty(); public abstract String resultExport(); public abstract String resultImport(); public abstract String resultImportIDs(); public abstract String resultImportNames(); public abstract String resultImportRoute(); public abstract String resultImportRouteEmpty(); public abstract String resultImportRouteInvalid(); public abstract String resultImportText(); public abstract String resultImportXml(); public abstract String resultImported(); public abstract String resultLoad(); public abstract String resultManage(); public abstract String resultManageTitle(); public abstract String resultOverwrite(); public abstract String resultSave(); public abstract String resultSelectRoutes(); public abstract String resultTabFull(); public abstract String resultTabInfo(); public abstract String resultTabShort(); public abstract String resultText(String name, int jumps, int waypoints, String security, String avoid, String time); public abstract String resultUiFail(); public abstract String resultUiOk(); public abstract String resultUiWaypoints(); public abstract String resultUnknownValue(); public abstract String resultUntitled(); public abstract String routeDeleteMsg(int size); public abstract String routeDeleteTitle(); public abstract String routeOverwrite(); public abstract String routeRenameTitle(); public abstract String routeSaveTitle(); public abstract String routeSaveMsg(); public abstract String routingTab(); public abstract String routingTitle(); public abstract String saveFilterMsg(); public abstract String saveFilterTitle(); public abstract String security(); public abstract String source(); public abstract String startEmpty(); public abstract String startSystem(); public abstract String total(Object arg0, Object arg1); public abstract String unchecked(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsSkills.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsSkills extends Bundle { public static TabsSkills get() { return BundleServiceFactory.getBundleService().get(TabsSkills.class); } public TabsSkills(final Locale locale) { super(locale); } public abstract String add(); public abstract String deleteSkillPlan(); public abstract String deleteSkillPlans(int size); public abstract String enterName(); public abstract String manage(); public abstract String manageTitle(); public abstract String merge(); public abstract String noValidSkills(); public abstract String overwrite(); public abstract String rename(); public abstract String skillPlans(); public abstract String skills(); public abstract String skillsOverview(); public abstract String tableToolTipCompleted(); public abstract String tableToolTipMissing(int missing); public abstract String tableToolTipSkill(String name, int approximateLevel, int targetLevel, String percent); public abstract String tableToolTipTruncated(); public abstract String total(); public abstract String columnSkill(); public abstract String columnGroup(); public abstract String columnCharacter(); public abstract String columnActive(); public abstract String columnTrained(); public abstract String columnTotal(); public abstract String columnUnallocated(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsSlots.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsSlots extends Bundle { public static TabsSlots get() { return BundleServiceFactory.getBundleService().get(TabsSlots.class); } public TabsSlots(final Locale locale) { super(locale); } public abstract String contractCharacter(); public abstract String contractCorporation(); public abstract String grandTotal(); public abstract String manufacturing(); public abstract String marketOrders(); public abstract String reactions(); public abstract String research(); public abstract String tableHeader(); public abstract String tableHeaderIcon(); public abstract String tableHeaderText(); public abstract String title(); public abstract String columnOwner(); public abstract String columnManufacturingDone(); public abstract String columnManufacturingFree(); public abstract String columnManufacturingActive(); public abstract String columnManufacturingMax(); public abstract String columnResearchDone(); public abstract String columnResearchFree(); public abstract String columnResearchActive(); public abstract String columnResearchMax(); public abstract String columnReactionsFree(); public abstract String columnReactionsDone(); public abstract String columnReactionsActive(); public abstract String columnReactionsMax(); public abstract String columnMarketOrdersFree(); public abstract String columnMarketOrdersActive(); public abstract String columnMarketOrdersMax(); public abstract String columnContractCharacterFree(); public abstract String columnContractCharacterActive(); public abstract String columnContractCharacterMax(); public abstract String columnContractCorporationFree(); public abstract String columnContractCorporationActive(); public abstract String columnContractCorporationMax(); public abstract String columnCurrentShip(); public abstract String columnCurrentStation(); public abstract String columnCurrentSystem(); public abstract String columnCurrentConstellation(); public abstract String columnCurrentRegion(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsStockpile.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsStockpile extends Bundle { public static TabsStockpile get() { return BundleServiceFactory.getBundleService().get(TabsStockpile.class); } public TabsStockpile(final Locale locale) { super(locale); } public abstract String addBlueprintMsg(); public abstract String addBlueprintTitle(); public abstract String addFilter(); public abstract String addFormulaMsg(); public abstract String addFormulaTitle(); public abstract String addItem(); public abstract String addLocation(); public abstract String addStockpileItem(); public abstract String addStockpileTitle(); public abstract String addToNewStockpile(); public abstract String addToStockpile(); public abstract String blueprintFacility(); public abstract String blueprintMe(); public abstract String blueprintRigs(); public abstract String blueprintSecurity(); public abstract String blueprintType(); public abstract String blueprints(); public abstract String cancel(); public abstract String clipboardStockpile(); public abstract String cloneStockpile(); public abstract String cloneStockpileFilter(); public abstract String cloneStockpileTitle(); public abstract String close(); public abstract String collapse(); public abstract String constellation(); public abstract String container(); public abstract String containerIncludeSubs(); public abstract String containerIncludeSubsToolTip(); public abstract String copy(); public abstract String countMinimum(); public abstract String csv(); public abstract String delete(); public abstract String deleteItem(); public abstract String deleteItemTitle(); public abstract String deleteItems(int size); public abstract String deleteStockpile(); public abstract String deleteStockpileTitle(); public abstract String deleteStockpileMsg(int count); public abstract String duplicate(); public abstract String edit(); public abstract String editCell(); public abstract String editGroup(); public abstract String editItem(); public abstract String editStockpile(); public abstract String editStockpileFilter(); public abstract String editStockpileItem(); public abstract String editStockpileTitle(); public abstract String estimatedMarketValue(); public abstract String eveMultibuy(); public abstract String eveUiOpen(); public abstract String expand(); public abstract String exportStockpilesXml(); public abstract String exportStockpilesText(); public abstract String filters(); public abstract String flag(); public abstract String flagIncludeSubs(); public abstract String flagIncludeSubsToolTip(); public abstract String getShoppingList(); public abstract String groupAddEmpty(); public abstract String groupAddExist(); public abstract String groupAddName(); public abstract String groupAddNew(); public abstract String groupAddTitle(); public abstract String groupCollapse(); public abstract String groupExpand(); public abstract String groupMenu(); public abstract String groupRenameExist(); public abstract String groupRenameTitle(); public abstract String groupShoppingListMsg(); public abstract String groupShoppingListTitle(); public abstract String groups(); public abstract String hideStockpile(); public abstract String importButton(); public abstract String importEveXml(); public abstract String importStockpilesText(); public abstract String importText(); public abstract String importTextFailedMsg(); public abstract String importStockpilesXml(); public abstract String importOptionsAll(int count); public abstract String importXmlFailedMsg(); public abstract String importFailedTitle(); public abstract String importOptions(); public abstract String importOptionsAdd(); public abstract String importOptionsAddHelp(); public abstract String importOptionsKeep(); public abstract String importOptionsKeepHelp(); public abstract String importOptionsMerge(); public abstract String importOptionsMergeHelp(); public abstract String importOptionsNew(); public abstract String importOptionsNewHelp(); public abstract String importOptionsOverwrite(); public abstract String importOptionsOverwriteHelp(); public abstract String importOptionsRename(); public abstract String importOptionsRenameHelp(); public abstract String importOptionsSkip(); public abstract String importOptionsSkipHelp(); public abstract String importOptionsTemplate(); public abstract String importOptionsTemplateHelp(); public abstract String include(); public abstract String includeCount(int i); public abstract String includeHelp(); public abstract String includeAssets(); public abstract String includeAssetsTip(); public abstract String includeBuyOrders(); public abstract String includeBuyOrdersTip(); public abstract String includeBuyTransactions(); public abstract String includeBuyTransactionsTip(); public abstract String includeJobs(); public abstract String includeJobsTip(); public abstract String includeSellOrders(); public abstract String includeSellOrdersTip(); public abstract String includeSellTransactions(); public abstract String includeSellTransactionsTip(); public abstract String includeBuyingContracts(); public abstract String includeBuyingContractsTip(); public abstract String includeBoughtContracts(); public abstract String includeBoughtContractsTip(); public abstract String includeSellingContracts(); public abstract String includeSellingContractsTip(); public abstract String includeSoldContracts(); public abstract String includeSoldContractsTip(); public abstract String item(); public abstract String items(); public abstract String itemsMissing(); public abstract String itemsOwned(); public abstract String itemsRequired(); public abstract String itemsShoppingList(); public abstract String jobsDays(); public abstract String jobsDaysLess(); public abstract String jobsDaysMore(); public abstract String jobsDaysTip(); public abstract String jobsDaysWarning(); public abstract String location(); public abstract String marketDetailsOwnerToolTip(); public abstract String match(); public abstract String matchAll(); public abstract String matchAllTip(); public abstract String matchExclude(); public abstract String matchInclude(); public abstract String materialsManufacturing(); public abstract String materialsReaction(); public abstract String me(); public abstract String multiple(); public abstract String multiplier(); public abstract String multiplierIgnore(); public abstract String multiplierSign(); public abstract String myLocations(); public abstract String name(); public abstract String needed(); public abstract String newStockpile(); public abstract String noLocationsFound(); public abstract String none(); public abstract String nothingNeeded(); public abstract String now(); public abstract String ok(); public abstract String original(); public abstract String owner(); public abstract String percent(); public abstract String percentFull(); public abstract String percentIgnore(); public abstract String planet(); public abstract String region(); public abstract String remove(); public abstract String renameStockpileTitle(); public abstract String runs(); public abstract String selectFits(); public abstract String selectGroup(); public abstract String selectStockpiles(); public abstract String shoppingList(); public abstract String showHidden(); public abstract String showHide(); public abstract String showStockpiles(); public abstract String showSubpileTree(); public abstract String shownValueNeeded(); public abstract String shownValueNow(); public abstract String shownVolumeNeeded(); public abstract String shownVolumeNow(); public abstract String singleton(); public abstract String source(); public abstract String spreadsheet(); public abstract String station(); public abstract String stockpile(); public abstract String stockpileAvailable(); public abstract String stockpileLocation(); public abstract String stockpileOwner(); public abstract String stockpileShoppingList(); public abstract String subpileShoppingList(); public abstract String subpiles(); public abstract String system(); public abstract String totalStockpile(); public abstract String totalToHaul(); public abstract String universe(); public abstract String columnName(); public abstract String columnGroup(); public abstract String columnCategory(); public abstract String columnSlot(); public abstract String columnChargeSize(); public abstract String columnMeta(); public abstract String columnEveUi(); public abstract String columnEveUiToolTip(); public abstract String columnCountNow(); public abstract String columnCountNowInventory(); public abstract String columnCountNowBuyOrders(); public abstract String columnCountNowBuyTransactions(); public abstract String columnCountNowSellOrders(); public abstract String columnCountNowSellTransactions(); public abstract String columnCountNowJobs(); public abstract String columnCountNowBuyingContracts(); public abstract String columnCountNowBoughtContracts(); public abstract String columnCountNowSellingContracts(); public abstract String columnCountNowSoldContracts(); public abstract String columnCountNeeded(); public abstract String columnCountMinimum(); public abstract String columnCountMinimumMultiplied(); public abstract String columnPercentNeeded(); public abstract String columnPrice(); public abstract String columnPriceToolTip(); public abstract String columnPriceSellMin(); public abstract String columnPriceSellMinToolTip(); public abstract String columnPriceBuyMax(); public abstract String columnPriceBuyMaxToolTip(); public abstract String columnPriceTransactionAverage(); public abstract String columnPriceTransactionAverageToolTip(); public abstract String columnTags(); public abstract String columnValueNow(); public abstract String columnValueNeeded(); public abstract String columnVolumeNow(); public abstract String columnVolumeNeeded(); public abstract String getFilterStockpileName(); public abstract String getFilterStockpileOwner(); public abstract String getFilterStockpileLocation(); public abstract String getFilterStockpileFlag(); public abstract String getFilterStockpileContainer(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsTracker.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsTracker extends Bundle { public static TabsTracker get() { return BundleServiceFactory.getBundleService().get(TabsTracker.class); } public TabsTracker(final Locale locale) { super(locale); } public abstract String all(); public abstract String allProfiles(); public abstract String assets(); public abstract String assetsFilters(); public abstract String cancel(); public abstract String characterCorporations(); public abstract String characterWallet(); public abstract String checkAllLocationsMsg(); public abstract String checkAllLocationsTitle(); public abstract String clear(); public abstract String contractCollateral(); public abstract String contractValue(); public abstract String corporationWallet(); public abstract String date(); public abstract String day1(); public abstract String delete(); public abstract String deleteSelected(); public abstract String division(String id); public abstract String edit(); public abstract String empty(); public abstract String enterNewValue(); public abstract String error(); public abstract String escrows(); public abstract String escrowsToCover(); public abstract String filterTitle(); public abstract String from(); public abstract String grandTotal(); public abstract String help(); public abstract String helpBugData(); public abstract String helpBugDataToolTip(); public abstract String helpLegacyData(); public abstract String helpLegacyDataToolTip(); public abstract String helpNewData(); public abstract String helpNewDataToolTip(); public abstract String implants(); public abstract String importFile(); public abstract String importFileImport(); public abstract String importFileInvalidMsg(); public abstract String importFileOptionsKeep(); public abstract String importFileOptionsMsg(); public abstract String importFileOptionsOverwrite(); public abstract String importFileOptionsReplace(); public abstract String importFileTitle(); public abstract String includeZero(); public abstract String invalid(); public abstract String invalidNumberMsg(); public abstract String invalidNumberTitle(); public abstract String knownLocations(); public abstract String manufacturing(); public abstract String month1(); public abstract String months3(); public abstract String months6(); public abstract String newSelected(); public abstract String noDataFound(); public abstract String note(); public abstract String notesAdd(); public abstract String notesDeleteMsg(String note); public abstract String notesDeleteTitle(); public abstract String notesEditMsg(); public abstract String notesEditTitle(); public abstract String ok(); public abstract String other(); public abstract String quickDate(); public abstract String reset(); public abstract String search(); public abstract String scaleLinear(); public abstract String scaleLogarithmic(); public abstract String selectDivision(); public abstract String selectFlag(); public abstract String selectLocation(); public abstract String selectOwner(); public abstract String selectionDate(); public abstract String selectionIsk(); public abstract String selectionNote(); public abstract String selectionShortDate(); public abstract String selectionShortIsk(); public abstract String selectionShortNote(); public abstract String sellOrders(); public abstract String show(); public abstract String skillPointFilters(); public abstract String skillPointValue(); public abstract String skillPoints(); public abstract String statusAssets(); public abstract String statusBalance(); public abstract String statusContractCollateral(); public abstract String statusContractValue(); public abstract String statusEscrows(); public abstract String statusEscrowsToCover(); public abstract String statusImplants(); public abstract String statusManufacturing(); public abstract String statusSellOrders(); public abstract String statusSkillPointValue(); public abstract String statusTotal(); public abstract String title(); public abstract String to(); public abstract String total(); public abstract String unknownLocations(); public abstract String walletBalance(); public abstract String walletBalanceFilters(); public abstract String week1(); public abstract String week2(); public abstract String year1(); public abstract String years2(); public abstract String columnShow(); public abstract String columnName(); public abstract String columnMinimum(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsTransaction.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsTransaction extends Bundle { public static TabsTransaction get() { return BundleServiceFactory.getBundleService().get(TabsTransaction.class); } public TabsTransaction(final Locale locale) { super(locale); } public abstract String bothAvg(); public abstract String bothCount(); public abstract String bothTitle(); public abstract String bothTotal(); public abstract String buy(); public abstract String buyAvg(); public abstract String buyCount(); public abstract String buyTitle(); public abstract String buyTotal(); public abstract String clearNew(); public abstract String corporation(); public abstract String personal(); public abstract String sell(); public abstract String sellAvg(); public abstract String sellCount(); public abstract String sellTitle(); public abstract String sellTotal(); public abstract String title(); public abstract String columnTransactionType(); public abstract String columnName(); public abstract String columnGroup(); public abstract String columnCategory(); public abstract String columnQuantity(); public abstract String columnPrice(); public abstract String columnTax(); public abstract String columnClientName(); public abstract String columnStationName(); public abstract String columnSystem(); public abstract String columnConstellation(); public abstract String columnRegion(); public abstract String columnTags(); public abstract String columnTransactionPrice(); public abstract String columnTransactionPriceToolTip(); public abstract String columnTransactionMargin(); public abstract String columnTransactionMarginToolTip(); public abstract String columnTransactionProfitDifference(); public abstract String columnTransactionProfitDifferenceToolTip(); public abstract String columnTransactionProfitPercent(); public abstract String columnTransactionProfitPercentToolTip(); public abstract String columnTransactionFor(); public abstract String columnValue(); public abstract String columnTransactionDate(); public abstract String columnOwner(); public abstract String columnLocation(); public abstract String columnAccountKey(); public abstract String columnAdded(); public abstract String columnAddedToolTip(); public abstract String columnVolume(); public abstract String columnTransactionID(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsTree.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsTree extends Bundle { public static TabsTree get() { return BundleServiceFactory.getBundleService().get(TabsTree.class); } public TabsTree(final Locale locale) { super(locale); } public abstract String categories(); public abstract String collapse(); public abstract String expand(); public abstract String locationAssetSafety(); public abstract String locationClones(); public abstract String locationContracts(); public abstract String locationDeliveries(); public abstract String locationItemHangar(); public abstract String locationMarketOrders(); public abstract String locationShipHangar(); public abstract String locations(); public abstract String title(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/i18n/TabsValues.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import java.util.Locale; import uk.me.candle.translations.Bundle; public abstract class TabsValues extends Bundle { public static TabsValues get() { return BundleServiceFactory.getBundleService().get(TabsValues.class); } public TabsValues(final Locale locale) { super(locale); } public abstract String columnAssets(); public abstract String columnBestAsset(); public abstract String columnBestModule(); public abstract String columnBestShip(); public abstract String columnBestShipFitted(); public abstract String columnContractCollateral(); public abstract String columnContractValue(); public abstract String columnEscrows(); public abstract String columnEscrowsToCover(); public abstract String columnManufacturing(); public abstract String columnOwner(); public abstract String columnSellOrders(); public abstract String columnSkillPointValue(); public abstract String columnTotal(); public abstract String columnWalletBalance(); public abstract String columnWalletDivision1(); public abstract String columnWalletDivision2(); public abstract String columnWalletDivision3(); public abstract String columnWalletDivision4(); public abstract String columnWalletDivision5(); public abstract String columnWalletDivision6(); public abstract String columnWalletDivision7(); public abstract String columnCurrentShip(); public abstract String columnCurrentStation(); public abstract String columnCurrentSystem(); public abstract String columnCurrentConstellation(); public abstract String columnCurrentRegion(); public abstract String grandTotal(); public abstract String none(); public abstract String empty(); public abstract String title(); public abstract String skillPointFilters(); public abstract String oldTitle(); public abstract String oldNoCharacter(); public abstract String oldNoCorporation(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/AbstractEsiGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.time.LocalDate; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.io.shared.AbstractGetter; import net.nikr.eve.jeveasset.io.shared.ThreadWoker; import net.nikr.eve.jeveasset.io.shared.ThreadWoker.TaskCancelledException; import net.troja.eve.esi.ApiClient; import net.troja.eve.esi.ApiClientBuilder; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.api.AssetsApi; import net.troja.eve.esi.api.CharacterApi; import net.troja.eve.esi.api.ClonesApi; import net.troja.eve.esi.api.ContractsApi; import net.troja.eve.esi.api.CorporationApi; import net.troja.eve.esi.api.FactionWarfareApi; import net.troja.eve.esi.api.IndustryApi; import net.troja.eve.esi.api.LocationApi; import net.troja.eve.esi.api.LoyaltyApi; import net.troja.eve.esi.api.MarketApi; import net.troja.eve.esi.api.PlanetaryInteractionApi; import net.troja.eve.esi.api.SkillsApi; import net.troja.eve.esi.api.UniverseApi; import net.troja.eve.esi.api.UserInterfaceApi; import net.troja.eve.esi.api.WalletApi; import net.troja.eve.esi.auth.OAuth; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import okhttp3.OkHttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AbstractEsiGetter extends AbstractGetter { private static final Logger LOG = LoggerFactory.getLogger(AbstractEsiGetter.class); private static OkHttpClient OkHttpClient; private static final ApiClient PUBLIC_CLIENT = new ApiClientBuilder().okHttpClient(getHttpClient()).build(); private static final UniverseApi UNIVERSE_API = new UniverseApi(PUBLIC_CLIENT); private static final CharacterApi CHARACTER_API = new CharacterApi(PUBLIC_CLIENT); private static final ContractsApi CONTRACTS_API = new ContractsApi(PUBLIC_CLIENT); private static final MarketApi MARKET_API = new MarketApi(PUBLIC_CLIENT); private static final IndustryApi INDUSTRY_API = new IndustryApi(PUBLIC_CLIENT); private static final FactionWarfareApi FACTION_WARFARE_API = new FactionWarfareApi(PUBLIC_CLIENT); public static final UserInterfaceApi USER_INTERFACE_API = new UserInterfaceApi(PUBLIC_CLIENT); public static final LocalDate COMPATIBILITY_DATE = UniverseApi.COMPATIBILITY_DATE; protected static final int UNIVERSE_BATCH_SIZE = 100; protected static final int LOCATIONS_BATCH_SIZE = 100; protected static final int DEFAULT_RETRIES = 3; /** * Errors left in in this error limit time frame (can be null) */ private static Integer errorLimit = null; /** * Date when the error limit will be reset (never null) */ private static Date errorReset = new Date(); public AbstractEsiGetter(UpdateTask updateTask, EsiOwner owner, boolean forceUpdate, Date nextUpdate, TaskType taskType) { super(updateTask, owner, forceUpdate(owner, taskType, forceUpdate), nextUpdate, taskType, "ESI"); } public static OkHttpClient getHttpClient() { if (OkHttpClient == null || OkHttpClient.interceptors().size() > 100 || OkHttpClient.networkInterceptors().size() > 100) { OkHttpClient = new OkHttpClient.Builder() .readTimeout(20, TimeUnit.SECONDS) .writeTimeout(20, TimeUnit.SECONDS) .connectTimeout(20, TimeUnit.SECONDS).build(); } return OkHttpClient; } private static boolean forceUpdate(EsiOwner owner, TaskType taskType, boolean forceUpdate) { if (forceUpdate) { return true; } if (taskType == TaskType.OWNER && owner != null) { OAuth auth = (OAuth) owner.getApiClient().getAuthentication(ApiClientBuilder.AUTHENTICATION); return auth.getJWT() == null; //Force update of old tokens } return false; } protected abstract RolesEnum[] getRequiredRoles(); @Override public void run() { if (!canUpdate()) { //Add warning for missing corporation roles if (owner != null && !haveAccess()) { RolesEnum[] requiredRoles = getRequiredRoles(); if (owner.isCorporation() && requiredRoles != null && requiredRoles.length > 0) { StringBuilder builder = new StringBuilder(); builder.append("Require corporation role:\r\n"); boolean first = true; for (RolesEnum role : requiredRoles) { if (first) { first = false; } else { builder.append(", "); } builder.append(role.getValue().replace("_", " ")); } addWarning("MISSING CORPORATION ROLE", builder.toString()); } } return; } //Check if API key is invalid (still update when editing account AKA forceUpdate) if (!isForceUpdate() && owner != null && owner.isInvalid()) { addError("INVALID AUTHORIZATION (OWNER)", "Account Authorization Invalid\r\n(Fix: Options > Accounts... > Edit the account)"); return; } try { update(); } catch (ApiException ex) { addError("Error Code: " + ex.getCode() + "\r\n" + ex.getResponseBody(), "Error Code: " + ex.getCode() + "\r\n" + ex.getResponseBody(), ex); } catch (TaskCancelledException ex) { logInfo(null, "Cancelled"); } catch (InvalidAuthException ex) { addError("INVALID AUTHORIZATION (API)", "Account Authorization Invalid\r\n(Fix: Options > Accounts... > Edit the account)"); } catch (Exception ex) { addError(ex.getMessage(), "Unknown Error: " + ex.getMessage(), ex); } } private R updateApi(Updater, ApiException> updater) throws ApiException { return updateApi(updater, 0); } private R updateApi(Updater, ApiException> updater, int retries) throws ApiException { checkErrors(); //Update timeframe as needed checkCancelled(); try { ApiResponse apiResponse = updater.update(); if (apiResponse == null) { return null; } handleHeaders(apiResponse); logInfo(updater.getStatus(), "Updated"); if (owner != null) { owner.setInvalid(false); } return apiResponse.getData(); } catch (ApiException ex) { handleHeaders(ex); logWarn(ex.getResponseBody(), ex.getMessage()); if (ex.getCode() == 401 && ex.getResponseBody().toLowerCase().contains("error") && ex.getResponseBody().toLowerCase().contains("authorization not provided")) { if (owner != null) { owner.setInvalid(true); } throw new InvalidAuthException(); } else if ((ex.getCode() >= 500 && ex.getCode() < 600 //CCP error, Lets try again in a sec || ex.getCode() == 0) //Other error, Lets try again in a sec && ex.getCode() != 503 //Don't retry when it may be downtime && (ex.getCode() != 502 || (ex.getResponseBody().toLowerCase().contains("no reply within 10 seconds") || ex.getResponseBody().toLowerCase().startsWith(""))) //Don't retry when it may be downtime, unless it's "no reply within 10 seconds" or html body && retries < updater.getMaxRetries()) { //Retries retries++; try { Thread.sleep(1000); //Wait a sec } catch (InterruptedException ex1) { //No problem } logInfo(updater.getStatus(), "Retrying " + retries + " of " + updater.getMaxRetries() + ":"); return updateApi(updater, retries); } else { throw ex; } } } protected void handleHeaders(ApiException apiException) { setExpires(apiException.getResponseHeaders()); setErrorLimit(apiException.getResponseHeaders()); //Always save error limit header } private void handleHeaders(ApiResponse apiResponse) { setExpires(apiResponse.getHeaders()); setErrorLimit(apiResponse.getHeaders()); //Always save error limit header } protected abstract void update() throws ApiException; private void setErrorLimit(Map> responseHeaders) { if (responseHeaders != null) { setErrorLimit(getHeaderInteger(responseHeaders, "x-esi-error-limit-remain")); setErrorReset(getHeaderInteger(responseHeaders, "x-esi-error-limit-reset")); } } private synchronized static void setErrorLimit(Integer errorLimit) { if (AbstractEsiGetter.errorLimit != null && errorLimit != null) { AbstractEsiGetter.errorLimit = Math.min(AbstractEsiGetter.errorLimit, errorLimit); } else { AbstractEsiGetter.errorLimit = errorLimit; } } private synchronized static void setErrorReset(Integer errorReset) { if (errorReset != null) { AbstractEsiGetter.errorReset = new Date(System.currentTimeMillis() + (errorReset * 1000L)); } } private synchronized static void checkErrors() { if (errorLimit != null && errorLimit < 10) { //Error limit reached try { long wait = (errorReset.getTime() + 1000) - System.currentTimeMillis(); LOG.warn("Error limit reached waiting: " + Formatter.milliseconds(wait, false, false)); if (wait > 0) { //Negative values throws an Exception Thread.sleep(wait); //Wait until the error window is reset } //Reset AbstractEsiGetter.errorReset = new Date(); //New timeframe AbstractEsiGetter.errorLimit = null; //No errors in this timeframe (yet) } catch (InterruptedException ex) { //No problem } } else if (errorLimit != null && errorLimit < 100) { //At least one error LOG.warn("Error limit: " + errorLimit); } } public MarketApi getMarketApiAuth() { return owner.getMarketApiAuth(); } public IndustryApi getIndustryApiAuth() { return owner.getIndustryApiAuth(); } protected CharacterApi getCharacterApiAuth() { return owner.getCharacterApiAuth(); } protected AssetsApi getAssetsApiAuth() { return owner.getAssetsApiAuth(); } protected WalletApi getWalletApiAuth() { return owner.getWalletApiAuth(); } protected UniverseApi getUniverseApiAuth() { return owner.getUniverseApiAuth(); } public ClonesApi getClonesApiAuth() { return owner.getClonesApiAuth(); } public ContractsApi getContractsApiAuth() { return owner.getContractsApiAuth(); } public CorporationApi getCorporationApiAuth() { return owner.getCorporationApiAuth(); } public LocationApi getLocationApiAuth() { return owner.getLocationApiAuth(); } public PlanetaryInteractionApi getPlanetaryInteractionApiAuth() { return owner.getPlanetaryInteractionApiAuth(); } public SkillsApi getSkillsApiAuth() { return owner.getSkillsApiAuth(); } public LoyaltyApi getLoyaltyApiAuth() { return owner.getLoyaltyApiAuth(); } public UniverseApi getUniverseApiOpen() { return UNIVERSE_API; } public CharacterApi getCharacterApiOpen() { return CHARACTER_API; } public static MarketApi getMarketApiOpen() { return MARKET_API; } public static FactionWarfareApi getFactionWarfareApiOpen() { return FACTION_WARFARE_API; } public static ContractsApi getContractsApiOpen() { return CONTRACTS_API; } public static IndustryApi getIndustryApiOpen() { return INDUSTRY_API; } protected final Map updateListSlow(Collection list, boolean trackProgress, int maxRetries, ListHandlerSlow handler) throws ApiException { Map values = new HashMap<>(); int count = 1; for (K k : list) { ListUpdater listUpdater = new ListUpdater<>(handler, k, count + " of " + list.size(), maxRetries); try { if (trackProgress) { setProgress(list.size(), count, 0, 100); } Map returnValue = listUpdater.go(); if (returnValue != null) { values.putAll(returnValue); } } catch (ApiException ex) { handler.handle(ex, k); } count++; } return values; } protected abstract class ListHandlerSlow extends ListHandler { protected abstract void handle(ApiException ex, K k) throws ApiException; } protected final Map updateList(Collection list, int maxRetries, ListHandler handler) throws ApiException { Map values = new HashMap<>(); List> updaters = new ArrayList<>(); int count = 1; for (K k : list) { updaters.add(new ListUpdater<>(handler, k, count + " of " + list.size(), maxRetries)); count++; } LOG.info("Starting " + updaters.size() + " list threads"); try { List>> futures = startSubThreads(updaters); for (Future> future : futures) { Map returnValue = future.get(); if (returnValue != null) { values.putAll(returnValue); } } } catch (InterruptedException ex) { throw new RuntimeException(ex); } catch (ExecutionException ex) { ThreadWoker.throwExecutionException(ApiException.class, ex); } return values; } protected abstract class ListHandler { protected abstract ApiResponse get(K k) throws ApiException; } protected class ListUpdater implements Updater, ApiException>, Callable> { private final ListHandler handler; private final K k; private final String status; private final int maxRetries; public ListUpdater(ListHandler handler, K k, String status, int maxRetries) { this.handler = handler; this.k = k; this.status = status; this.maxRetries = maxRetries; } @Override public ApiResponse update() throws ApiException { return handler.get(k); } public Map go() throws ApiException { V v = updateApi(this); if (v != null) { Map map = new HashMap<>(); map.put(k, v); return map; } else { return null; } } @Override public Map call() throws Exception { return go(); } @Override public String getStatus() { return status; } @Override public int getMaxRetries() { return maxRetries; } } protected final List updatePagedList(Collection list, PagedListHandler handler) throws ApiException { List>> updaters = new ArrayList<>(); for (K k : list) { updaters.add(new Callable>() { @Override public List call() throws Exception { return handler.get(k); } } ); } LOG.info("Starting " + updaters.size() + " list threads"); List values = new ArrayList<>(); try { List>> futures = startSubThreads(updaters); for (Future> future : futures) { List returnValue = future.get(); if (returnValue != null) { values.addAll(returnValue); } } } catch (InterruptedException ex) { throw new RuntimeException(ex); } catch (ExecutionException ex) { ThreadWoker.throwExecutionException(ApiException.class, ex); } return values; } protected abstract class PagedListHandler { protected abstract List get(K k) throws ApiException; } protected final Map> updatePagedMap(Collection list, PagedListHandler handler) throws ApiException { List>>> updaters = new ArrayList<>(); for (K k : list) { updaters.add(new Callable>>() { @Override public Map> call() throws Exception { List v = handler.get(k); if (v != null) { Map> map = new HashMap<>(); map.put(k, v); return map; } else { return null; } } } ); } LOG.info("Starting " + updaters.size() + " list threads"); Map> values = new HashMap<>(); try { List>>> futures = startSubThreads(updaters); for (Future>> future : futures) { Map> returnValue = future.get(); if (returnValue != null) { values.putAll(returnValue); } } } catch (InterruptedException ex) { throw new RuntimeException(ex); } catch (ExecutionException ex) { ThreadWoker.throwExecutionException(ApiException.class, ex); } return values; } protected final List updateIDs(Set existing, int maxRetries, IDsHandler handler) throws ApiException { List list = new ArrayList<>(); Long fromID = null; boolean run = true; int count = 0; while (run) { count++; List result; result = updateApi(new IdUpdater<>(handler, fromID, count + " of ?", maxRetries)); if (result == null || result.isEmpty()) { //Nothing returned: we're done break; //Stop updating } list.addAll(result); //Add new Long lastID = handler.getID(result.get(result.size() - 1)); //Get the last ID if (lastID.equals(fromID)) { //ID is the same as on last update: we're done break; //Stop updating } fromID = lastID; //Set ID for next update for (K t : result) { //Search for existing data if (existing.contains(handler.getID(t))) { //Found existing data run = false; //Stop updating break; //no need to continue } } } return list; } public abstract class IDsHandler { protected abstract ApiResponse> get(Long fromID) throws ApiException; protected abstract Long getID(K response); } public class IdUpdater implements Updater>, ApiException> { private final IDsHandler handler; private final Long fromID; private final String status; private final int maxRetries; public IdUpdater(IDsHandler handler, Long fromID, String status, int maxRetries) { this.handler = handler; this.fromID = fromID; this.status = status; this.maxRetries = maxRetries; } @Override public ApiResponse> update() throws ApiException { return handler.get(fromID); } @Override public String getStatus() { return status; } @Override public int getMaxRetries() { return maxRetries; } } protected List updatePages(int maxRetries, EsiPagesHandler handler) throws ApiException { List values = new ArrayList<>(); EsiPageUpdater pageUpdater = new EsiPageUpdater<>(handler, 1, "1 of ?", maxRetries); List returnValue = updateApi(pageUpdater); if (returnValue != null) { values.addAll(returnValue); } Integer pages = getHeaderInteger(pageUpdater.getResponse().getHeaders(), "x-pages"); //Get pages header int count = 2; if (pages != null && pages > 1) { //More than one page List> updaters = new ArrayList<>(); for (int i = 2; i <= pages; i++) { //Get the remaining pages (we already got page 1 so we start at page 2 updaters.add(new EsiPageUpdater<>(handler, i, count + " of " + pages, maxRetries)); count++; } LOG.info("Starting " + updaters.size() + " pages threads"); try { List>> futures = startSubThreads(updaters); for (Future> future : futures) { if (future.isDone()) { returnValue = future.get(); //Get data from ESI if (returnValue != null) { values.addAll(returnValue); } } } } catch (InterruptedException ex) { throw new RuntimeException(ex); } catch (ExecutionException ex) { ThreadWoker.throwExecutionException(ApiException.class, ex); } } return values; } public interface EsiPagesHandler { public ApiResponse> get(Integer page) throws ApiException; } public class EsiPageUpdater implements Callable>, Updater>, ApiException> { private final EsiPagesHandler handler; private final int page; private final String status; private final int maxRetries; private ApiResponse> response; public EsiPageUpdater(EsiPagesHandler handler, int page, String status, int maxRetries) { this.handler = handler; this.page = page; this.status = status; this.maxRetries = maxRetries; } @Override public ApiResponse> update() throws ApiException { response = handler.get(page); return response; } @Override public List call() throws Exception { return updateApi(this); } public ApiResponse> getResponse() { return response; } @Override public String getStatus() { return status; } @Override public int getMaxRetries() { return maxRetries; } } protected K update(int maxRetries, EsiHandler handler) throws ApiException { EsiUpdater esiUpdater = new EsiUpdater<>(maxRetries, handler); return esiUpdater.go(); } public interface EsiHandler { public ApiResponse get() throws ApiException; } public class EsiUpdater implements Updater, ApiException> { private final int maxRetries; private final EsiHandler handler; public EsiUpdater(int maxRetries, EsiHandler handler) { this.maxRetries = maxRetries; this.handler = handler; } public T go() throws ApiException { return updateApi(this); } @Override public ApiResponse update() throws ApiException { return handler.get(); } @Override public String getStatus() { return "Completed"; } @Override public int getMaxRetries() { return maxRetries; } } private static class InvalidAuthException extends RuntimeException { } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/AuthCodeListener.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; public interface AuthCodeListener { public void setAuthCode(String authCode); public boolean isListening(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiAccountBalanceGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.List; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.CorporationWalletsResponse; public class EsiAccountBalanceGetter extends AbstractEsiGetter { public EsiAccountBalanceGetter(UpdateTask updateTask, EsiOwner owner) { super(updateTask, owner, false, owner.getBalanceNextUpdate(), TaskType.ACCOUNT_BALANCE); } @Override protected void update() throws ApiException { if (owner.isCorporation()) { List response = update(DEFAULT_RETRIES, new EsiHandler>() { @Override public ApiResponse> get() throws ApiException {//(, DATASOURCE, null, null); ApiResponse> apiResponse = getWalletApiAuth().getCorporationWalletsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, null, null, null); Date modified = getHeaderDate(apiResponse.getHeaders(), "last-modified"); if (modified != null && (owner.getBalanceLastUpdate() == null || modified.after(owner.getBalanceLastUpdate()))) { owner.setBalanceLastUpdate(modified); } return apiResponse; } }); owner.setAccountBalances(EsiConverter.toAccountBalanceCorporation(response, owner)); } else { Double response = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { ApiResponse apiResponse = getWalletApiAuth().getCharacterWalletWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, null, null, null); Date modified = getHeaderDate(apiResponse.getHeaders(), "last-modified"); if (modified != null && (owner.getBalanceLastUpdate() == null || modified.after(owner.getBalanceLastUpdate()))) { owner.setBalanceLastUpdate(modified); } return apiResponse; } }); owner.setAccountBalances(EsiConverter.toAccountBalance(response, owner, 1000)); } } @Override protected void setNextUpdate(Date date) { owner.setBalanceNextUpdate(date); } @Override protected boolean haveAccess() { return owner.isAccountBalance(); } @Override protected RolesEnum[] getRequiredRoles() { RolesEnum[] roles = {RolesEnum.DIRECTOR, RolesEnum.ACCOUNTANT, RolesEnum.JUNIOR_ACCOUNTANT}; return roles; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiAssetsGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.List; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterAssetsResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.CorporationAssetsResponse; public class EsiAssetsGetter extends AbstractEsiGetter { public EsiAssetsGetter(UpdateTask updateTask, EsiOwner owner) { super(updateTask, owner, false, owner.getAssetNextUpdate(), TaskType.ASSETS); } @Override protected void update() throws ApiException { if (owner.isCorporation()) { List responses = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { ApiResponse> apiResponse = getAssetsApiAuth().getCorporationAssetsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, page, null, null, null); Date modified = getHeaderDate(apiResponse.getHeaders(), "last-modified"); if (modified != null && (owner.getAssetLastUpdate() == null || modified.after(owner.getAssetLastUpdate()))) { owner.setAssetLastUpdate(modified); } return apiResponse; } }); owner.setAssets(EsiConverter.toAssetsCorporation(responses, owner)); } else { List responses = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { ApiResponse> apiResponse = getAssetsApiAuth().getCharacterAssetsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, page, null, null, null); Date modified = getHeaderDate(apiResponse.getHeaders(), "last-modified"); if (modified != null && (owner.getAssetLastUpdate() == null || modified.after(owner.getAssetLastUpdate()))) { owner.setAssetLastUpdate(modified); } return apiResponse; } }); owner.setAssets(EsiConverter.toAssets(responses, owner)); } } @Override protected void setNextUpdate(Date date) { owner.setAssetNextUpdate(date); } @Override protected boolean haveAccess() { return owner.isAssetList(); } @Override protected RolesEnum[] getRequiredRoles() { RolesEnum[] roles = {RolesEnum.DIRECTOR}; return roles; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiAuth.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.awt.Window; import java.io.UnsupportedEncodingException; import java.util.Base64; import java.util.Set; import java.util.UUID; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.io.shared.DesktopUtil; import net.troja.eve.esi.auth.OAuth; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class EsiAuth { private static final Logger LOG = LoggerFactory.getLogger(EsiAuth.class); private OAuth oAuth; private final MicroServe microServe; private EsiCallbackURL callbackURL; public EsiAuth() { microServe = new MicroServe(); microServe.startServer(); } public void cancelImport() { microServe.stopListening(); } public boolean isServerStarted() { return microServe.isServerStarted(); } public boolean openWebpage(EsiCallbackURL callbackURL, Set scopes, Window window) { try { if (callbackURL == EsiCallbackURL.LOCALHOST) { microServe.startListening(); } oAuth = new OAuth(); //We always need a new oAuth to start a new flow this.callbackURL = callbackURL; oAuth.setClientId(callbackURL.getA()); String state = UUID.randomUUID().toString(); String authorizationUri = oAuth.getAuthorizationUri(callbackURL.getUrl(), scopes, state); return DesktopUtil.browse(authorizationUri, window); } catch (Exception ex) { LOG.error(ex.getMessage(), ex); return false; } } public boolean finishFlow(EsiOwner esiOwner, String authCode) { if (oAuth == null) { return false; } String code; if (callbackURL == EsiCallbackURL.LOCALHOST) { code = microServe.getAuthCode(); if (code == null) { return false; } } else { try { code = new String(Base64.getUrlDecoder().decode(authCode), "UTF-8"); } catch (UnsupportedEncodingException ex) { return false; } catch (IllegalArgumentException ex) { return false; } } try { oAuth.finishFlow(code, "jeveassets"); esiOwner.setAuth(callbackURL, oAuth.getRefreshToken(), oAuth.getAccessToken()); return true; } catch (Exception ex) { LOG.error(ex.getMessage(), ex); return false; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiBlueprintsGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.List; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterBlueprintsResponse; import net.troja.eve.esi.model.CharacterRolesResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.CorporationBlueprintsResponse; public class EsiBlueprintsGetter extends AbstractEsiGetter { public EsiBlueprintsGetter(UpdateTask updateTask, EsiOwner owner) { super(updateTask, owner, false, owner.getBlueprintsNextUpdate(), TaskType.BLUEPRINTS); } @Override protected void update() throws ApiException { if (owner.isCorporation()) { List responses = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getCorporationApiAuth().getCorporationBlueprintsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, page, null, null, null); } }); owner.setBlueprints(EsiConverter.toBlueprintsCorporation(responses)); } else { List responses = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getCharacterApiAuth().getCharacterBlueprintsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, page, null, null, null); } }); owner.setBlueprints(EsiConverter.toBlueprints(responses)); } if (owner.getBlueprints().size() == 25000) { addWarning("BLUEPRINT MAX ITEMS", "25000 blueprints updated\r\nESI is limited to 25K blueprints per char/corp\r\nSome blueprints may not have ME/TE/Runs"); } } @Override protected void setNextUpdate(Date date) { owner.setBlueprintsNextUpdate(date); } @Override protected boolean haveAccess() { return owner.isBlueprints(); } @Override protected RolesEnum[] getRequiredRoles() { CharacterRolesResponse.RolesEnum[] roles = {CharacterRolesResponse.RolesEnum.DIRECTOR}; return roles; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiCallbackURL.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; public enum EsiCallbackURL { LOCALHOST("http://localhost:2221", ""), EVE_NIKR_NET("https://eve.nikr.net/jeveasset/auth", ""), ; private final String url; private final String a; private EsiCallbackURL(String url, String a) { this.url = url; this.a = a; } public String getUrl() { return url; } public String getA() { return a; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiClonesGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.List; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.api.FittingsApi; import net.troja.eve.esi.model.CharacterClonesResponse; import net.troja.eve.esi.model.CharacterLocationResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; public class EsiClonesGetter extends AbstractEsiGetter { public EsiClonesGetter(UpdateTask updateTask, EsiOwner owner, Date assetNextUpdate) { super(updateTask, owner, false, assetNextUpdate, TaskType.CLONES); } @Override protected void update() throws ApiException { if (owner.isCorporation()) { return; //Character Endpoint } //Get Jump Clones CharacterClonesResponse jumpClonesResponse = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { return getClonesApiAuth().getCharacterClonesWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, null, null, null); } }); //Get Active Clone List activeCloneImplants = update(DEFAULT_RETRIES, new EsiHandler>() { @Override public ApiResponse> get() throws ApiException { return getClonesApiAuth().getCharacterImplantsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, null, null, null); } }); //Get Location CharacterLocationResponse characterLocation = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { return getLocationApiAuth().getCharacterLocationWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, null, null, null); } }); Long activeCloneLocationID = RawConverter.toLocationID(characterLocation); owner.setClones(EsiConverter.toClones(jumpClonesResponse, activeCloneImplants, activeCloneLocationID, owner)); } @Override protected void setNextUpdate(Date date) { //Use the assets update times } @Override protected boolean haveAccess() { if (owner.isCorporation()) { return true; //Overwrite the default, so, we don't get errors } else { return owner.isClones() && owner.isImplants(); } } @Override protected RolesEnum[] getRequiredRoles() { return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiContractItemsGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.ContractItemsResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.PublicContractsItemsResponse; public class EsiContractItemsGetter extends AbstractEsiGetter { private final List owners; private static Map> contracts; private static Map> publicContracts; private final static AtomicInteger SIZE = new AtomicInteger(0); private final static AtomicInteger PROGRESS = new AtomicInteger(0); private final static int BATCH_SIZE = 20; private final boolean saveHistory; public EsiContractItemsGetter(UpdateTask updateTask, EsiOwner owner, List owners, boolean saveHistory) { super(updateTask, owner, false, Settings.getNow(), TaskType.CONTRACT_ITEMS); this.owners = owners; this.saveHistory = saveHistory; } public static void reset() { contracts = null; SIZE.set(0); PROGRESS.set(0); } @Override protected void update() throws ApiException { createContracts(owners); if (owner.isCorporation()) { List> updates = splitList(contracts.get(owner.getOwnerID()), BATCH_SIZE); Map> responses = new HashMap<>(); boolean first = true; for (List list : updates) { if (first) { first = false; } else { try { Thread.sleep(10000); } catch (InterruptedException ex) { throw new RuntimeException(ex); } } try { Map> response = updateList(list, DEFAULT_RETRIES, new ListHandler>() { @Override public ApiResponse> get(MyContract t) throws ApiException { return getContractsApiAuth().getCorporationContractItemsWithHttpInfo(SafeConverter.toLong(t.getContractID()), owner.getOwnerID(), COMPATIBILITY_DATE, null, null, null); } }); responses.putAll(response); } catch (ApiException ex) { if (ex.getCode() == 429) { addError("RATE LIMIT 429", "ESI rate limit reached. Contracts will be missing data. Try again in 15 minutes", ex); break; //Ignoring rate limit } else { throw ex; } } PROGRESS.getAndAdd(list.size()); setProgress(SIZE.get(), PROGRESS.get(), 0, 100); } owner.setContracts(EsiConverter.toContractItems(responses, owner, saveHistory)); } else { Map> responses = updateList(contracts.get(owner.getOwnerID()), DEFAULT_RETRIES, new ListHandler>() { @Override public ApiResponse> get(MyContract t) throws ApiException { //((int) , , DATASOURCE, null, null); ApiResponse> response = getContractsApiAuth().getCharacterContractItemsWithHttpInfo(owner.getOwnerID(), SafeConverter.toLong(t.getContractID()), COMPATIBILITY_DATE, null, null, null); PROGRESS.getAndAdd(1); setProgress(SIZE.get(), PROGRESS.get(), 0, 100); return response; } }); owner.setContracts(EsiConverter.toContractItems(responses, owner, saveHistory)); } //Public contracts (Have blueprint info Runs/Me/Te) Map> responses = updatePagedMap(publicContracts.get(owner.getOwnerID()), new PagedListHandler() { @Override protected List get(MyContract contract) throws ApiException { return updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { ApiResponse> response = getContractsApiOpen().getPublicContractsItemsContractIdWithHttpInfo(SafeConverter.toLong(contract.getContractID()), COMPATIBILITY_DATE, page, null, null, null); PROGRESS.getAndAdd(1); setProgress(SIZE.get(), PROGRESS.get(), 0, 100); return response; } }); } }); owner.setContracts(EsiConverter.toContractItemsPublic(responses, owner, saveHistory)); } private static synchronized void createContracts(List owners) { if (contracts == null) { contracts = new HashMap<>(); publicContracts = new HashMap<>(); Set uniqueContacts = new HashSet<>(); Map uniqueOwners = new HashMap<>(); for (EsiOwner esiOwner : owners) { if (!esiOwner.isShowOwner()) { continue; } uniqueOwners.put(esiOwner.getOwnerID(), esiOwner); contracts.put(esiOwner.getOwnerID(), new ArrayList<>()); publicContracts.put(esiOwner.getOwnerID(), new ArrayList<>()); for (Map.Entry> entry : esiOwner.getContracts().entrySet()) { MyContract contract = entry.getKey(); if (contract.isIgnoreContract()) { continue; //Ignore contracts without items } if (entry.getValue() != null && !entry.getValue().isEmpty()) { continue; //Ignore contracts that have been already updated } if (esiOwner.isCorporation() && contract.isDeleted()) { continue; //Ignore deleted corporation contracts } if (!contract.isESI()) { continue; //No longer in ESI } uniqueContacts.add(contract); //Open public contracts if (contract.isPublic() && contract.isOpen()) { publicContracts.get(esiOwner.getOwnerID()).add(contract); SIZE.getAndIncrement(); } } } for (MyContract contract : uniqueContacts) { if (uniqueOwners.containsKey(contract.getIssuerID())) { contracts.get(contract.getIssuerID()).add(contract); SIZE.getAndIncrement(); } else if (uniqueOwners.containsKey(contract.getAssigneeID())) { contracts.get(contract.getAssigneeID()).add(contract); SIZE.getAndIncrement(); } else if (uniqueOwners.containsKey(contract.getAcceptorID())) { contracts.get(contract.getAcceptorID()).add(contract); SIZE.getAndIncrement(); } else if (uniqueOwners.containsKey(contract.getIssuerCorpID())) { //Last resort (Rate limited and access to less contract items) contracts.get(contract.getIssuerCorpID()).add(contract); SIZE.getAndIncrement(); } } } } @Override protected void setNextUpdate(Date date) { //We will never update again... } @Override protected boolean haveAccess() { return owner.isContracts(); } @Override protected RolesEnum[] getRequiredRoles() { return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiContractsGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.List; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterContractsResponse; import net.troja.eve.esi.model.CharacterRolesResponse; import net.troja.eve.esi.model.CorporationContractsResponse; public class EsiContractsGetter extends AbstractEsiGetter { private final boolean saveHistory; public EsiContractsGetter(UpdateTask updateTask, EsiOwner owner, boolean saveHistory) { super(updateTask, owner, false, owner.getContractsNextUpdate(), TaskType.CONTRACTS); this.saveHistory = saveHistory; } @Override protected void update() throws ApiException { if (owner.isCorporation()) { List contracts = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getContractsApiAuth().getCorporationContractsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, page, null, null, null); } }); owner.setContracts(EsiConverter.toContractsCorporation(contracts, owner, saveHistory)); } else { List contracts = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getContractsApiAuth().getCharacterContractsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, page, null, null, null); } }); owner.setContracts(EsiConverter.toContracts(contracts, owner, saveHistory)); } } @Override protected void setNextUpdate(Date date) { owner.setContractsNextUpdate(date); } @Override protected boolean haveAccess() { return owner.isContracts(); } @Override protected CharacterRolesResponse.RolesEnum[] getRequiredRoles() { return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiConverter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyAccountBalance; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyExtraction; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.api.my.MyShip; import net.nikr.eve.jeveasset.data.api.my.MySkill; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.api.raw.RawAccountBalance; import net.nikr.eve.jeveasset.data.api.raw.RawAsset; import net.nikr.eve.jeveasset.data.api.raw.RawBlueprint; import net.nikr.eve.jeveasset.data.api.raw.RawClone; import net.nikr.eve.jeveasset.data.api.raw.RawContract; import net.nikr.eve.jeveasset.data.api.raw.RawContractItem; import net.nikr.eve.jeveasset.data.api.raw.RawExtraction; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob; import net.nikr.eve.jeveasset.data.api.raw.RawJournal; import net.nikr.eve.jeveasset.data.api.raw.RawLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawMining; import net.nikr.eve.jeveasset.data.api.raw.RawNpcStanding; import net.nikr.eve.jeveasset.data.api.raw.RawPublicMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawSkill; import net.nikr.eve.jeveasset.data.api.raw.RawTransaction; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.DataConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.model.CharacterAssetsResponse; import net.troja.eve.esi.model.CharacterBlueprintsResponse; import net.troja.eve.esi.model.CharacterClonesResponse; import net.troja.eve.esi.model.CharacterContractsResponse; import net.troja.eve.esi.model.CharacterIndustryJobsResponse; import net.troja.eve.esi.model.CharacterLocationResponse; import net.troja.eve.esi.model.CharacterLoyaltyPointsResponse; import net.troja.eve.esi.model.CharacterMiningResponse; import net.troja.eve.esi.model.CharacterOrdersHistoryResponse; import net.troja.eve.esi.model.CharacterOrdersResponse; import net.troja.eve.esi.model.CharacterPlanetsResponse; import net.troja.eve.esi.model.CharacterShipResponse; import net.troja.eve.esi.model.StandingsResponse; import net.troja.eve.esi.model.CharacterWalletJournalResponse; import net.troja.eve.esi.model.CharacterWalletTransactionsResponse; import net.troja.eve.esi.model.CorporationAssetsResponse; import net.troja.eve.esi.model.CorporationBlueprintsResponse; import net.troja.eve.esi.model.PlanetPin; import net.troja.eve.esi.model.Skill; import net.troja.eve.esi.model.ContractItemsResponse; import net.troja.eve.esi.model.CorporationContractsResponse; import net.troja.eve.esi.model.CorporationIndustryJobsResponse; import net.troja.eve.esi.model.CorporationMiningExtractionsResponse; import net.troja.eve.esi.model.CorporationMiningObserverResponse; import net.troja.eve.esi.model.CorporationMiningObserversResponse; import net.troja.eve.esi.model.CorporationOrdersHistoryResponse; import net.troja.eve.esi.model.CorporationOrdersResponse; import net.troja.eve.esi.model.CorporationWalletJournalResponse; import net.troja.eve.esi.model.CorporationWalletTransactionsResponse; import net.troja.eve.esi.model.CorporationWalletsResponse; import net.troja.eve.esi.model.DivisionsHangar; import net.troja.eve.esi.model.DivisionsWallet; import net.troja.eve.esi.model.JumpClone; import net.troja.eve.esi.model.MarketRegionOrdersResponse; import net.troja.eve.esi.model.PinContent; import net.troja.eve.esi.model.PublicContractsItemsResponse; public class EsiConverter extends DataConverter { private EsiConverter() { } public static List toAccountBalance(Double responses, OwnerType owner, Integer accountKey) { return convertRawAccountBalance(Collections.singletonList(new RawAccountBalance(responses, accountKey)), owner); } public static List toAccountBalanceCorporation(List responses, OwnerType owner) { List rawAccountBalances = new ArrayList<>(); for (CorporationWalletsResponse response : responses) { rawAccountBalances.add(new RawAccountBalance(response)); } return convertRawAccountBalance(rawAccountBalances, owner); } public static MyShip toActiveShip(CharacterShipResponse shipType, CharacterLocationResponse shipLocation) { return new MyShip(shipType, shipLocation); } public static List toAssets(List responses, OwnerType owner) { List rawAssets = new ArrayList<>(); for (CharacterAssetsResponse response : responses) { rawAssets.add(new RawAsset(response)); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getTypeId())); } return convertRawAssets(rawAssets, owner); } public static List toAssetsCorporation(List responses, OwnerType owner) { List rawAssets = new ArrayList<>(); for (CorporationAssetsResponse response : responses) { rawAssets.add(new RawAsset(response)); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getTypeId())); } return convertRawAssets(rawAssets, owner); } public static MyAsset toAssetsShip(CharacterShipResponse shipType, CharacterLocationResponse shipLocation, OwnerType owner) { return toMyAsset(new RawAsset(shipType, shipLocation), owner, new ArrayList<>()); } public static MyAsset toAssetsPlanetaryInteraction(CharacterPlanetsResponse planet, PlanetPin pin, OwnerType owner) { MyAsset parent = toMyAsset(new RawAsset(planet, pin), owner, new ArrayList<>()); List parents = Collections.singletonList(parent); for (PinContent content : pin.getContents()) { parent.addAsset(toMyAsset(new RawAsset(planet, pin, content), owner, parents)); } return parent; } public static Map toBlueprints(List responses) { Map rawBlueprints = new HashMap<>(); for (CharacterBlueprintsResponse response : responses) { rawBlueprints.put(response.getItemId(), new RawBlueprint(response)); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getTypeId())); } return rawBlueprints; } public static Map toBlueprintsCorporation(List responses) { Map rawBlueprints = new HashMap<>(); for (CorporationBlueprintsResponse response : responses) { rawBlueprints.put(response.getItemId(), new RawBlueprint(response)); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getTypeId())); } return rawBlueprints; } public static Set toIndustryJobs(List responses, OwnerType owner, boolean saveHistory) { List rawIndustryJobs = new ArrayList<>(); for (CharacterIndustryJobsResponse response : responses) { rawIndustryJobs.add(new RawIndustryJob(response)); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getBlueprintTypeId())); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getProductTypeId())); } return convertRawIndustryJobs(rawIndustryJobs, owner, saveHistory); } public static Set toIndustryJobsCorporation(List responses, OwnerType owner, boolean saveHistory) { List rawIndustryJobs = new ArrayList<>(); for (CorporationIndustryJobsResponse response : responses) { rawIndustryJobs.add(new RawIndustryJob(response)); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getBlueprintTypeId())); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getProductTypeId())); } return convertRawIndustryJobs(rawIndustryJobs, owner, saveHistory); } public static Set toJournals(List responses, OwnerType owner, Integer accountKey, boolean saveHistory) { List rawJournals = new ArrayList<>(); for (CharacterWalletJournalResponse response : responses) { rawJournals.add(new RawJournal(response, accountKey)); } return convertRawJournals(rawJournals, owner, saveHistory); } public static Set toJournalsCorporation(List responses, OwnerType owner, Integer accountKey, boolean saveHistory) { List rawJournals = new ArrayList<>(); for (CorporationWalletJournalResponse response : responses) { rawJournals.add(new RawJournal(response, accountKey)); } return convertRawJournals(rawJournals, owner, saveHistory); } public static Map> toContracts(List responses, OwnerType owner, boolean saveHistory) { List rawContracts = new ArrayList<>(); for (CharacterContractsResponse response : responses) { rawContracts.add(new RawContract(response)); } return convertRawContracts(rawContracts, owner, saveHistory); } public static Map> toContractsCorporation(List responses, OwnerType owner, boolean saveHistory) { List rawContracts = new ArrayList<>(); for (CorporationContractsResponse response : responses) { rawContracts.add(new RawContract(response)); } return convertRawContracts(rawContracts, owner, saveHistory); } public static Map> toContractItems(Map> responsess, OwnerType owner, boolean saveHistory) { Map> rawContractItems = new HashMap<>(); for (Map.Entry> entry : responsess.entrySet()) { for (ContractItemsResponse response : entry.getValue()) { List list = rawContractItems.get(entry.getKey()); if (list == null) { list = new ArrayList<>(); rawContractItems.put(entry.getKey(), list); } list.add(new RawContractItem(response)); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getTypeId())); } } return convertRawContractItems(rawContractItems, owner, saveHistory); } public static Map> toContractItemsPublic(Map> responsess, OwnerType owner, boolean saveHistory) { Map> rawContractItems = new HashMap<>(); for (Map.Entry> entry : responsess.entrySet()) { for (PublicContractsItemsResponse response : entry.getValue()) { List list = rawContractItems.get(entry.getKey()); if (list == null) { list = new ArrayList<>(); rawContractItems.put(entry.getKey(), list); } list.add(new RawContractItem(response)); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getTypeId())); } } return convertRawContractItems(rawContractItems, owner, saveHistory); } public static Set toMarketOrders(List responses, List responsesHistory, OwnerType owner, boolean saveHistory) { List rawMarketOrders = new ArrayList<>(); for (CharacterOrdersResponse response : responses) { rawMarketOrders.add(new RawMarketOrder(response)); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getTypeId())); } for (CharacterOrdersHistoryResponse response : responsesHistory) { rawMarketOrders.add(new RawMarketOrder(response)); } return convertRawMarketOrders(rawMarketOrders, owner, saveHistory); } public static Set toMarketOrdersCorporation(List responses, List responsesHistory, OwnerType owner, boolean saveHistory) { List rawMarketOrders = new ArrayList<>(); for (CorporationOrdersResponse response : responses) { rawMarketOrders.add(new RawMarketOrder(response)); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getTypeId())); } for (CorporationOrdersHistoryResponse response : responsesHistory) { rawMarketOrders.add(new RawMarketOrder(response)); } return convertRawMarketOrders(rawMarketOrders, owner, saveHistory); } public static Set toTransaction(List responses, OwnerType owner, Integer accountKey, boolean saveHistory) { List rawTransactions = new ArrayList<>(); for (CharacterWalletTransactionsResponse response : responses) { rawTransactions.add(new RawTransaction(response, accountKey)); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getTypeId())); } return convertRawTransactions(rawTransactions, owner, saveHistory); } public static Set toTransactionCorporation(List responses, OwnerType owner, Integer accountKey, boolean saveHistory) { List rawTransactions = new ArrayList<>(); for (CorporationWalletTransactionsResponse response : responses) { rawTransactions.add(new RawTransaction(response, accountKey)); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getTypeId())); } return convertRawTransactions(rawTransactions, owner, saveHistory); } public static Map toWalletDivisions(List divisionsWallets) { Map divisions = new HashMap<>(); for (DivisionsWallet response : divisionsWallets) { divisions.put(SafeConverter.toInteger(response.getDivision()), response.getName()); } return divisions; } public static Map toAssetDivisions(List divisionsWallets) { Map divisions = new HashMap<>(); for (DivisionsHangar response : divisionsWallets) { divisions.put(SafeConverter.toInteger(response.getDivision()), response.getName()); } return divisions; } public static Map> toPublicMarketOrders(List responses) { Map> marketOrders = new HashMap<>(); for (MarketRegionOrdersResponse response : responses) { RawPublicMarketOrder marketOrder = new RawPublicMarketOrder(response); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getTypeId())); Set set = marketOrders.get(marketOrder.getTypeID()); if (set == null) { set = new HashSet<>(); marketOrders.put(marketOrder.getTypeID(), set); } set.add(marketOrder); } return marketOrders; } public static List toSkills(List responses, OwnerType owner) { List skills = new ArrayList<>(); for (Skill response : responses) { skills.add(new RawSkill(response)); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getSkillId())); } return convertRawSkills(skills, owner); } public static Set toMining(List responses, OwnerType owner, boolean saveHistory) { List mining = new ArrayList<>(); for (CharacterMiningResponse response : responses) { mining.add(new RawMining(response, owner)); ApiIdConverter.updateItem(SafeConverter.toInteger(response.getTypeId())); } return convertRawMining(mining, owner, saveHistory); } public static Set toMining(Map> responses, OwnerType owner, boolean saveHistory) { List mining = new ArrayList<>(); for (Map.Entry> response : responses.entrySet()) { for (CorporationMiningObserverResponse miningObserver : response.getValue()) { mining.add(new RawMining(response.getKey(), miningObserver, owner)); } } return convertRawMining(mining, owner, saveHistory); } public static Set toExtraction(List responses, OwnerType owner, boolean saveHistory) { List extractions = new ArrayList<>(); for (CorporationMiningExtractionsResponse response : responses) { extractions.add(new RawExtraction(response)); } return convertRawExtraction(extractions, owner, saveHistory); } public static List toClones(CharacterClonesResponse responses, List activeCloneImplants, Long activeCloneLocationID, OwnerType owner) { List clones = new ArrayList<>(); clones.add(new RawClone(activeCloneImplants, owner.getOwnerID(), activeCloneLocationID)); for (JumpClone response : responses.getJumpClones()) { clones.add(new RawClone(response)); } return clones; } public static Set toLoyaltyPoints(List responses, OwnerType owner) { Set loyaltyPoints = new HashSet<>(); for (CharacterLoyaltyPointsResponse response : responses) { loyaltyPoints.add(new RawLoyaltyPoints(response)); } return convertMyLoyaltyPoints(loyaltyPoints, owner); } public static Set toNpcStanding(List responses, OwnerType owner) { Set npcStandings = new HashSet<>(); for (StandingsResponse response : responses) { npcStandings.add(new RawNpcStanding(response)); } return convertMyNpcStanding(npcStandings, owner); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiDivisionsGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.CorporationDivisionsResponse; public class EsiDivisionsGetter extends AbstractEsiGetter { public EsiDivisionsGetter(UpdateTask updateTask, EsiOwner owner) { super(updateTask, owner, false, owner.getAssetNextUpdate(), TaskType.DIVISIONS); } @Override protected void update() throws ApiException { if (!owner.isCorporation()) { return; //Character accounts can not get divisions } CorporationDivisionsResponse response = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { return getCorporationApiAuth().getCorporationDivisionsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, null, null, null); } }); owner.setAssetDivisions(EsiConverter.toAssetDivisions(response.getHangar())); owner.setWalletDivisions(EsiConverter.toWalletDivisions(response.getWallet())); } @Override protected boolean haveAccess() { if (owner.isCorporation()) { return owner.isDivisions(); } else { return true; //Overwrite the default, so, we don't get errors } } @Override protected void setNextUpdate(Date date) { //Nope } @Override protected RolesEnum[] getRequiredRoles() { RolesEnum[] roles = {RolesEnum.DIRECTOR}; return roles; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiFactionWarfareGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.FactionWarfareSystemsResponse; import net.troja.eve.esi.model.FactionsResponse; public class EsiFactionWarfareGetter extends AbstractEsiGetter { public EsiFactionWarfareGetter(UpdateTask updateTask) { super(updateTask, null, false, Settings.get().getFactionWarfareNextUpdate(), TaskType.FACTION_WARFARE); } @Override protected void update() throws ApiException { List factionWarfareSystems = update(DEFAULT_RETRIES, new EsiHandler>() { @Override public ApiResponse> get() throws ApiException { return getFactionWarfareApiOpen().getFactionWarfareSystemsWithHttpInfo(COMPATIBILITY_DATE, null, null, null); } }); List factions = update(DEFAULT_RETRIES, new EsiHandler>() { @Override public ApiResponse> get() throws ApiException { return getUniverseApiOpen().getFactionsWithHttpInfo(COMPATIBILITY_DATE, null, null, null); } }); Map factionNames = new HashMap<>(); for (FactionsResponse faction : factions) { factionNames.put(faction.getFactionId(), faction.getName()); } Map systemOwners = new HashMap<>(); for (FactionWarfareSystemsResponse system : factionWarfareSystems) { systemOwners.put(system.getSolarSystemId(), factionNames.get(system.getOccupierFactionId())); } Settings.get().setFactionWarfareSystemOwners(systemOwners); } @Override protected void setNextUpdate(Date date) { Settings.get().setFactionWarfareNextUpdate(date); } @Override protected boolean haveAccess() { return true; } @Override protected RolesEnum[] getRequiredRoles() { return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiIndustryJobsGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterIndustryJobsResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.CorporationIndustryJobsResponse; public class EsiIndustryJobsGetter extends AbstractEsiGetter { private final boolean saveHistory; public EsiIndustryJobsGetter(UpdateTask updateTask, EsiOwner owner, boolean saveHistory) { super(updateTask, owner, false, owner.getIndustryJobsNextUpdate(), TaskType.INDUSTRY_JOBS); this.saveHistory = saveHistory; } @Override protected void update() throws ApiException { if (owner.isCorporation()) { List industryJobs = new ArrayList<>(); //Completed List completed = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getIndustryApiAuth().getCorporationIndustryJobsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, true, page, null, null, null); } }); industryJobs.addAll(completed); //Not Completed List incomplated = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getIndustryApiAuth().getCorporationIndustryJobsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, false, page, null, null, null); } }); industryJobs.addAll(incomplated); owner.setIndustryJobs(EsiConverter.toIndustryJobsCorporation(industryJobs, owner, saveHistory)); } else { Set completed = new HashSet<>(); completed.add(true); completed.add(false); Map> updateList = updateList(completed, DEFAULT_RETRIES, new ListHandler>() { @Override protected ApiResponse> get(Boolean includeCompleted) throws ApiException { return getIndustryApiAuth().getCharacterIndustryJobsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, includeCompleted, null, null, null); } }); List industryJobs = new ArrayList<>(); for (List list : updateList.values()) { industryJobs.addAll(list); } owner.setIndustryJobs(EsiConverter.toIndustryJobs(industryJobs, owner, saveHistory)); } } @Override protected void setNextUpdate(Date date) { owner.setIndustryJobsNextUpdate(date); } @Override protected boolean haveAccess() { return owner.isIndustryJobs(); } @Override protected RolesEnum[] getRequiredRoles() { RolesEnum[] roles = {RolesEnum.DIRECTOR, RolesEnum.FACTORY_MANAGER}; return roles; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiItemsGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.settings.Settings; import static net.nikr.eve.jeveasset.io.esi.AbstractEsiGetter.getMarketApiOpen; import net.nikr.eve.jeveasset.io.local.ItemsReader; import net.nikr.eve.jeveasset.io.online.EveRefGetter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CategoryResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.DogmaAttribute; import net.troja.eve.esi.model.DogmaEffect; import net.troja.eve.esi.model.GroupResponse; import net.troja.eve.esi.model.MarketGroupResponse; import net.troja.eve.esi.model.TypeResponse; public class EsiItemsGetter extends AbstractEsiGetter { /** * Change ESI_ITEM_VERSION to force items_updates.xml items to be updated again. * ChangeLog * 1.2.0: * Updated with EveRef type and blueprint data */ public final static String ESI_ITEM_VERSION = "1.2.0"; public final static String ESI_ITEM_EMPTY = "EMPTY"; private final static Map GROUPS_CACHE = new HashMap<>(); private final static Map CATEGORY_CACHE = new HashMap<>(); private final static Map MARKET_GROUP_CACHE = new HashMap<>(); public final static long BASE_PRICE_DEFAULT = -1; public final static int PRODUCT_TYPE_ID_DEFAULT = 0; public final static int PRODUCT_QUANTITY_DEFAULT = 1; private final int typeID; private Item item = null; public EsiItemsGetter(int typeID) { super(null, null, true, Settings.getNow(), TaskType.ITEM_TYPES); this.typeID = typeID; } @Override protected void update() throws ApiException { //Types TypeResponse typeResponse = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { return getUniverseApiOpen().getTypeWithHttpInfo((long) typeID, COMPATIBILITY_DATE, null, null, null); } }); //Groups final long groupID = typeResponse.getGroupId(); GroupResponse groupResponse = GROUPS_CACHE.get(groupID); if (groupResponse == null) { groupResponse = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { return getUniverseApiOpen().getGroupWithHttpInfo(groupID, COMPATIBILITY_DATE, null, null, null); } }); GROUPS_CACHE.put(groupID, groupResponse); } final long categoryID = groupResponse.getCategoryId(); //Categories CategoryResponse categoryResponse = CATEGORY_CACHE.get(categoryID); if (categoryResponse == null) { categoryResponse = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { return getUniverseApiOpen().getCategoryWithHttpInfo(categoryID, COMPATIBILITY_DATE, null, null, null); } }); CATEGORY_CACHE.put(categoryID, categoryResponse); } //Market Groups MarketGroupResponse marketGroupResponse = null; Long marketGroupID = typeResponse.getMarketGroupId(); if (marketGroupID != null) { marketGroupResponse = MARKET_GROUP_CACHE.get(marketGroupID); if (marketGroupResponse == null) { marketGroupResponse = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { return getMarketApiOpen().getMarketGroupWithHttpInfo(marketGroupID, COMPATIBILITY_DATE, null, null, null); } }); MARKET_GROUP_CACHE.put(marketGroupID, marketGroupResponse); } } String name = typeResponse.getName() .replaceAll(" +", " ") //Replace 2 or more spaces .replace("\t", " ") //Tab .replace("„", "\"") //Index .replace("“", "\"") //Set transmit state .replace("”", "\"") //Cancel character .replace("‘", "'") //Private use one .replace("’", "'") //Private use two .replace("`", "'") //Grave accent .replace("´", "'") //Acute accent .replace("–", "-") //En dash .replace("‐", "-") //Hyphen .replace("‑", "-") //Non-breaking hyphen .replace("‒", "-") //Figure dash .replace("—", "-") //Em dash .trim(); String group = groupResponse.getName(); String category = categoryResponse.getName(); long basePrice = BASE_PRICE_DEFAULT; //Base Price float volume = getNotNull(typeResponse.getVolume()); float packagedVolume = getNotNull(typeResponse.getPackagedVolume()); float capacity = getNotNull(typeResponse.getCapacity()); //Meta / Charge Sire Integer metaGroupID = null; int metaLevel = 0; List dogmaAttributes = typeResponse.getDogmaAttributes(); Integer charge = null; if (dogmaAttributes != null) { for (DogmaAttribute attribute : dogmaAttributes) { if (attribute.getAttributeId() == 1692) { //1692 = meta group metaGroupID = attribute.getValue().intValue(); } if (attribute.getAttributeId() == 633) { //633 = meta level metaLevel = attribute.getValue().intValue(); } if (attribute.getAttributeId() == 128) { //128 = The size of the charges that can fit in the turret/whatever. charge = attribute.getValue().intValue(); } } } //Tech Level final String techLevel = getTechLevel(metaGroupID); boolean marketGroup; if (marketGroupResponse != null) { marketGroup = marketGroupResponse.getTypes().contains(SafeConverter.toLong(typeID)); } else { marketGroup = false; } int portion = SafeConverter.toInteger(typeResponse.getPortionSize()); int productTypeID = PRODUCT_TYPE_ID_DEFAULT; //Product int productQuantity = PRODUCT_QUANTITY_DEFAULT; //Product Quantity //Slot String slot = null; List dogmaEffects = typeResponse.getDogmaEffects(); if (dogmaEffects != null) { for (DogmaEffect attribute : dogmaEffects) { if (attribute.getIsDefault()) { continue; } if (attribute.getEffectId() == 11) { //11 = Requires a low power slot slot = "Low"; break; } if (attribute.getEffectId() == 12) { //12 = Requires a high power slot slot = "High"; break; } if (attribute.getEffectId() == 13) { //13 = Requires a medium power slot slot = "Medium"; break; } if (attribute.getEffectId() == 2663) { //2663 = Must be installed into an open rig slot slot = "Rig"; break; } if (attribute.getEffectId() == 3772) { //3772 = Must be installed into an available subsystem slot on a Tech III ship. slot = "Subsystem"; break; } } } //Charge Size String chargeSize = ItemsReader.getChargeSize(charge); //Item item = new Item(typeID, name, group, category, basePrice, volume, packagedVolume, capacity, metaLevel, techLevel, marketGroup, portion, productTypeID, productQuantity, slot, chargeSize, ESI_ITEM_VERSION); //EveRef Update item = EveRefGetter.getItem(item); //Update from EveRef } private float getNotNull(Double d) { if (d != null) { return SafeConverter.toFloat(d); } else { return 0f; } } public static String getTechLevel(Integer metaGroupID) { if (metaGroupID == null) { return "Tech I"; } switch (metaGroupID) { case 1: return "Tech I"; case 2: return "Tech II"; case 3: return "Storyline"; case 4: return "Faction"; case 5: return "Officer"; case 6: return "Deadspace"; /* //No longer in use case 7: return "Frigates"; case 8: return "Elite Frigates"; case 9: return "Commander Frigates"; case 10: return "Destroyer"; case 11: return "Cruiser"; case 12: return "Elite Cruiser"; case 13: return "Commander Cruiser"; */ case 14: return "Tech III"; case 15: return "Abyssal"; case 17: return "Premium"; case 19: return "Limited Time"; case 52: return "Faction"; //Structure Faction case 53: return "Tech II"; //Structure Tech II case 54: return "Tech I"; //Structure Tech I default: return "Tech I"; } } public Item getItem() { return item; } @Override protected void setNextUpdate(Date date) { //Do Nothing } @Override protected boolean haveAccess() { return true; //Only use public endpoints } @Override protected RolesEnum[] getRequiredRoles() { return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiJournalGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.List; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.CharacterWalletJournalResponse; import net.troja.eve.esi.model.CorporationWalletJournalResponse; public class EsiJournalGetter extends AbstractEsiGetter { private final boolean saveHistory; public EsiJournalGetter(UpdateTask updateTask, EsiOwner owner, boolean saveHistory) { super(updateTask, owner, false, owner.getJournalNextUpdate(), TaskType.JOURNAL); this.saveHistory = saveHistory; } @Override protected void update() throws ApiException { if (owner.isCorporation()) { for (int i = 1; i < 8; i++) { //Division 1-7 final int division = i; List journals = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { //((int) , division, DATASOURCE, null, page, null); return getWalletApiAuth().getCorporationWalletJournalWithHttpInfo(owner.getOwnerID(), SafeConverter.toLong(division), COMPATIBILITY_DATE, page, null, null, null); } }); int fixedDivision = division + 999; owner.setJournal(EsiConverter.toJournalsCorporation(journals, owner, fixedDivision, saveHistory)); } } else { List journals = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getWalletApiAuth().getCharacterWalletJournalWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, page, null, null, null); } }); owner.setJournal(EsiConverter.toJournals(journals, owner, 1000, saveHistory)); } } @Override protected void setNextUpdate(Date date) { owner.setJournalNextUpdate(date); } @Override protected boolean haveAccess() { return owner.isJournal(); } @Override protected RolesEnum[] getRequiredRoles() { RolesEnum[] roles = {RolesEnum.DIRECTOR, RolesEnum.ACCOUNTANT, RolesEnum.JUNIOR_ACCOUNTANT}; return roles; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiLocationsGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.settings.Citadel; import net.nikr.eve.jeveasset.data.settings.Citadel.CitadelSource; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.io.online.CitadelGetter; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.AssetsNamesResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; public class EsiLocationsGetter extends AbstractEsiGetter { public EsiLocationsGetter(UpdateTask updateTask, EsiOwner owner) { super(updateTask, owner, false, owner.getLocationsNextUpdate(), TaskType.LOCATIONS); } @Override protected void update() throws ApiException { Map iDs = getIDs(owner); if (owner.isCorporation()) { Map, List> responses = updateList(splitSet(iDs.keySet(), LOCATIONS_BATCH_SIZE), DEFAULT_RETRIES, new ListHandler, List>() { @Override public ApiResponse> get(Set t) throws ApiException { return getAssetsApiAuth().postCorporationAssetsNamesWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, t, null, null, null); } }); try { Settings.lock("Ship/Container Names"); for (Map.Entry, List> entry : responses.entrySet()) { for (AssetsNamesResponse response : entry.getValue()) { final long itemID = response.getItemId(); final String eveName = response.getName(); if (!eveName.isEmpty()) { //Set name Settings.get().getEveNames().put(itemID, eveName); MyAsset asset = iDs.get(itemID); if (asset.getItem().getCategory().equals(Item.CATEGORY_STRUCTURE)) { CitadelGetter.set(new Citadel(asset.getItemID(), eveName, asset.getLocationID(), false, true, CitadelSource.ESI_LOCATIONS)); } } else { //Remove name (Empty) Settings.get().getEveNames().remove(itemID); } } } } finally { Settings.unlock("Ship/Container Names"); } } else { Map, List> responses = updateList(splitSet(iDs.keySet(), LOCATIONS_BATCH_SIZE), DEFAULT_RETRIES, new ListHandler, List>() { @Override public ApiResponse> get(Set t) throws ApiException { //((int) , t, DATASOURCE, null); return getAssetsApiAuth().postCharacterAssetsNamesWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, t, null, null, null); } }); try { Settings.lock("Ship/Container Names"); for (Map.Entry, List> entry : responses.entrySet()) { for (AssetsNamesResponse response : entry.getValue()) { final long itemID = response.getItemId(); final String eveName = response.getName(); if (!eveName.isEmpty()) { //Set name Settings.get().getEveNames().put(itemID, eveName); MyAsset asset = iDs.get(itemID); if (asset.getItem().getCategory().equals(Item.CATEGORY_STRUCTURE)) { CitadelGetter.set(new Citadel(asset.getItemID(), eveName, asset.getLocationID(), false, true, CitadelSource.ESI_LOCATIONS)); } } else { //Remove name (Empty) Settings.get().getEveNames().remove(itemID); } } } } finally { Settings.unlock("Ship/Container Names"); } } } @Override protected void setNextUpdate(Date date) { owner.setLocationsNextUpdate(date); } @Override protected boolean haveAccess() { return owner.isLocations(); } @Override protected RolesEnum[] getRequiredRoles() { RolesEnum[] roles = {RolesEnum.DIRECTOR}; return roles; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiLoyaltyPointsGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.List; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterLoyaltyPointsResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; public class EsiLoyaltyPointsGetter extends AbstractEsiGetter { public EsiLoyaltyPointsGetter(UpdateTask updateTask, EsiOwner owner) { super(updateTask, owner, false, owner.getLoyaltyPointsNextUpdate(), TaskType.LOYALTY_POINTS); } @Override protected void update() throws ApiException { List response = update(DEFAULT_RETRIES, new EsiHandler>() { @Override public ApiResponse> get() throws ApiException { return getLoyaltyApiAuth().getCharacterLoyaltyPointsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, null, null, null); } }); owner.setLoyaltyPoints(EsiConverter.toLoyaltyPoints(response, owner)); } @Override protected void setNextUpdate(Date date) { owner.setLoyaltyPointsNextUpdate(date); } @Override protected boolean haveAccess() { return owner.isLoyaltyPoints(); } @Override protected RolesEnum[] getRequiredRoles() { return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiManufacturingPrices.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.data.sde.IndustryMaterial; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import static net.nikr.eve.jeveasset.io.esi.AbstractEsiGetter.getIndustryApiOpen; import static net.nikr.eve.jeveasset.io.esi.AbstractEsiGetter.getMarketApiOpen; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.IndustrySystemsResponse; import net.troja.eve.esi.model.MarketPricesResponse; import net.troja.eve.esi.model.SystemCostIndice; public class EsiManufacturingPrices extends AbstractEsiGetter { public EsiManufacturingPrices(UpdateTask updateTask) { super(updateTask, null, false, Settings.get().getManufacturingSettings().getNextUpdate(), TaskType.MANUFACTURING_PRICES); } @Override protected void update() throws ApiException { //Manufacturing Base Cost List priceResponses = update(DEFAULT_RETRIES, new EsiHandler>() { @Override public ApiResponse> get() throws ApiException { return getMarketApiOpen().getMarketPricesWithHttpInfo(COMPATIBILITY_DATE, null, null, null); } }); Map prices = new HashMap<>(); for (MarketPricesResponse price : priceResponses) { prices.put(SafeConverter.toInteger(price.getTypeId()), price); } Map manufacturingPrices = new HashMap<>(); for (Item item : StaticData.get().getItems().values()) { int productTypeID = item.getProductTypeID(); if (item.getManufacturingMaterials().isEmpty() || productTypeID == 0) { continue; } double price = getPrice(prices, item); manufacturingPrices.put(productTypeID, price); manufacturingPrices.put(item.getTypeID(), price); } Settings.get().getManufacturingSettings().setPrices(manufacturingPrices); //System Indexes List systemResponses = update(DEFAULT_RETRIES, new EsiHandler>() { @Override public ApiResponse> get() throws ApiException { return getIndustryApiOpen().getIndustrySystemsWithHttpInfo(COMPATIBILITY_DATE, null, null, null); } }); Map manufacturingSystems = new HashMap<>(); for (IndustrySystemsResponse system : systemResponses) { for (SystemCostIndice costIndice : system.getCostIndices()) { switch (costIndice.getActivity()) { case MANUFACTURING: manufacturingSystems.put(SafeConverter.toInteger(system.getSolarSystemId()), SafeConverter.toFloat(costIndice.getCostIndex())); break; } } } Settings.get().getManufacturingSettings().setSystems(manufacturingSystems); } @Override protected void setNextUpdate(Date date) { Settings.get().getManufacturingSettings().setNextUpdate(date); } @Override protected boolean haveAccess() { return true; //Public } @Override protected RolesEnum[] getRequiredRoles() { return null; //Public } private double getPrice(Map prices, Item item) { double price = 0; for (IndustryMaterial material : item.getManufacturingMaterials()) { MarketPricesResponse response = prices.get(material.getTypeID()); if (response == null) { Item deeper = ApiIdConverter.getItem(material.getTypeID()); System.out.println(item.getTypeName() + " does not have a price for: " + deeper.getTypeName()); //price = price + getPrice(prices, deeper); continue; } double adjustedPrice = response.getAdjustedPrice(); int quantity = material.getQuantity(); price = price + (adjustedPrice * quantity); } return price; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiMarketOrdersGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.List; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterOrdersHistoryResponse; import net.troja.eve.esi.model.CharacterOrdersResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.CorporationOrdersHistoryResponse; import net.troja.eve.esi.model.CorporationOrdersResponse; public class EsiMarketOrdersGetter extends AbstractEsiGetter { private final boolean saveHistory; public EsiMarketOrdersGetter(UpdateTask updateTask, EsiOwner owner, boolean saveHistory) { super(updateTask, owner, false, owner.getMarketOrdersNextUpdate(), TaskType.MARKET_ORDERS); this.saveHistory = saveHistory; } @Override protected void update() throws ApiException { if (owner.isCorporation()) { List marketOrders = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getMarketApiAuth().getCorporationOrdersWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, page, null, null, null); } }); List marketOrdersHistory = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getMarketApiAuth().getCorporationOrdersHistoryWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, page, null, null, null); } }); owner.setMarketOrders(EsiConverter.toMarketOrdersCorporation(marketOrders, marketOrdersHistory, owner, saveHistory)); } else { List marketOrders = update(DEFAULT_RETRIES, new EsiHandler>() { @Override public ApiResponse> get() throws ApiException { return getMarketApiAuth().getCharacterOrdersWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, null, null, null); } }); List marketOrdersHistory = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getMarketApiAuth().getCharacterOrdersHistoryWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, page, null, null, null); } }); owner.setMarketOrders(EsiConverter.toMarketOrders(marketOrders, marketOrdersHistory, owner, saveHistory)); } } @Override protected void setNextUpdate(Date date) { owner.setMarketOrdersNextUpdate(date); } @Override protected boolean haveAccess() { return owner.isMarketOrders(); } @Override protected RolesEnum[] getRequiredRoles() { RolesEnum[] roles = {RolesEnum.DIRECTOR, RolesEnum.ACCOUNTANT, RolesEnum.TRADER}; return roles; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiMiningGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.Citadel; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import static net.nikr.eve.jeveasset.io.esi.AbstractEsiGetter.DEFAULT_RETRIES; import net.nikr.eve.jeveasset.io.online.CitadelGetter; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterMiningResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.CorporationMiningExtractionsResponse; import net.troja.eve.esi.model.CorporationMiningObserverResponse; import net.troja.eve.esi.model.CorporationMiningObserversResponse; import net.troja.eve.esi.model.MoonResponse; public class EsiMiningGetter extends AbstractEsiGetter { private final boolean saveHistory; public EsiMiningGetter(UpdateTask updateTask, EsiOwner owner, boolean saveHistory) { super(updateTask, owner, false, owner.getMiningNextUpdate(), TaskType.MINING); this.saveHistory = saveHistory; } @Override protected void update() throws ApiException { if (owner.isCorporation()) { //Moon Extractions List extractions = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getIndustryApiAuth().getCorporationMiningExtractionsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, page, null, null, null); } }); //Moon Locations Set moonIDs = new HashSet<>(); for (CorporationMiningExtractionsResponse response : extractions) { //For each planet Long planetID = response.getMoonId(); MyLocation location = ApiIdConverter.getLocation(SafeConverter.toInteger(planetID)); if (location.isEmpty()) { moonIDs.add(planetID); } } Map locationResponses = updateList(moonIDs, DEFAULT_RETRIES, new ListHandler() { @Override protected ApiResponse get(Long planetID) throws ApiException { //MoonsMoonIdWithHttpInfo(, DATASOURCE, null); return getUniverseApiOpen().getMoonWithHttpInfo(planetID, COMPATIBILITY_DATE, null, null, null); } }); List citadels = new ArrayList<>(); for (MoonResponse moon : locationResponses.values()) { Citadel citadel = ApiIdConverter.getCitadel(moon); if (citadel != null) { citadels.add(citadel); } } CitadelGetter.set(citadels); owner.setExtractions(EsiConverter.toExtraction(extractions, owner, saveHistory)); //Must be after the moon location update //Mining Ledger List observers = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getIndustryApiAuth().getCorporationMiningObserversWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, page, null, null, null); } }); Map> miningObservers = updatePagedMap(observers, new PagedListHandler() { @Override protected List get(CorporationMiningObserversResponse observer) throws ApiException { return updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getIndustryApiAuth().getCorporationMiningObserverWithHttpInfo(owner.getOwnerID(), observer.getObserverId(), COMPATIBILITY_DATE, page, null, null, null); } }); } }); owner.setMining(EsiConverter.toMining(miningObservers, owner, true)); } else { List responses = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getIndustryApiAuth().getCharacterMiningWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, page, null, null, null); } }); owner.setMining(EsiConverter.toMining(responses, owner, saveHistory)); } } @Override protected void setNextUpdate(Date date) { owner.setMiningNextUpdate(date); } @Override protected boolean haveAccess() { return owner.isMining(); } @Override protected RolesEnum[] getRequiredRoles() { RolesEnum[] roles = {RolesEnum.DIRECTOR, RolesEnum.ACCOUNTANT, RolesEnum.STATION_MANAGER}; return roles; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiNameGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.gui.shared.Updatable; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.NamesResponse; public class EsiNameGetter extends AbstractEsiGetter { private static final long ONE_DAY = 1000 * 60 * 60 * 24; private final List ownerTypes; public EsiNameGetter(UpdateTask updateTask, List ownerTypes) { super(updateTask, null, false, Settings.getNow(), TaskType.OWNER_ID_TO_NAME); this.ownerTypes = ownerTypes; } @Override protected void update() throws ApiException { Set ids = getOwnerIDs(ownerTypes); Map, List> responses = updateList(splitSet(ids, UNIVERSE_BATCH_SIZE), DEFAULT_RETRIES, new ListHandler, List>() { @Override public ApiResponse> get(Set t) throws ApiException { try { return getUniverseApiOpen().postNamesWithHttpInfo(COMPATIBILITY_DATE, t, null, null, null); } catch (ApiException ex) { if (ex.getCode() == 404 && ex.getResponseBody().toLowerCase().contains("ensure all ids are valid before resolving")) { handleHeaders(ex); return null; //Ignore this error we will use another endpoint instead } else { throw ex; } } } }); Set retries = new HashSet<>(ids); for (Map.Entry, List> entry : responses.entrySet()) { for (NamesResponse lookup : entry.getValue()) { Settings.get().getOwners().put((long)lookup.getId(), lookup.getName()); } retries.removeAll(entry.getKey()); } Map, List> retryResponses = updateList(splitSet(retries, 1), DEFAULT_RETRIES, new ListHandler, List>() { @Override public ApiResponse> get(Set t) throws ApiException { try { return getUniverseApiOpen().postNamesWithHttpInfo(COMPATIBILITY_DATE, t, null, null, null); } catch (ApiException ex) { if (ex.getCode() == 404 && ex.getResponseBody().toLowerCase().contains("ensure all ids are valid before resolving")) { handleHeaders(ex); return null; //Ignore this error we will use another endpoint instead } else { throw ex; } } } }); int count = 30; for (Map.Entry, List> entry : retryResponses.entrySet()) { for (NamesResponse lookup : entry.getValue()) { Settings.get().getOwners().put((long)lookup.getId(), lookup.getName()); Date date = new Date(System.currentTimeMillis() + (ONE_DAY * count)); count--; if (count < 1) { count = 30; } Settings.get().getOwnersNextUpdate().put(lookup.getId(), date); } } } private Set getOwnerIDs(List ownerTypes) { Set list = new HashSet<>(); for (OwnerType ownerType : ownerTypes) { addOwnerID(list, ownerType.getOwnerID()); for (MyIndustryJob myIndustryJob : ownerType.getIndustryJobs()) { addOwnerID(list, myIndustryJob.getInstallerID()); addOwnerID(list, myIndustryJob.getCompletedCharacterID()); } for (MyMarketOrder marketOrder : ownerType.getMarketOrders()) { addOwnerID(list, marketOrder.getIssuedBy()); } for (MyContract contract : ownerType.getContracts().keySet()) { addOwnerID(list, contract.getAcceptorID()); addOwnerID(list, contract.getAssigneeID()); addOwnerID(list, contract.getIssuerCorpID()); addOwnerID(list, contract.getIssuerID()); } for (MyTransaction transaction : ownerType.getTransactions()) { addOwnerID(list, transaction.getClientID()); } for (MyJournal journal : ownerType.getJournal()) { addOwnerID(list, journal.getFirstPartyID()); addOwnerID(list, journal.getSecondPartyID()); ContextType contextType = journal.getContextType(); if (contextType == ContextType.ALLIANCE_ID || contextType == ContextType.CHARACTER_ID || contextType == ContextType.CORPORATION_ID ) { addOwnerID(list, journal.getContextID()); } } for (MyLoyaltyPoints loyaltyPoints : ownerType.getLoyaltyPoints()) { addOwnerID(list, loyaltyPoints.getCorporationID()); } for (MyNpcStanding npcStanding : ownerType.getNpcStanding()) { addOwnerID(list, npcStanding.getFromID()); addOwnerID(list, npcStanding.getCorporationID()); addOwnerID(list, npcStanding.getFactionID()); } for (MyMining mining : ownerType.getMining()) { addOwnerID(list, mining.getCharacterID()); addOwnerID(list, mining.getCorporationID()); } } return list; } private void addOwnerID(Set list, Number number) { //Ignore null if (number == null) { return; } //Ignore Locations if (!ApiIdConverter.getLocation(number.longValue()).isEmpty()) { return; } //Next Update Date nextUpdate = Settings.get().getOwnersNextUpdate().get(number.longValue()); if (nextUpdate != null && !Updatable.isUpdatable(nextUpdate)) { return; } long l = number.longValue(); if (l >= 100) { list.add(l); } } @Override protected void setNextUpdate(Date date) { } @Override protected boolean haveAccess() { return true; } @Override protected RolesEnum[] getRequiredRoles() { return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiNpcStandingGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.List; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.StandingsResponse; public class EsiNpcStandingGetter extends AbstractEsiGetter { public EsiNpcStandingGetter(UpdateTask updateTask, EsiOwner owner) { super(updateTask, owner, false, owner.getNpcStandingNextUpdate(), TaskType.NPC_STANDING); } @Override protected void update() throws ApiException { if (owner.isCorporation()) { List response = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return getCorporationApiAuth().getCorporationStandingsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, page, null, null, null); } }); owner.setNpcStanding(EsiConverter.toNpcStanding(response, owner)); } else { List response = update(DEFAULT_RETRIES, new EsiHandler>() { @Override public ApiResponse> get() throws ApiException { return getCharacterApiAuth().getCharacterStandingsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, null, null, null); } }); owner.setNpcStanding(EsiConverter.toNpcStanding(response, owner)); } } @Override protected void setNextUpdate(Date date) { owner.setNpcStandingNextUpdate(date); } @Override protected boolean haveAccess() { return owner.isNpcStanding(); } @Override protected RolesEnum[] getRequiredRoles() { return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiOwnerGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Collections; import java.util.Date; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.io.shared.AccountAdder; import net.troja.eve.esi.ApiClientBuilder; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.auth.JWT; import net.troja.eve.esi.auth.OAuth; import net.troja.eve.esi.model.CharacterAffiliationResponse; import net.troja.eve.esi.model.CharacterRolesResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.NamesResponse; public class EsiOwnerGetter extends AbstractEsiGetter implements AccountAdder{ private static final long CACHE_TIMER = 1 * 60 * 60 * 1000L; // 1 hour (hours*min*sec*ms) private boolean wrongEntry = false; private final Date nextUpdate; public EsiOwnerGetter(EsiOwner owner, boolean forceUpdate) { this(null, owner, forceUpdate); } public EsiOwnerGetter(UpdateTask updateTask, EsiOwner owner) { this(updateTask, owner, owner.getCorporationName() == null); } private EsiOwnerGetter(UpdateTask updateTask, EsiOwner owner, boolean forceUpdate) { super(updateTask, owner, forceUpdate, owner.getAccountNextUpdate(), TaskType.OWNER); nextUpdate = new Date(new Date().getTime() + CACHE_TIMER); } @Override protected void update() throws ApiException { //characterID OAuth auth = (OAuth) owner.getApiClient().getAuthentication(ApiClientBuilder.AUTHENTICATION); JWT jwt = auth.getJWT(); if (jwt == null) { addError("INVALID AUTHORIZATION (JWT)", "Account Authorization Invalid\r\n(Fix: Options > Accounts... > Edit the account)", null); owner.setInvalid(true); return; } JWT.Payload payload = jwt.getPayload(); if (payload == null) { addError("INVALID AUTHORIZATION (PAYLOAD)", "Account Authorization Invalid\r\n(Fix: Options > Accounts... > Edit the account)", null); owner.setInvalid(true); return; } Set roles = EnumSet.noneOf(RolesEnum.class); Long characterID = payload.getCharacterID(); //CorporationID List affiliationResponse = update(DEFAULT_RETRIES, new EsiHandler>() { @Override public ApiResponse> get() throws ApiException { return getCharacterApiOpen().postCharactersAffiliationWithHttpInfo(COMPATIBILITY_DATE, Collections.singleton(characterID), null, null, null); } }); if (affiliationResponse.isEmpty()) { addError("INVALID AUTHORIZATION (AFFILIATION)", "Account Authorization Invalid\r\n(Fix: Options > Accounts... > Edit the account)", null); owner.setInvalid(true); return; } Long corporationID = affiliationResponse.get(0).getCorporationId(); //IDs to Names Set ids = new HashSet<>(); ids.add(characterID); ids.add(corporationID); List namesResponse = update(DEFAULT_RETRIES, new EsiHandler>() { @Override public ApiResponse> get() throws ApiException { //UniverseNamesWithHttpInfo(, DATASOURCE); return getUniverseApiOpen().postNamesWithHttpInfo(COMPATIBILITY_DATE, ids, null, null, null); } }); String characterName = null; String corporationName = null; for (NamesResponse response : namesResponse) { if (characterID.equals(response.getId())) { characterName = response.getName(); } else if (corporationID.equals(response.getId())) { corporationName = response.getName(); } } if (characterName == null || corporationName == null) { addError("INVALID AUTHORIZATION (NAMES)", "Account Authorization Invalid\r\n(Fix: Options > Accounts... > Edit the account)", null); owner.setInvalid(true); return; } //Roles boolean isCorporation = EsiScopes.CORPORATION_ROLES.isInScope(payload.getScopes()); if (isCorporation) { //Corporation //Updated Character Roles CharacterRolesResponse characterRolesResponse = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { return getCharacterApiAuth().getCharacterRolesWithHttpInfo(characterID, COMPATIBILITY_DATE, null, null, null); } }); roles.addAll(characterRolesResponse.getRoles()); } if (((!isCorporation && characterID != owner.getOwnerID()) || (isCorporation && corporationID != owner.getOwnerID())) && owner.getOwnerID() != 0) { addError(null, "Wrong Entry", null); wrongEntry = true; return; } //Update owner owner.setScopes(payload.getScopes()); owner.setRoles(roles); owner.setCorporationName(corporationName); if (owner.isCorporation()) { owner.setOwnerID(corporationID); owner.setOwnerName(corporationName); } else { owner.setOwnerID(payload.getCharacterID()); owner.setOwnerName(characterName); } if (isPrivilegesLimited()) { addWarning("LIMITED ACCOUNT", "Limited account data access\r\n(Fix: Options > Accounts... > Edit)"); setError(null); } setNextUpdateInner(nextUpdate); } @Override protected void setNextUpdate(Date date) { if (date.after(owner.getAccountNextUpdate())) { owner.setAccountNextUpdate(date); } } @Override protected boolean haveAccess() { return true; //Always update accounts } @Override public boolean isPrivilegesLimited() { return owner.isPrivilegesLimited(); } @Override public boolean isPrivilegesInvalid() { return owner.isPrivilegesInvalid(); } @Override public boolean isInvalid() { return false; } @Override public boolean isWrongEntry() { return wrongEntry; } @Override protected RolesEnum[] getRequiredRoles() { return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiPlanetaryInteractionGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.ArrayList; import java.util.Date; import java.util.List; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.settings.Citadel; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.io.online.CitadelGetter; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterPlanetResponse; import net.troja.eve.esi.model.PlanetPin; import net.troja.eve.esi.model.CharacterPlanetsResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.PlanetResponse; public class EsiPlanetaryInteractionGetter extends AbstractEsiGetter { public EsiPlanetaryInteractionGetter(UpdateTask updateTask, EsiOwner esiOwner, Date assetNextUpdate) { super(updateTask, esiOwner, false, assetNextUpdate, TaskType.PLANETARY_INTERACTION); } @Override protected void update() throws ApiException { if (owner.isCorporation()) { return; //Character Endpoint } //Get PI Planets List responses = update(DEFAULT_RETRIES, new EsiHandler>() { @Override public ApiResponse> get() throws ApiException { return getPlanetaryInteractionApiAuth().getCharacterPlanetsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, null, null, null); } }); List citadels = new ArrayList<>(); for (CharacterPlanetsResponse response : responses) { //For each planet //Convert planet location to citadel PlanetResponse planet = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { return getUniverseApiOpen().getPlanetWithHttpInfo(response.getPlanetId(), COMPATIBILITY_DATE, null, null, null); } }); Citadel citadel = ApiIdConverter.getCitadel(planet); if (citadel != null) { citadels.add(citadel); } //Get planetary assets CharacterPlanetResponse planetResponse = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { return getPlanetaryInteractionApiAuth().getCharacterPlanetWithHttpInfo(owner.getOwnerID(), response.getPlanetId(), COMPATIBILITY_DATE, null, null, null); } }); for (PlanetPin pin : planetResponse.getPins()) { //For each pin on planet if (pin.getContents() == null) { continue; } owner.addAsset(EsiConverter.toAssetsPlanetaryInteraction(response, pin, owner)); } } CitadelGetter.set(citadels); } @Override protected boolean haveAccess() { if (owner.isCorporation()) { return true; //Overwrite the default, so, we don't get errors } else { return owner.isPlanetaryInteraction(); } } @Override protected void setNextUpdate(Date date) { //Use the assets update times } @Override protected RolesEnum[] getRequiredRoles() { return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiPublicMarketOrdersGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import net.nikr.eve.jeveasset.data.api.raw.RawPublicMarketOrder; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.Citadel; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.tabs.orders.OutbidProcesser; import net.nikr.eve.jeveasset.gui.tabs.orders.OutbidProcesser.OutbidProcesserInput; import net.nikr.eve.jeveasset.gui.tabs.orders.OutbidProcesser.OutbidProcesserOutput; import static net.nikr.eve.jeveasset.io.esi.AbstractEsiGetter.DEFAULT_RETRIES; import static net.nikr.eve.jeveasset.io.esi.AbstractEsiGetter.getMarketApiOpen; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.api.MarketApi; import net.troja.eve.esi.api.UniverseApi; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.MarketRegionOrdersResponse; import net.troja.eve.esi.model.MarketStructureResponse; import net.troja.eve.esi.model.StructureResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class EsiPublicMarketOrdersGetter extends AbstractEsiGetter { private static final Logger LOG = LoggerFactory.getLogger(EsiPublicMarketOrdersGetter.class); private static final Long OFFSET = 1000L * 3L; // 3 seconds private final UpdateTask updateTask; private final OutbidProcesserInput input; private final OutbidProcesserOutput output; private boolean publicMarketOrders = false; private boolean modified = false; private Date nextUpdate = null; private Date lastUpdate; public EsiPublicMarketOrdersGetter(UpdateTask updateTask, OutbidProcesserInput input, OutbidProcesserOutput output) { super(updateTask, null, false, Settings.get().getPublicMarketOrdersNextUpdate(), TaskType.PUBLIC_MARKET_ORDERS); this.updateTask = updateTask; this.input = input; this.output = output; } @Override protected void update() throws ApiException { AtomicInteger count = new AtomicInteger(0); //Update public market orders publicMarketOrders = true; List responses = new ArrayList<>(); for (Integer regionID : input.getRegionIDs()) { try { List response = updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { ApiResponse> response = getMarketApiOpen().getMarketRegionOrdersWithHttpInfo("all", SafeConverter.toLong(regionID), COMPATIBILITY_DATE, page, null, null, null, null); String header = getHeader(response.getHeaders(), "last-modified"); if (header != null) { Date date = Formatter.parseExpireDate(header); if (lastUpdate == null) { lastUpdate = date; } else if (!modified && !lastUpdate.equals(date)){ modified = true; } } return response; } }); responses.addAll(response); } finally { setProgressAll(input.getRegionIDs().size(), count.incrementAndGet(), 0, 40); } } if (modified) { addWarning("last-modified changed while updating", "Cache expired while updating"); } publicMarketOrders = false; Map> orders = EsiConverter.toPublicMarketOrders(responses); for (MarketRegionOrdersResponse ordersResponse : responses) { //Find leaking market structures if (ordersResponse.getLocationId() > 100000000) { input.getStructureIDs().add(ordersResponse.getLocationId()); } //Map known locationID <=> systemID input.getLocationToSystem().put(ordersResponse.getLocationId(), ordersResponse.getSystemId()); } //Get public structures input.getStructureIDs().addAll(update(DEFAULT_RETRIES, new EsiHandler>() { @Override public ApiResponse> get() throws ApiException { return getUniverseApiOpen().getStructuresWithHttpInfo(COMPATIBILITY_DATE, "market", null, null, null); } })); //Update orders in structures count.set(0); MarketApi marketApi = input.getMarketApi(); if (marketApi != null) { List structuresResponses = updatePagedList(input.getStructureIDs(), new PagedListHandler() { @Override protected List get(Long structureID) throws ApiException { try { return updatePages(DEFAULT_RETRIES, new EsiPagesHandler() { @Override public ApiResponse> get(Integer page) throws ApiException { return marketApi.getMarketStructureWithHttpInfo(structureID, COMPATIBILITY_DATE, page, null, null, null); } }); } catch (ApiException ex) { if (ex.getCode() == 403 && ex.getResponseBody().toLowerCase().contains("market access denied")) { LOG.warn(ex.getMessage() + ":\n" + ex.getResponseBody()); return null; } else { throw ex; } } finally { setProgressAll(input.getStructureIDs().size(), count.incrementAndGet(), 40, 90); } } }); for (MarketStructureResponse response : structuresResponses) { RawPublicMarketOrder marketOrder = new RawPublicMarketOrder(response, getSystemID(input, response.getLocationId())); Set set = orders.get(marketOrder.getTypeID()); if (set == null) { set = new HashSet<>(); orders.put(marketOrder.getTypeID(), set); } set.add(marketOrder); } } else { addError("NO ENOUGH ACCESS PRIVILEGES", "No character with market orders structure scope found\r\n(Add scope: [Options] > [Acounts...] > [Edit])"); } input.addOrders(orders, lastUpdate); //Process data OutbidProcesser.process(input, output); if (output.hasUnknownLocations()) { updateTask.addWarning(TaskType.PUBLIC_MARKET_ORDERS.getTaskName(), "Market orders in unknown locations ignored"); } if (lastUpdate != null) { Settings.lock("Public Orders (last update)"); Settings.get().setPublicMarketOrdersLastUpdate(lastUpdate); Settings.unlock("Public Orders (last update)"); } setProgressAll(100, 100, 90, 100); } private void setProgressAll(final float progressEnd, final float progressNow, final int minimum, final int maximum) { if (updateTask != null) { updateTask.setTaskProgress(progressEnd, progressNow, minimum, maximum); updateTask.setTotalProgress(progressEnd, progressNow, minimum, maximum); } } @Override protected void setNextUpdate(Date date) { if (publicMarketOrders && (nextUpdate == null || nextUpdate.before(date))) { nextUpdate = date; Date fixedDate = new Date(date.getTime() + OFFSET); Settings.lock("Public Orders (next update)"); Settings.get().setPublicMarketOrdersNextUpdate(fixedDate); Settings.unlock("Public Orders (next update)"); } } @Override protected boolean haveAccess() { return true; //Public } @Override protected RolesEnum[] getRequiredRoles() { return null; } private Long getSystemID(OutbidProcesser.OutbidProcesserInput data, long locationID) { Long systemID = data.getLocationToSystem().get(locationID); if (systemID != null) { return systemID; } MyLocation location = ApiIdConverter.getLocation(locationID); if (!location.isEmpty()) { return location.getSystemID(); } Citadel citadel = data.getCitadels().get(locationID); if (citadel != null) { return citadel.getSystemID(); } UniverseApi structuresApi = data.getStructuresApi(); if (structuresApi != null) { try { StructureResponse response = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { return structuresApi.getStructureWithHttpInfo(locationID, COMPATIBILITY_DATE, null, null, null); } }); data.getCitadels().put(locationID, ApiIdConverter.getCitadel(response, locationID)); return response.getSolarSystemId(); } catch (ApiException ex) { handleHeaders(ex); LOG.error(ex.getMessage(), ex); } } LOG.warn("Unknown market location"); return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiScopes.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Set; import net.nikr.eve.jeveasset.i18n.DialoguesAccount; import net.troja.eve.esi.auth.SsoScopes; public enum EsiScopes { CHARACTER_ASSETS(SsoScopes.ESI_ASSETS_READ_ASSETS_V1, DialoguesAccount.get().scopeAssets(), ScopeType.CHARACTER), CHARACTER_CLONE(SsoScopes.ESI_CLONES_READ_CLONES_V1, DialoguesAccount.get().scopeClones(), ScopeType.CHARACTER), CHARACTER_IMPLANT(SsoScopes.ESI_CLONES_READ_IMPLANTS_V1, DialoguesAccount.get().scopeImplants(), ScopeType.CHARACTER), CHARACTER_WALLET(SsoScopes.ESI_WALLET_READ_CHARACTER_WALLET_V1, DialoguesAccount.get().scopeWallet(), ScopeType.CHARACTER), CHARACTER_INDUSTRY_JOBS(SsoScopes.ESI_INDUSTRY_READ_CHARACTER_JOBS_V1, DialoguesAccount.get().scopeIndustryJobs(), ScopeType.CHARACTER), CHARACTER_MARKET_ORDERS(SsoScopes.ESI_MARKETS_READ_CHARACTER_ORDERS_V1, DialoguesAccount.get().scopeMarketOrders(), ScopeType.CHARACTER), CHARACTER_BLUEPRINTS(SsoScopes.ESI_CHARACTERS_READ_BLUEPRINTS_V1, DialoguesAccount.get().scopeBlueprints(), ScopeType.CHARACTER), CHARACTER_CONTRACTS(SsoScopes.ESI_CONTRACTS_READ_CHARACTER_CONTRACTS_V1, DialoguesAccount.get().scopeContracts(), ScopeType.CHARACTER), CHARACTER_STRUCTURES(SsoScopes.ESI_UNIVERSE_READ_STRUCTURES_V1, DialoguesAccount.get().scopeStructures(), ScopeType.CHARACTER), CHARACTER_MARKET_STRUCTURES(SsoScopes.ESI_MARKETS_STRUCTURE_MARKETS_V1, DialoguesAccount.get().scopeMarketStructures(), ScopeType.CHARACTER), CHARACTER_SHIP_TYPE(SsoScopes.ESI_LOCATION_READ_SHIP_TYPE_V1, DialoguesAccount.get().scopeShipType(), ScopeType.CHARACTER), CHARACTER_SHIP_LOCATION(SsoScopes.ESI_LOCATION_READ_LOCATION_V1, DialoguesAccount.get().scopeShipLocation(), ScopeType.CHARACTER), CHARACTER_OPEN_WINDOWS(SsoScopes.ESI_UI_OPEN_WINDOW_V1, DialoguesAccount.get().scopeOpenWindows(), ScopeType.CHARACTER), CHARACTER_PLANETARY_INTERACTION(SsoScopes.ESI_PLANETS_MANAGE_PLANETS_V1, DialoguesAccount.get().scopePlanetaryInteraction(), ScopeType.CHARACTER), CHARACTER_AUTOPILOT(SsoScopes.ESI_UI_WRITE_WAYPOINT_V1, DialoguesAccount.get().scopeAutopilot(), ScopeType.CHARACTER), CHARACTER_SKILLS(SsoScopes.ESI_SKILLS_READ_SKILLS_V1, DialoguesAccount.get().scopeSkills(), ScopeType.CHARACTER), CHARACTER_LOYALTY_POINTS(SsoScopes.ESI_CHARACTERS_READ_LOYALTY_V1, DialoguesAccount.get().scopeLoyaltyPoints(), ScopeType.CHARACTER), CHARACTER_NPC_STANDING(SsoScopes.ESI_CHARACTERS_READ_STANDINGS_V1, DialoguesAccount.get().scopeNpcStanding(), ScopeType.CHARACTER), CHARACTER_MINING(SsoScopes.ESI_INDUSTRY_READ_CHARACTER_MINING_V1, DialoguesAccount.get().scopeMining(), ScopeType.CHARACTER), CORPORATION_ROLES(SsoScopes.ESI_CHARACTERS_READ_CORPORATION_ROLES_V1, DialoguesAccount.get().scopeRoles(), ScopeType.CORPORATION, true), CORPORATION_ASSETS(SsoScopes.ESI_ASSETS_READ_CORPORATION_ASSETS_V1, DialoguesAccount.get().scopeAssets(), ScopeType.CORPORATION), CORPORATION_WALLET(SsoScopes.ESI_WALLET_READ_CORPORATION_WALLETS_V1, DialoguesAccount.get().scopeWallet(), ScopeType.CORPORATION), CORPORATION_INDUSTRY_JOBS(SsoScopes.ESI_INDUSTRY_READ_CORPORATION_JOBS_V1, DialoguesAccount.get().scopeIndustryJobs(), ScopeType.CORPORATION), CORPORATION_MARKET_ORDERS(SsoScopes.ESI_MARKETS_READ_CORPORATION_ORDERS_V1, DialoguesAccount.get().scopeMarketOrders(), ScopeType.CORPORATION), CORPORATION_BLUEPRINTS(SsoScopes.ESI_CORPORATIONS_READ_BLUEPRINTS_V1, DialoguesAccount.get().scopeBlueprints(), ScopeType.CORPORATION), CORPORATION_CONTRACTS(SsoScopes.ESI_CONTRACTS_READ_CORPORATION_CONTRACTS_V1, DialoguesAccount.get().scopeContracts(), ScopeType.CORPORATION), CORPORATION_DIVISIONS(SsoScopes.ESI_CORPORATIONS_READ_DIVISIONS_V1, DialoguesAccount.get().scopeDivisions(), ScopeType.CORPORATION), CORPORATION_NPC_STANDING(SsoScopes.ESI_CORPORATIONS_READ_STANDINGS_V1, DialoguesAccount.get().scopeNpcStanding(), ScopeType.CORPORATION), CORPORATION_MINING(SsoScopes.ESI_INDUSTRY_READ_CORPORATION_MINING_V1, DialoguesAccount.get().scopeMining(), ScopeType.CORPORATION), NAMES(), //Public CONQUERABLE_STATIONS(), //Public ; private final String scope; private final String text; private final ScopeType scopeType; private final boolean forced; /** * Public Scopes */ private EsiScopes() { this("", "", ScopeType.PUBLIC, false); } /** * Corporation and Character Scopes * @param scope * @param text * @param scopeType */ private EsiScopes(String scope, String text, ScopeType scopeType) { this(scope, text, scopeType, false); } /** * Forced Corporation and Character Scopes * @param scope * @param text * @param scopeType * @param forced */ private EsiScopes(String scope, String text, ScopeType scopeType, boolean forced) { this.scope = scope; this.text = text; this.scopeType = scopeType; this.forced = forced; } public String getScope() { return scope; } public boolean isInScope(Set scopes) { return scopes.contains(scope); } public boolean isCharacterScope() { return scopeType == ScopeType.CHARACTER; } public boolean isCorporationScope() { return scopeType == ScopeType.CORPORATION; } public boolean isPublicScope() { return scopeType == ScopeType.PUBLIC; } public boolean isForced() { return forced; } public static boolean isPrivilegesLimited(boolean corp, Set scopes) { boolean found = false; boolean missing = false; for (EsiScopes scope : EsiScopes.values()) { if (!corp && !scope.isCharacterScope()) { continue; } if (corp && !scope.isCorporationScope()) { continue; } if (scope.isInScope(scopes)) { found = true; } else { missing = true; } } return missing && found; } public static boolean isPrivilegesInvalid(boolean corp, Set scopes) { for (EsiScopes scope : EsiScopes.values()) { if (!corp && !scope.isCharacterScope()) { continue; } if (corp && !scope.isCorporationScope()) { continue; } if (scope.isInScope(scopes)) { return false; } } return true; } @Override public String toString() { return text; } private static enum ScopeType { CORPORATION, CHARACTER, PUBLIC } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiShipGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.ArrayList; import java.util.Date; import java.util.List; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterLocationResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.CharacterShipResponse; public class EsiShipGetter extends AbstractEsiGetter { public EsiShipGetter(UpdateTask updateTask, EsiOwner owner, Date assetNextUpdate) { super(updateTask, owner, false, assetNextUpdate, TaskType.SHIP); } @Override protected void update() throws ApiException { if (owner.isCorporation()) { return; //Character Endpoint } //Get Ship CharacterShipResponse shipType = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { return getLocationApiAuth().getCharacterShipWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, null, null, null); } }); //Get Location CharacterLocationResponse shipLocation = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { return getLocationApiAuth().getCharacterLocationWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, null, null, null); } }); //Create assets MyAsset activeShip = EsiConverter.toAssetsShip(shipType, shipLocation, owner); //Search for active ship List assets; synchronized (owner) { assets = new ArrayList<>(owner.getAssets()); } boolean activeShipInAssets = false; for (MyAsset asset : assets) { if (asset.getItemID().equals(activeShip.getItemID())) { activeShipInAssets = true; break; } } //Update Assets (if active ship is not found) if (!activeShipInAssets) { List activeShipChildren = new ArrayList<>(); for (MyAsset asset : assets) { //Root assets only if (asset.getParents().isEmpty() && activeShip.getItemID().equals(asset.getLocationID())) { //Found Child //Add asset to active ship activeShip.addAsset(asset); //Update locationID from ItemID to locationID setLocationID(asset, activeShip.getLocationID()); //Add assets that needs to be removed from the root activeShipChildren.add(asset); //Set active ship as parent asset.getParents().add(activeShip); } } //Add active ship to root owner.addAsset(activeShip); //Remove active ship children from root owner.removeAssets(activeShipChildren); //Save ship name try { Settings.lock("Active Ship Name"); Settings.get().getEveNames().put(shipType.getShipItemId(), shipType.getShipName()); } finally { Settings.unlock("Active Ship Name"); } } //Active Ship - Must be after getEveNames is updated owner.setActiveShip(EsiConverter.toActiveShip(shipType, shipLocation)); } /** * Set locationID for asset and children. * @param asset * @param locationID */ private void setLocationID(MyAsset asset, long locationID) { asset.setLocationID(locationID); for (MyAsset child : asset.getAssets()) { setLocationID(child, locationID); } } @Override protected void setNextUpdate(Date date) { //Use the assets update times } @Override protected boolean haveAccess() { if (owner.isCorporation()) { return true; //Overwrite the default, so, we don't get errors } else { return owner.isShip(); } } @Override protected RolesEnum[] getRequiredRoles() { return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiSkillGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.CharacterSkillsResponse; public class EsiSkillGetter extends AbstractEsiGetter { public EsiSkillGetter(UpdateTask updateTask, EsiOwner owner) { super(updateTask, owner, false, owner.getSkillsNextUpdate(), TaskType.SKILLS); } @Override protected void update() throws ApiException { if (owner.isCorporation()) { return; //Character Endpoint } CharacterSkillsResponse response = update(DEFAULT_RETRIES, new EsiHandler() { @Override public ApiResponse get() throws ApiException { return getSkillsApiAuth().getCharacterSkillsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, null, null, null); } }); owner.setSkills(EsiConverter.toSkills(response.getSkills(), owner)); owner.setTotalSkillPoints(response.getTotalSp()); owner.setUnallocatedSkillPoints(SafeConverter.toInteger(response.getUnallocatedSp())); } @Override protected void setNextUpdate(Date date) { owner.setSkillsNextUpdate(date); } @Override protected boolean haveAccess() { if (owner.isCorporation()) { return true; //Overwrite the default, so, we don't get errors } else { return owner.isSkills(); } } @Override protected RolesEnum[] getRequiredRoles() { return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiStructuresGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.raw.RawAsset; import net.nikr.eve.jeveasset.data.api.raw.RawBlueprint; import net.nikr.eve.jeveasset.data.api.raw.RawContract; import net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.Citadel; import net.nikr.eve.jeveasset.data.settings.TrackerData; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.tabs.values.AssetValue; import net.nikr.eve.jeveasset.gui.tabs.values.Value; import net.nikr.eve.jeveasset.io.online.CitadelGetter; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.StructureResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class EsiStructuresGetter extends AbstractEsiGetter { private static final Logger LOG = LoggerFactory.getLogger(EsiStructuresGetter.class); private final static Set IDS = new HashSet<>(); private final static Set DONE = new HashSet<>(); private final boolean tracker; public EsiStructuresGetter(UpdateTask updateTask, EsiOwner owner, boolean tracker) { super(updateTask, owner, false, owner.getStructuresNextUpdate(), TaskType.STRUCTURES); this.tracker = tracker; } public static String estimate(List esiOwners, List ownerTypes, Set locations, boolean tracker) { int total = 0; if (locations != null) { //Locations EsiStructuresGetter.createIDsFromLocations(locations); total = IDS.size() * esiOwners.size(); } else if (ownerTypes != null) { EsiStructuresGetter.createIDsFromOwners(ownerTypes, tracker); total = IDS.size() * esiOwners.size(); } else { DONE.clear(); for (EsiOwner esiOwner : esiOwners) { total = total + buildIDs(esiOwner, tracker).size(); } } total = (int)(total / 100.0 * 60.0 * 1000.0); //100 errors a minute to ms return Formatter.milliseconds(total, true, true); } public static void createIDsFromOwners(List ownerTypes, boolean tracker) { IDS.clear(); DONE.clear(); IDS.addAll(buildIDs(ownerTypes, tracker)); } public static void createIDsFromLocations(Set locations) { IDS.clear(); DONE.clear(); IDS.addAll(buildIDs(locations)); } public static void createIDsFromOwner() { IDS.clear(); DONE.clear(); } @Override protected void update() throws ApiException { if (owner.isCorporation()) { return; //Corporation accounts don't get structures } boolean ownerUpdate = IDS.isEmpty(); if (ownerUpdate) { IDS.addAll(buildIDs(owner, tracker)); } Map responses = updateListSlow(IDS, true, DEFAULT_RETRIES, new ListHandlerSlow() { @Override public ApiResponse get(Long k) throws ApiException { pause(); return getUniverseApiAuth().getStructureWithHttpInfo(k, COMPATIBILITY_DATE, null, null, null); } @Override protected void handle(ApiException ex, Long k) throws ApiException { if ((ex.getCode() == 403 && ex.getResponseBody().toLowerCase().contains("forbidden")) || (ex.getCode() == 404 && ex.getResponseBody().toLowerCase().contains("structure")) || (ex.getCode() == 502 && ex.getResponseBody().toLowerCase().contains("could not determine docking access"))) { LOG.warn("Failed to find locationID: " + k); } else { LOG.error("Failed to find locationID: " + k, ex); throw ex; } } }); List citadels = new ArrayList<>(); for (Map.Entry entry : responses.entrySet()) { citadels.add(ApiIdConverter.getCitadel(entry.getValue(), entry.getKey())); } if (ownerUpdate) { DONE.addAll(responses.keySet()); //Add Completed IDS.clear(); } else { IDS.removeAll(responses.keySet()); //Remove completed structures } CitadelGetter.set(citadels); } @Override protected void setNextUpdate(Date date) { owner.setStructuresNextUpdate(date); } @Override protected boolean haveAccess() { if (owner.isCorporation()) { return true; //Overwrite the default, so, we don't get errors } else { return owner.isStructures(); } } @Override protected RolesEnum[] getRequiredRoles() { return null; } private static Set buildIDs(EsiOwner esiOwner, boolean tracker) { Set locationIDs = buildIDs(Collections.singletonList(esiOwner), tracker); locationIDs.removeAll(DONE); return locationIDs; } private static Set buildIDs(Set locations) { Set locationIDs = new HashSet<>(); for (MyLocation locationEnd : locations) { if (locationEnd.isEmpty() || locationEnd.isUserLocation() || locationEnd.isCitadel()) { locationIDs.add(locationEnd.getLocationID()); } } return locationIDs; } private static Set buildIDs(List ownerTypes, boolean tracker) { Set itemIDs = new HashSet<>(); Set locationIDs = new HashSet<>(); if (tracker) { try { TrackerData.readLock(); for (List values : TrackerData.get().values()) { for (Value value : values) { for (AssetValue assetValue : value.getAssetsFilter().keySet()) { add(locationIDs, assetValue.getLocationID()); } } } } finally { TrackerData.readUnlock(); } } for (OwnerType ownerType : ownerTypes) { for (RawAsset asset : ownerType.getAssets()) { add(locationIDs, asset.getLocationID()); } getAssetItemIDs(itemIDs, ownerType.getAssets()); for (RawBlueprint blueprint : ownerType.getBlueprints().values()) { itemIDs.add(blueprint.getItemID()); add(locationIDs, blueprint.getLocationID()); } for (RawContract contract : ownerType.getContracts().keySet()) { add(locationIDs, contract.getEndLocationID()); add(locationIDs, contract.getStartLocationID()); } for (MyIndustryJob industryJob : ownerType.getIndustryJobs()) { add(locationIDs, industryJob.getStationID()); add(locationIDs, industryJob.getBlueprintLocationID()); add(locationIDs, industryJob.getOutputLocationID()); } for (RawMarketOrder marketOrder : ownerType.getMarketOrders()) { add(locationIDs, marketOrder.getLocationID()); } for (MyJournal journal : ownerType.getJournal()) { if (journal.getContextType() == ContextType.STRUCTURE_ID) { add(locationIDs, journal.getContextID()); } } } locationIDs.removeAll(itemIDs); return locationIDs; } private static void getAssetItemIDs(Set itemIDs, List assets) { for (MyAsset asset : assets) { itemIDs.add(asset.getItemID()); getAssetItemIDs(itemIDs, asset.getAssets()); } } private static void add(Set locationIDs, Long locationID) { if (locationID == null) { return; } if (locationID < 100000000) { return; } MyLocation location = ApiIdConverter.getLocation(locationID); if (location.isEmpty() || location.isUserLocation() || location.isCitadel()) { locationIDs.add(location.getLocationID()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/EsiTransactionsGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.io.shared.SafeConverter; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.CharacterWalletTransactionsResponse; import net.troja.eve.esi.model.CorporationWalletTransactionsResponse; public class EsiTransactionsGetter extends AbstractEsiGetter { private final boolean saveHistory; public EsiTransactionsGetter(UpdateTask updateTask, EsiOwner owner, boolean saveHistory) { super(updateTask, owner, false, owner.getTransactionsNextUpdate(), TaskType.TRANSACTIONS); this.saveHistory = saveHistory; } @Override protected void update() throws ApiException { Set existing = new HashSet<>(); if (saveHistory) { for (MyTransaction transaction : owner.getTransactions()) { existing.add(transaction.getTransactionID()); } } if (owner.isCorporation()) { for (int i = 1; i < 8; i++) { //Division 1-7 final int division = i; List responses = updateIDs(existing, DEFAULT_RETRIES, new IDsHandler() { @Override public ApiResponse> get(Long fromID) throws ApiException { return getWalletApiAuth().getCorporationWalletTransactionsWithHttpInfo(owner.getOwnerID(), SafeConverter.toLong(division), COMPATIBILITY_DATE, fromID, null, null, null); } @Override public Long getID(CorporationWalletTransactionsResponse response) { return response.getTransactionId(); } }); int fixedDivision = division + 999; owner.setTransactions(EsiConverter.toTransactionCorporation(responses, owner, fixedDivision, saveHistory)); } } else { List responses = updateIDs(existing, DEFAULT_RETRIES, new IDsHandler() { @Override public ApiResponse> get(Long fromID) throws ApiException { return getWalletApiAuth().getCharacterWalletTransactionsWithHttpInfo(owner.getOwnerID(), COMPATIBILITY_DATE, fromID, null, null, null); } @Override public Long getID(CharacterWalletTransactionsResponse response) { return response.getTransactionId(); } }); owner.setTransactions(EsiConverter.toTransaction(responses, owner, 1000, saveHistory)); } } @Override protected void setNextUpdate(Date date) { owner.setTransactionsNextUpdate(date); } @Override protected boolean haveAccess() { return owner.isTransactions(); } @Override protected RolesEnum[] getRequiredRoles() { RolesEnum[] roles = {RolesEnum.DIRECTOR, RolesEnum.ACCOUNTANT, RolesEnum.JUNIOR_ACCOUNTANT}; return roles; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/esi/MicroServe.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Inet4Address; import java.net.ServerSocket; import java.net.Socket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MicroServe implements AuthCodeListener { private static final Logger LOG = LoggerFactory.getLogger(MicroServe.class); private static final Object LOCK = new Object(); private boolean serverStarted; private String authCode; private boolean listen = false; public MicroServe() { } public void startServer() { try { ServerSocket serverSocket = new ServerSocket(2221, 50, Inet4Address.getLoopbackAddress()); ConnectionListener connectionListener = new ConnectionListener(serverSocket, this); connectionListener.start(); serverStarted = true; } catch (IOException ex) { LOG.error(ex.getMessage(), ex); serverStarted = false; } } public void stopListening() { authCode = null; listen = false; } public void startListening() { listen = true; } public boolean isServerStarted() { return serverStarted; } public String getAuthCode() { synchronized(LOCK) { try { LOCK.wait(); } catch (InterruptedException ex) { //No problem } } return authCode; } @Override public void setAuthCode(String authCode) { this.authCode = authCode; } @Override public synchronized boolean isListening() { return listen; } private static class ConnectionListener extends Thread { private final ServerSocket serverSocket; private final AuthCodeListener listener; public ConnectionListener(ServerSocket serverSocket, AuthCodeListener listener) { this.serverSocket = serverSocket; this.listener = listener; } @Override public void run() { while (true) { try { Socket clientSocket = serverSocket.accept(); ConnectionResponse response = new ConnectionResponse(clientSocket, listener); response.start(); } catch (IOException ex) { LOG.error(ex.getMessage(), ex); } } } } private static class ConnectionResponse extends Thread { private final Socket clientSocket; private final AuthCodeListener listener; public ConnectionResponse(Socket clientSocket, AuthCodeListener listener) { this.clientSocket = clientSocket; this.listener = listener; } @Override public void run() { boolean found = false; InputStreamReader inputStreamReader = null; BufferedReader in = null; OutputStream out = null; try { inputStreamReader = new InputStreamReader(clientSocket.getInputStream()); in = new BufferedReader(inputStreamReader); out = clientSocket.getOutputStream(); String s; while ((s = in.readLine()) != null) { if (s.startsWith("GET") && s.contains("code=")) { String temp = s; int start = temp.indexOf("code="); temp = temp.substring(start + 5); int end = temp.indexOf("&"); temp = temp.substring(0 , end); listener.setAuthCode(temp); found = true; } if (s.isEmpty()) { break; } } // http response writeln(out, "HTTP/1.1 200 OK"); // signal end of headers writeln(out, ""); //html if (listener.isListening()) { if (found) { write(out, "Authentication Successful", " Return to jEveAssets to complete the import.
\n" + "
\n" + " This browser window can now be closed.\n" ); } else { write(out, "Authorization Failed", " The authorization process failed.
\n" + " You can report the problem in the forum thread.
\n" + "
\n" + " This browser window can now be closed.\n" ); } } else { write(out, "Authorization Cancelled", " The authorization process was cancelled in jEveAssets.
\n" + " Please, try again...
\n" + "
\n" + " This browser window can now be closed.\n" ); } out.flush(); } catch (IOException ex) { LOG.error(ex.getMessage(), ex); } finally { if (clientSocket != null) { try { clientSocket.close(); //Close connection } catch (IOException ex) { //That is okay } } if (inputStreamReader != null) { try { inputStreamReader.close(); //Close connection } catch (IOException ex) { //That is okay } } if (in != null) { try { in.close(); //Close connection } catch (IOException ex) { //That is okay } } if (out != null) { try { out.close(); //Close connection } catch (IOException ex) { //That is okay } } if (found) { synchronized(LOCK) { LOCK.notifyAll(); } } } } } private static void write(OutputStream out, String header, String text) throws IOException { String value = "\n" + "\n" + "\n" + " " + header + "\n" + " \n" + " \n" + "\n" + "\n" + "
\n" + "
\n" + " " + header + "\n" + "
\n" + "
\n" + "
\n" + text + "
\n" + "
\n" + "\n" + ""; out.write(value.getBytes("ASCII")); } private static void writeln(OutputStream out, String value) throws IOException { value = value + "\r\n"; out.write(value.getBytes("ASCII")); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/AbstractBackup.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.io.local.FileLock.SafeFileIO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AbstractBackup extends AttributeGetters { private static final Logger LOG = LoggerFactory.getLogger(AbstractBackup.class); protected boolean exist(final String filename) { return new File(filename).exists() //.xml || getNewFile(filename).exists() //.new || getBackupFile(filename).exists(); //.bac } protected boolean restoreBackupFile(final String filename) { File targetFile = new File(filename); renameFile(targetFile, getCorruptFile(filename)); //Backup corrupted file return renameFile(getBackupFile(filename), targetFile); } protected boolean restoreNewFile(final String filename) { File targetFile = new File(filename); renameFile(targetFile, getCorruptFile(filename)); //Backup corrupted file return renameFile(getNewFile(filename), targetFile); } protected void restoreFailed(final String filename) { File targetFile = new File(filename); renameFile(targetFile, getCorruptFile(filename)); //Backup corrupted file } protected void backupFile(final String filename) { File targetFile = new File(filename); //target to bac (new is safe) renameFile(targetFile, getBackupFile(filename)); //new to target (bac is safe) renameFile(getNewFile(filename), targetFile); } protected File getNewFile(final String filename) { return new File(filename.substring(0, filename.lastIndexOf(".")) + ".new"); } private File getProgramBackup(final String filename) { return new File(filename.substring(0, filename.lastIndexOf(".")) + "_" + Program.PROGRAM_VERSION.replace(" ", "_") + "_backup.zip"); } protected void backup(final String filename) { File sourceFile = new File(filename); File backupFile = getProgramBackup(filename); if (!backupFile.exists()) { try (SafeFileIO io = new SafeFileIO(sourceFile); ZipOutputStream out = new ZipOutputStream(new FileOutputStream(backupFile))){ InputStream in = io.getFileInputStream(); ZipEntry e = new ZipEntry(sourceFile.getName()); out.putNextEntry(e); byte[] buffer = new byte[8192]; int len; while ((len = in.read(buffer)) != -1) { out.write(buffer, 0, len); } out.closeEntry(); LOG.info("Backup Created: " + backupFile.getName()); } catch (IOException ex) { LOG.error("Failed to create backup for new program version", ex); } } } private File getBackupFile(final String filename) { return new File(filename.substring(0, filename.lastIndexOf(".")) + ".bac"); } private File getCorruptFile(final String filename) { File file = null; int count = 0; while(file == null || file.exists()) { count++; file = new File(filename.substring(0, filename.lastIndexOf(".")) + ".error" + count); } return file; } private boolean renameFile(File from, File to) { if (!from.exists()) { LOG.warn("Move failed: " + from.getName() + " does not exist"); return false; } if (to.exists() && !to.delete()) { LOG.warn("Move failed: failed to delete: " + to.getName()); return false; } if (from.exists() && from.renameTo(to)) { LOG.info(from.getName() + " moved to: "+ to.getName()); return true; } else { LOG.warn("Move failed: from " + from.getName() + " to " + to.getName()); return false; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/AbstractXmlReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.File; import java.io.IOException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import net.nikr.eve.jeveasset.io.local.FileLock.SafeFileIO; import net.nikr.eve.jeveasset.io.online.Updater; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; public abstract class AbstractXmlReader extends AbstractBackup { private static final Logger LOG = LoggerFactory.getLogger(AbstractXmlReader.class); public static enum XmlType { DYNAMIC, STATIC, DYNAMIC_BACKUP, IMPORT } protected T read(final String name, final String filename, final XmlType xmlType) { if (!exist(filename) && (xmlType == XmlType.DYNAMIC || xmlType == XmlType.DYNAMIC_BACKUP)) { return doNotExistValue(); } try { Element element = getDocumentElement(filename, xmlType); T t = parse(element); LOG.info(name+ " loaded"); return t; } catch (IOException ex) { LOG.error(name+ " not loaded", ex); if (xmlType == XmlType.STATIC) { staticDataFix(); } return failValue(); } catch (IllegalArgumentException | ArrayIndexOutOfBoundsException | XmlException ex) { LOG.error(name+ " not loaded: " + ex.getMessage(), ex); if (xmlType == XmlType.STATIC) { //Static data staticDataFix(); } else if (xmlType == XmlType.DYNAMIC || xmlType == XmlType.DYNAMIC_BACKUP) { //Dynamic data if (restoreNewFile(filename)) { //If possible restore from .new (Should be the newest) return read(name, filename, xmlType); } else if (restoreBackupFile(filename)) { //If possible restore from .bac (Should be the oldest, but, still worth trying) return read(name, filename, xmlType); } else { //Nothing left to try - throw error restoreFailed(filename); //Backup error file } } return failValue(); } } protected abstract T parse(Element element) throws XmlException; protected abstract T failValue(); protected abstract T doNotExistValue(); private void staticDataFix() { Updater updater = new Updater(); updater.fixData(); } private Element getDocumentElement(final String filename, final XmlType xmlType) throws XmlException, IOException { File file = new File(filename); if (xmlType == XmlType.DYNAMIC_BACKUP) { backup(filename); } try (SafeFileIO io = new SafeFileIO(file, xmlType == XmlType.IMPORT || xmlType == XmlType.STATIC)){ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(io.getFileInputStream()); Element element = doc.getDocumentElement(); return element; } catch (SAXException ex) { throw new XmlException(ex.getMessage(), ex); } catch (ParserConfigurationException ex) { throw new XmlException(ex.getMessage(), ex); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/AbstractXmlWriter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.awt.Color; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.nio.channels.NonWritableChannelException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import net.nikr.eve.jeveasset.io.local.FileLock.SafeFileIO; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Document; import org.w3c.dom.Element; public abstract class AbstractXmlWriter extends AbstractBackup { private static DocumentBuilderFactory factory = null; protected Document getXmlDocument(final String rootname) throws XmlException { try { DocumentBuilder builder = getFactory().newDocumentBuilder(); DOMImplementation impl = builder.getDOMImplementation(); return impl.createDocument(null, rootname, null); } catch (ParserConfigurationException ex) { throw new XmlException(ex.getMessage(), ex); } } private synchronized static DocumentBuilderFactory getFactory() { if (factory == null) { factory = DocumentBuilderFactory.newInstance(); } return factory; } protected void writeXmlFileFitting(final Document doc, final String filename, final boolean createBackup) throws XmlException { writeXmlFile(doc, filename, "UTF-8", createBackup, true); } protected void writeXmlFile(final Document doc, final String filename, final boolean createBackup) throws XmlException { writeXmlFile(doc, filename, "UTF-16", createBackup, false); } private void writeXmlFile(final Document doc, final String filename, final String encoding, boolean createBackup, boolean fitting) throws XmlException { DOMSource source = new DOMSource(doc); File file; if (createBackup) { file = getNewFile(filename); //Save to .new file } else { file = new File(filename); } try (SafeFileIO io = new SafeFileIO(file)){ //Save file OutputStreamWriter outputStreamWriter = io.getOutputStreamWriter(encoding); if (fitting) { outputStreamWriter.append("\r\n"); } // result Result result = new StreamResult(outputStreamWriter); TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer; transformer = transformerFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty(OutputKeys.STANDALONE, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "4"); transformer.setOutputProperty(OutputKeys.ENCODING, encoding); if (fitting) { transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); } transformer.transform(source, result); io.unlock(); //Unlock before backupFile() is called //Saving done - create backup and rename new file to target if (createBackup) { backupFile(filename); //Rename .xml => .bac (.new is safe) and .new => .xml (.bac is safe). That way we always have at least one safe file } } catch (FileNotFoundException ex) { throw new XmlException(ex.getMessage(), ex); } catch (TransformerConfigurationException ex) { throw new XmlException(ex.getMessage(), ex); } catch (TransformerException ex) { throw new XmlException(ex.getMessage(), ex); } catch (UnsupportedEncodingException ex) { throw new XmlException(ex.getMessage(), ex); } catch (NonWritableChannelException ex) { throw new XmlException(ex.getMessage(), ex); } catch (IOException ex) { throw new XmlException(ex.getMessage(), ex); } } protected void setAttribute(final Element node, final String qualifiedName, final Object value) { node.setAttribute(qualifiedName, valueOf(value)); } protected void setAttributeOptional(final Element node, final String qualifiedName, final Object value) { if (value != null) { node.setAttribute(qualifiedName, valueOf(value)); } } protected void setAttribute(final Element node, final String qualifiedName, final String value) { node.setAttribute(qualifiedName, value); } public static String valueOf(final Object object) { if (object == null) { throw new RuntimeException("Can't save null"); } else if (object instanceof Collection) { Collection collection = (Collection) object; List list = new ArrayList<>(); for (Object t : collection) { list.add(valueOf(t)); } return String.join(",", list); } else if (object instanceof Color) { Color color = (Color) object; return String.valueOf(color.getRGB()); } else if (object instanceof Date) { Date date = (Date) object; return String.valueOf(date.getTime()); } else if (object instanceof Enum) { return ((Enum)object).name(); } else { return String.valueOf(object); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/AgentsReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.util.Map; import net.nikr.eve.jeveasset.data.sde.Agent; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public final class AgentsReader extends AbstractXmlReader { private final Map agents; public AgentsReader(Map agents) { this.agents = agents; } public static void load(Map agents) { AgentsReader reader = new AgentsReader(agents); reader.read("Agents", FileUtil.getPathAgents(), AbstractXmlReader.XmlType.STATIC); } @Override protected Boolean parse(Element element) throws XmlException { parseAgents(element); return true; } @Override protected Boolean failValue() { return false; } @Override protected Boolean doNotExistValue() { return false; } private void parseAgents(final Element element) throws XmlException { NodeList nodes = element.getElementsByTagName("row"); for (int i = 0; i < nodes.getLength(); i++) { Element itemElement = (Element) nodes.item(i); Agent agent = parseAgent(itemElement); agents.put(agent.getAgentID(), agent); } } private Agent parseAgent(final Node node) throws XmlException { String agent = getString(node, "agent"); int agentID = getInt(node, "agentid"); int corporationID = getInt(node, "corporationid"); int level = getInt(node, "level"); int divisionID = getInt(node, "divisionid"); int agentTypeID = getInt(node, "agenttypeid"); long locationID = getLong(node, "locationid"); boolean locator = getBoolean(node, "locator"); return new Agent(agent, agentID, corporationID, level, divisionID, agentTypeID, locationID, locator); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/AssetAddedReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.reflect.TypeToken; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Type; import java.util.Date; import java.util.HashMap; import java.util.Map; import net.nikr.eve.jeveasset.data.settings.AddedData; import net.nikr.eve.jeveasset.io.local.FileLock.SafeFileIO; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AssetAddedReader extends AbstractBackup { private static final Logger LOG = LoggerFactory.getLogger(AssetAddedReader.class); public static void load() { AssetAddedReader reader = new AssetAddedReader(); reader.read(FileUtil.getPathAssetAdded()); } protected void read(String filename) { File file = new File(filename); if (!file.exists()) { return; } backup(filename); try (SafeFileIO io = new SafeFileIO(file)){ Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new DateDeserializer()).create(); Map assetAddedData = gson.fromJson(new InputStreamReader(io.getFileInputStream()), new TypeToken>() {}.getType()); if (assetAddedData != null) { AddedData.getAssets().set(assetAddedData); //Import from added.json LOG.info("Asset added data loaded"); } } catch (IOException | JsonParseException ex) { if (restoreNewFile(filename)) { //If possible restore from .new (Should be the newest) read(filename); } else if (restoreBackupFile(filename)) { //If possible restore from .bac (Should be the oldest, but, still worth trying) read(filename); } else { //Nothing left to try - throw error restoreFailed(filename); //Backup error file LOG.error(ex.getMessage(), ex); } } } public static class DateDeserializer implements JsonDeserializer { @Override public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { return new Date(json.getAsLong()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/AttributeGetters.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.awt.Color; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.List; import net.nikr.eve.jeveasset.data.settings.Settings; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class AttributeGetters { private static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyy-MM-dd HH:mm:ss"); protected AttributeGetters() { } protected Element getNodeOptional(final Element parent, final String nodeName) throws XmlException { NodeList nodes = parent.getElementsByTagName(nodeName); if (nodes.getLength() != 1) { return null; } return (Element) nodes.item(0); } protected Element getNode(final Element parent, final String nodeName) throws XmlException { NodeList nodes = parent.getElementsByTagName(nodeName); if (nodes.getLength() != 1) { throw new XmlException(nodeName + " is " + nodes.getLength()+ " (should be 1)"); } return (Element) nodes.item(0); } protected boolean haveAttribute(final Node node, final String attributeName) { Node attributeNode = node.getAttributes().getNamedItem(attributeName); return attributeNode != null; } protected Color getColorOptional(final Node node, final String attributeName) throws XmlException { Integer i = getIntOptional(node, attributeName); if (i == null) { return null; } else { return new Color(i); } } protected Color getColor(final Node node, final String attributeName) throws XmlException { int i = getInt(node, attributeName); return new Color(i); } protected List getStringListOptional(final Node node, final String attributeName) throws XmlException { String nodeValue = getNodeValueOptional(node, attributeName); if (nodeValue == null) { return null; } else { return stringToList(nodeValue); } } protected void addIntToList(final Node node, final String attributeName, final Collection addTo) throws XmlException { String nodeValue = getNodeValueOptional(node, attributeName); if (nodeValue == null) { return; } for (String s : nodeValue.split(",")) { try { addTo.add(Integer.valueOf(s)); } catch (NumberFormatException ex) { //Ignore... } } } protected List getStringList(final Node node, final String attributeName) throws XmlException { String nodeValue = getNodeValue(node, attributeName); return stringToList(nodeValue); } private List stringToList(String nodeValue) { String[] arr = nodeValue.split(","); return new ArrayList<>(Arrays.asList(arr)); } protected String getString(final Node node, final String attributeName) throws XmlException { return getNodeValue(node, attributeName); } protected String getStringOptional(final Node node, final String attributeName) throws XmlException { return getNodeValueOptional(node, attributeName); } protected String getStringNotNull(final Node node, final String attributeName, final String defaultValue) throws XmlException { String value = getNodeValueOptional(node, attributeName); if (value == null) { return defaultValue; } return value; } protected Date getDate(final Node node, final String attributeName) throws XmlException { String value = getNodeValue(node, attributeName); return toDate(value, node, attributeName); } protected Date getDateNotNull(final Node node, final String attributeName) { String value = getNodeValueOptional(node, attributeName); if (value == null) { return Settings.getNow(); } try { return toDate(value, node, attributeName); } catch (XmlException ex) { return Settings.getNow(); } } protected Date getDateOptional(final Node node, final String attributeName) throws XmlException { String value = getNodeValueOptional(node, attributeName); if (value == null) { return null; } return toDate(value, node, attributeName); } private Date toDate(final String value, final Node node, final String attributeName) throws XmlException { try { return FORMAT.parse(value); } catch (ParseException ex) { //Lets try one more thing } try { return new Date(Long.parseLong(value)); } catch (NumberFormatException ex) { throw new XmlException("Failed to convert value: " +value+ " to Date form node: " + node.getNodeName() + " > " + attributeName); } } protected int getInt(final Node node, final String attributeName) throws XmlException { String value = getNodeValue(node, attributeName); return toInt(value, node, attributeName); } protected Integer getIntOptional(final Node node, final String attributeName) throws XmlException { String value = getNodeValueOptional(node, attributeName); if (value == null) { return null; } return toInt(value, node, attributeName); } protected int getIntNotNull(final Node node, final String attributeName, final int defaultValue) throws XmlException { String value = getNodeValueOptional(node, attributeName); if (value == null) { return defaultValue; } return toInt(value, node, attributeName); } protected Integer toInt(String value, final Node node, final String attributeName) throws XmlException { try { return Integer.parseInt(value); } catch (NumberFormatException ex) { throw new XmlException("Failed to convert value: " +value+ " to Integer form node: " + node.getNodeName() + " > " + attributeName); } } protected long getLong(final Node node, final String attributeName) throws XmlException { String value = getNodeValue(node, attributeName); return toLong(value, node, attributeName); } protected Long getLongOptional(final Node node, final String attributeName) throws XmlException { String value = getNodeValueOptional(node, attributeName); if (value == null) { return null; } return toLong(value, node, attributeName); } protected long getLongNotNull(final Node node, final String attributeName, final long defaultValue) throws XmlException { String value = getNodeValueOptional(node, attributeName); if (value == null) { return defaultValue; } return toLong(value, node, attributeName); } private Long toLong(final String value, final Node node, final String attributeName) throws XmlException { try { return safeStringToLong(value); } catch (NumberFormatException ex) { throw new XmlException("Failed to convert value: " +value+ " to Long form node: " + node.getNodeName() + " > " + attributeName); } } protected double getDouble(final Node node, final String attributeName) throws XmlException { String value = getNodeValue(node, attributeName); return toDouble(value, node, attributeName); } protected Double getDoubleOptional(final Node node, final String attributeName) throws XmlException { String value = getNodeValueOptional(node, attributeName); if (value == null) { return null; } return toDouble(value, node, attributeName); } protected double getDoubleNotNull(final Node node, final String attributeName, final double defaultValue) throws XmlException { String value = getNodeValueOptional(node, attributeName); if (value == null) { return defaultValue; } return toDouble(value, node, attributeName); } private Double toDouble(final String value, final Node node, final String attributeName) throws XmlException { try { return Double.valueOf(value); } catch (NumberFormatException ex) { throw new XmlException("Failed to convert value: " +value+ " to Double form node: " + node.getNodeName() + " > " + attributeName); } } protected float getFloat(final Node node, final String attributeName) throws XmlException { String value = getNodeValue(node, attributeName); return toFloat(value, node, attributeName); } protected Float getFloatOptional(final Node node, final String attributeName) throws XmlException { String value = getNodeValueOptional(node, attributeName); if (value == null) { return null; } return toFloat(value, node, attributeName); } protected float getFloatNotNull(final Node node, final String attributeName, final float defaultValue) throws XmlException { String value = getNodeValueOptional(node, attributeName); if (value == null) { return defaultValue; } return toFloat(value, node, attributeName); } private Float toFloat(String value, final Node node, final String attributeName) throws XmlException { try { return Float.valueOf(value); } catch (NumberFormatException ex) { throw new XmlException("Failed to convert value: " +value+ " to Float form node: " + node.getNodeName() + " > " + attributeName); } } protected boolean getBoolean(final Node node, final String attributeName) throws XmlException { String value = getNodeValue(node, attributeName); return (value.equals("true") || value.equals("1")); } protected Boolean getBooleanOptional(final Node node, final String attributeName) throws XmlException { String value = getNodeValueOptional(node, attributeName); if (value == null) { return null; } return (value.equals("true") || value.equals("1")); } protected boolean getBooleanNotNull(final Node node, final String attributeName, final boolean defaultValue) throws XmlException { String value = getNodeValueOptional(node, attributeName); if (value == null) { return defaultValue; } return (value.equals("true") || value.equals("1")); } private Long safeStringToLong(final String s) { int nE = s.indexOf("E"); if (nE == -1) { nE = s.indexOf("e"); } if (nE == -1) { return Long.parseLong(s); } String sFirstNumber = s.substring(0, nE); String sLastNumber = s.substring(nE + 2); double nFirstNumber = Double.parseDouble(sFirstNumber); double nLastNumber = Double.parseDouble(sLastNumber); long nOutput = 10; for (int a = 1; a < nLastNumber; a++) { nOutput = nOutput * 10; } nOutput = (long) Math.ceil(nFirstNumber * nOutput); return nOutput; } private String getNodeValue(final Node node, final String attributeName) throws XmlException { Node attributeNode = node.getAttributes().getNamedItem(attributeName); if (attributeNode == null) { throw new XmlException("Failed to parse attribute from node: " + node.getNodeName() + " > " + attributeName); } return attributeNode.getNodeValue(); } private String getNodeValueOptional(final Node node, final String attributeName) { Node attributeNode = node.getAttributes().getNamedItem(attributeName); if (attributeNode == null) { return null; } else { return attributeNode.getNodeValue(); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/CitadelReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import net.nikr.eve.jeveasset.data.settings.Citadel; import net.nikr.eve.jeveasset.data.settings.Citadel.CitadelSource; import net.nikr.eve.jeveasset.data.settings.CitadelSettings; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.w3c.dom.Element; import org.w3c.dom.NodeList; public final class CitadelReader extends AbstractXmlReader { private CitadelReader() { } public static CitadelSettings load() { CitadelReader reader = new CitadelReader(); return reader.read("Citadels", FileUtil.getPathCitadel(), AbstractXmlReader.XmlType.DYNAMIC); } @Override protected CitadelSettings parse(Element element) throws XmlException { CitadelSettings settings = new CitadelSettings(); parseCitadels(element, settings); return settings; } @Override protected CitadelSettings failValue() { return new CitadelSettings(); } @Override protected CitadelSettings doNotExistValue() { return new CitadelSettings(); } private void parseCitadels(final Element element, final CitadelSettings settings) throws XmlException { if (!element.getNodeName().equals("citadels")) { throw new XmlException("Wrong root element name."); } parseCitadel(element, settings); } private void parseCitadel(final Element element, final CitadelSettings settings) throws XmlException { NodeList filterNodes = element.getElementsByTagName("citadel"); for (int i = 0; i < filterNodes.getLength(); i++) { Element currentNode = (Element) filterNodes.item(i); long id = getLong(currentNode, "stationid"); String name = getString(currentNode, "name"); long systemId = getLong(currentNode, "systemid"); boolean userLocation = getBooleanNotNull(currentNode, "userlocation", false) ; boolean citadel = getBooleanNotNull(currentNode, "citadel", true); CitadelSource source = CitadelSource.OLD; if (haveAttribute(currentNode, "source")) { try { source = CitadelSource.valueOf(getString(currentNode, "source")); } catch (IllegalArgumentException ex) { source = CitadelSource.OLD; } } settings.put(id, new Citadel(id, name, systemId, userLocation, citadel, source)); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/CitadelWriter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.util.Map; import net.nikr.eve.jeveasset.data.settings.Citadel; import net.nikr.eve.jeveasset.data.settings.CitadelSettings; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; public final class CitadelWriter extends AbstractXmlWriter { private static final Logger LOG = LoggerFactory.getLogger(CitadelWriter.class); private CitadelWriter() { } public static void save(CitadelSettings settings) { CitadelWriter writer = new CitadelWriter(); writer.write(settings); } private void write(CitadelSettings settings) { Document xmldoc = null; try { xmldoc = getXmlDocument("citadels"); } catch (XmlException ex) { LOG.error("Citadel not saved " + ex.getMessage(), ex); } writeCitadels(xmldoc, settings); //xmldoc.normalizeDocument(); try { writeXmlFile(xmldoc, FileUtil.getPathCitadel(), true); } catch (XmlException ex) { LOG.error("Citadel not saved " + ex.getMessage(), ex); } LOG.info(" Citadel saved"); } private void writeCitadels(final Document xmldoc, final CitadelSettings settings) { Element parentNode = xmldoc.getDocumentElement(); for (Map.Entry entry : settings.getCache()) { Element node = xmldoc.createElementNS(null, "citadel"); Citadel citadel = entry.getValue(); setAttribute(node, "stationid", entry.getKey()); setAttribute(node, "systemid", citadel.getSystemID()); setAttribute(node, "name", citadel.getLocation()); setAttribute(node, "userlocation", citadel.isUserLocation()); setAttribute(node, "citadel", citadel.isCitadel()); setAttribute(node, "source", citadel.getSource()); parentNode.appendChild(node); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/CsvWriter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.FileWriter; import java.io.IOException; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.supercsv.io.CsvMapWriter; import org.supercsv.io.ICsvMapWriter; import org.supercsv.prefs.CsvPreference; public final class CsvWriter { private static final Logger LOG = LoggerFactory.getLogger(CsvWriter.class); private CsvWriter() { } public static boolean save(final String filename, final List> data, final String[] header, final String[] headerKeys, final CsvPreference csvPreference) { CsvWriter writer = new CsvWriter(); return writer.write(filename, data, header, headerKeys, csvPreference); } private boolean write(final String filename, final List> data, final String[] header, final String[] headerKeys, final CsvPreference csvPreference) { ICsvMapWriter writer; try { writer = new CsvMapWriter(new FileWriter(filename), csvPreference); writer.writeHeader(header); for (Map map : data) { writer.write(map, headerKeys); } writer.close(); } catch (IOException ex) { LOG.warn("CSV file not saved"); return false; } LOG.info("CSV file saved"); return true; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/EveFittingReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; import org.w3c.dom.Element; import org.w3c.dom.NodeList; public class EveFittingReader extends AbstractXmlReader>> { public static Map> load(final String filename) { EveFittingReader reader = new EveFittingReader(); return reader.read("Fitting", filename, XmlType.IMPORT); } @Override protected Map> parse(Element element) throws XmlException { Map> map = new TreeMap<>(); parseFits(element, map); return map; } @Override protected Map> failValue() { return null; } @Override protected Map> doNotExistValue() { return null; } private void parseFits(final Element element, final Map> map) throws XmlException { if (!element.getNodeName().equals("fittings")) { throw new XmlException("Wrong root element name."); } parseFit(element, map); } private void parseFit(final Element element, final Map> map) throws XmlException { NodeList fittingNodes = element.getElementsByTagName("fitting"); Map types = new HashMap<>(); for (Item item : StaticData.get().getItems().values()) { types.put(item.getTypeName(), item.getTypeID()); } for (int i = 0; i < fittingNodes.getLength(); i++) { Element fittingNode = (Element) fittingNodes.item(i); String name = getString(fittingNode, "name"); Map data = new HashMap<>(); map.put(name, data); NodeList hardwareNodes = fittingNode.getElementsByTagName("hardware"); for (int a = 0; a < hardwareNodes.getLength(); a++) { Element hardwareNode = (Element) hardwareNodes.item(a); double quantity = getIntNotNull(hardwareNode, "qty", 1); String type = getString(hardwareNode, "type"); Integer typeID = types.get(type); if (typeID != null) { Double previuse = data.put(typeID, quantity); if (previuse != null) { data.put(typeID, quantity + previuse); } } } NodeList shipTypeNodes = fittingNode.getElementsByTagName("shipType"); for (int a = 0; a < shipTypeNodes.getLength(); a++) { Element shipTypeNode = (Element) shipTypeNodes.item(a); String type = getString(shipTypeNode, "value"); Integer typeID = types.get(type); if (typeID != null) { Double previuse = data.put(typeID, 1.0); if (previuse != null) { data.put(typeID, 1.0 + previuse); } } } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/EveFittingWriter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; public final class EveFittingWriter extends AbstractXmlWriter { private static final Logger LOG = LoggerFactory.getLogger(EveFittingWriter.class); private EveFittingWriter() { } public static void save(final List assets, final String filename) { save(assets, filename, null, null); } public static void save(final List assets, final String filename, final String setupName, final String description) { EveFittingWriter writer = new EveFittingWriter(); writer.write(assets, filename, setupName, description); } private void write(final List assets, final String filename, String setupName, String description) { Document xmldoc = null; try { xmldoc = getXmlDocument("fittings"); } catch (XmlException ex) { LOG.error("Eve fitting not saved " + ex.getMessage(), ex); } boolean noSetupName = (setupName == null); if (description == null) { description = Program.PROGRAM_NAME + " export all"; } for (MyAsset asset : assets) { if (noSetupName) { setupName = asset.getName(); } writeFitting(xmldoc, asset, setupName, description); } try { writeXmlFileFitting(xmldoc, filename, false); } catch (XmlException ex) { LOG.error("Eve fitting not saved " + ex.getMessage(), ex); } LOG.info("Eve fitting saved"); } private void writeFitting(final Document xmldoc, final MyAsset asset, final String setupName, final String description) { Element fittingsNode = xmldoc.getDocumentElement(); Element fittingNode = xmldoc.createElementNS(null, "fitting"); //Fit Name setAttribute(fittingNode, "name", setupName); fittingsNode.appendChild(fittingNode); //Description Element descriptionNode = xmldoc.createElementNS(null, "description"); setAttribute(descriptionNode, "value", description); fittingNode.appendChild(descriptionNode); //Ship Type Element shipTypeNode = xmldoc.createElementNS(null, "shipType"); setAttribute(shipTypeNode, "value", asset.getTypeName()); fittingNode.appendChild(shipTypeNode); //Sort assets by (last) flag Map> modules = new HashMap>(); for (MyAsset module : asset.getAssets()) { String flag = module.getFlag(); if (flag.contains(" > ")) { //last flag int start = flag.indexOf(" > ") + 3; flag = flag.substring(start); } List subModules = modules.get(flag); if (subModules == null) { //New flag list subModules = new ArrayList(); modules.put(flag, subModules); } subModules.add(module); //Add to flag list } Element hardwareNode; //Low Slots 0-7 for (int i = 0; i < 8; i++) { if (modules.containsKey("LoSlot" + i)) { hardwareNode = xmldoc.createElementNS(null, "hardware"); setAttribute(hardwareNode, "slot", "low slot " + i); setAttribute(hardwareNode, "type", modules.get("LoSlot" + i).get(0).getName()); fittingNode.appendChild(hardwareNode); } } //Medium Slots 0-7 for (int i = 0; i < 8; i++) { if (modules.containsKey("MedSlot" + i)) { hardwareNode = xmldoc.createElementNS(null, "hardware"); setAttribute(hardwareNode, "slot", "med slot " + i); setAttribute(hardwareNode, "type", modules.get("MedSlot" + i).get(0).getName()); fittingNode.appendChild(hardwareNode); } } //High Slots 0-7 for (int i = 0; i < 8; i++) { if (modules.containsKey("HiSlot" + i)) { hardwareNode = xmldoc.createElementNS(null, "hardware"); setAttribute(hardwareNode, "slot", "hi slot " + i); setAttribute(hardwareNode, "type", modules.get("HiSlot" + i).get(0).getName()); fittingNode.appendChild(hardwareNode); } } //Rig Slots 0-7 for (int i = 0; i < 8; i++) { if (modules.containsKey("RigSlot" + i)) { hardwareNode = xmldoc.createElementNS(null, "hardware"); setAttribute(hardwareNode, "slot", "rig slot " + i); setAttribute(hardwareNode, "type", modules.get("RigSlot" + i).get(0).getName()); fittingNode.appendChild(hardwareNode); } } //Sub Systems for (int i = 0; i < 5; i++) { if (modules.containsKey("SubSystem" + i)) { hardwareNode = xmldoc.createElementNS(null, "hardware"); setAttribute(hardwareNode, "slot", "subsystem slot" + i); setAttribute(hardwareNode, "type", modules.get("SubSystem" + i).get(0).getName()); fittingNode.appendChild(hardwareNode); } } //Drone Bay if (modules.containsKey("DroneBay")) { Map moduleCount = new HashMap(); List subModules = modules.get("DroneBay"); for (MyAsset subModule : subModules) { if (moduleCount.containsKey(subModule.getName())) { long count = moduleCount.get(subModule.getName()); moduleCount.remove(subModule.getName()); count = count + subModule.getCount(); moduleCount.put(subModule.getName(), count); } else { moduleCount.put(subModule.getName(), subModule.getCount()); } } for (Map.Entry entry : moduleCount.entrySet()) { hardwareNode = xmldoc.createElementNS(null, "hardware"); setAttribute(hardwareNode, "qty", String.valueOf(entry.getValue())); setAttribute(hardwareNode, "slot", "drone bay"); setAttribute(hardwareNode, "type", entry.getKey()); fittingNode.appendChild(hardwareNode); } } //Cargo if (modules.containsKey("Cargo")) { Map moduleCount = new HashMap(); List subModules = modules.get("Cargo"); for (MyAsset subModule : subModules) { if (moduleCount.containsKey(subModule.getName())) { long count = moduleCount.get(subModule.getName()); moduleCount.remove(subModule.getName()); count = count + subModule.getCount(); moduleCount.put(subModule.getName(), count); } else { moduleCount.put(subModule.getName(), subModule.getCount()); } } for (Map.Entry entry : moduleCount.entrySet()) { hardwareNode = xmldoc.createElementNS(null, "hardware"); setAttribute(hardwareNode, "qty", String.valueOf(entry.getValue())); setAttribute(hardwareNode, "slot", "cargo"); setAttribute(hardwareNode, "type", entry.getKey()); fittingNode.appendChild(hardwareNode); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/FileLock.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.List; import javax.swing.JEditorPane; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.gui.shared.components.JLabelMultilineHtml; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.LoggerFactory; public class FileLock { private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(FileLock.class); private static final Object SYNC_LOCK = new Object(); private static final int MAX_TRIES = 12; //1 minute private static final int DELAY = 5000; private static final List LOCKS = new ArrayList<>(); private static final List OS_LOCKS = new ArrayList<>(); private static boolean safe = false; private static void saferShutdown() { Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { unlockLocked(); } }); } private static void unlockLocked() { LOG.info("Unlocking " + LOCKS.size() + " files"); while (!LOCKS.isEmpty()) { unlock(LOCKS.get(0)); } } private static void add(File file) { if (!safe) { safe = true; saferShutdown(); } LOCKS.add(file); } private static void remove(File file) { LOCKS.remove(file); } public static void unlockAll() { LOG.info("Unlocking all files"); File folder; folder = new File(FileUtil.getPathProfilesDirectory()); unlockFiles(folder.listFiles()); folder = new File(FileUtil.getPathStaticDataDirectory()); unlockFiles(folder.listFiles()); folder = new File(FileUtil.getPathDataDirectory()); unlockFiles(folder.listFiles()); while (!OS_LOCKS.isEmpty()) { try { OS_LOCKS.get(0).close(); } catch (IOException ex) { throw new RuntimeException(ex); } } } private static void unlockFiles(File[] files) { if (files == null) { //We can not be sure directory has been created... return; } for (File file : files) { if (file.getName().endsWith(".LOCK")) { file.delete(); } } } private static void lock(File file) { lock(file, 0, DELAY); } private static void lock(File file, int tries, int delay) { try { tryLockFile(file); } catch (Exception ex) { tries++; if (tries > MAX_TRIES) { JOptionPane.showMessageDialog(null, getMessage(file), General.get().fileLockTitle(), JOptionPane.ERROR_MESSAGE); System.exit(-1); } else { waitForUnlock(file, tries, delay); lock(file, tries, delay); } } } private static synchronized void tryLockFile(File file) throws Exception { if (isLocked(file)) { throw new IOException(); } boolean ok = convertFile(file).createNewFile(); if (!ok) { throw new IOException(); } add(file); } private static synchronized void unlock(File file) { convertFile(file).delete(); remove(file); synchronized (SYNC_LOCK) { SYNC_LOCK.notify(); } } protected static boolean isLocked(File file) { return convertFile(file).exists(); } private static File convertFile(File file) { return new File(file.getAbsolutePath() + ".LOCK"); } private static void waitForUnlock(File file, int tries, int delay) { LOG.info("Waiting for lock: " + file.getName() + " (" + tries + " of " + MAX_TRIES + ")"); try { synchronized (SYNC_LOCK) { SYNC_LOCK.wait(delay); } } catch (InterruptedException ex) { } } private static JEditorPane getMessage(File file) { JLabelMultilineHtml jEditorPane = new JLabelMultilineHtml(General.get().fileLockMsg(file.getName())); return jEditorPane; } public static class SafeFileIO implements Closeable { private final File file; private final boolean skipInternalLock; private Closeable closeable; private FileChannel channel; private java.nio.channels.FileLock lock; public SafeFileIO(String filename) { this(new File(filename)); } public SafeFileIO(File file) { this(file, false); } public SafeFileIO(File file, boolean skipInternalLock) { this.file = file; this.skipInternalLock = skipInternalLock; if (!skipInternalLock) { FileLock.lock(file); //Lock internally - must be first } OS_LOCKS.add(this); } public OutputStreamWriter getOutputStreamWriter() throws IOException { return getOutputStreamWriter(null); } public OutputStreamWriter getOutputStreamWriter(final String encoding) throws IOException { FileOutputStream os = getFileOutputStream(); OutputStreamWriter osw; if (encoding != null) { osw = new OutputStreamWriter(os, encoding); } else { osw = new OutputStreamWriter(os); } closeable = osw; return osw; } public FileOutputStream getFileOutputStream() throws IOException { unlock(); FileOutputStream os = new FileOutputStream(file); closeable = os; channel = os.getChannel(); try { lock = channel.lock(); //Write Lock } catch (IOException ex) { //Ignore operation not supported (the file will not be locked) if (!ex.getMessage().equalsIgnoreCase("Operation not supported")) { throw ex; } } return os; } public FileInputStream getFileInputStream() throws IOException { unlock(); FileInputStream is = new FileInputStream(file); closeable = is; channel = is.getChannel(); try { lock = channel.lock(0, Long.MAX_VALUE, true); //Read Lock } catch (IOException ex) { //Ignore operation not supported (the file will not be locked) if (!ex.getMessage().equalsIgnoreCase("Operation not supported")) { throw ex; } } return is; } public final void unlock() throws IOException { if (lock != null && lock.isValid()) { lock.release(); } if (closeable != null) { closeable.close(); } if (channel != null) { channel.close(); } OS_LOCKS.remove(this); } @Override public final void close() throws IOException { unlock(); if (!skipInternalLock) { FileLock.unlock(file); //Release internally - must be last } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/FlagsReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.util.Map; import net.nikr.eve.jeveasset.data.sde.ItemFlag; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public final class FlagsReader extends AbstractXmlReader { private final Map flags; public FlagsReader(Map flags) { this.flags = flags; } public static boolean load(Map flags) { FlagsReader reader = new FlagsReader(flags); return reader.read("Flags", FileUtil.getPathFlags(), AbstractXmlReader.XmlType.STATIC); } @Override protected Boolean parse(Element element) throws XmlException { parseFlags(element); return true; } @Override protected Boolean failValue() { return false; } @Override protected Boolean doNotExistValue() { return false; } private void parseFlags(final Element element) throws XmlException { NodeList nodes = element.getElementsByTagName("row"); ItemFlag itemFlag; for (int i = 0; i < nodes.getLength(); i++) { Element itemElement = (Element) nodes.item(i); itemFlag = parseFlag(itemElement); flags.put(itemFlag.getFlagID(), itemFlag); } } private ItemFlag parseFlag(final Node node) throws XmlException { int flagID = getInt(node, "flagid"); String flagName = getString(node, "flagname"); String flagText = getString(node, "flagtext"); return new ItemFlag(flagID, flagName, flagText); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/HtmlWriter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.BufferedWriter; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.types.ItemType; import net.nikr.eve.jeveasset.data.settings.types.LocationType; import net.nikr.eve.jeveasset.data.settings.types.LocationsType; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.HierarchyColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.NumberValue; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeAsset; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class HtmlWriter { private static final Logger LOG = LoggerFactory.getLogger(HtmlWriter.class); private HtmlWriter() { } public static boolean save(final String filename, final List, String>> data, final List> header, final List items, final boolean htmlStyled, final int htmlRepeatHeader, final boolean treetable) { HtmlWriter writer = new HtmlWriter(); return writer.write(filename, data, header, items, htmlStyled, htmlRepeatHeader, treetable); } private boolean write(final String filename, final List, String>> data, final List> header, final List items, final boolean htmlStyled, final int htmlRepeatHeader, final boolean treetable) { try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename), "UTF-8"))) { if (htmlStyled) { writeHeader(writer); } else { writeComment(writer); } writer.write("\r\n"); writeTableHeader(writer, header, items != null); writeTableRows(writer, data, header, items, htmlStyled, htmlRepeatHeader, treetable); writer.write("
\r\n"); if (htmlStyled) { writeFooter(writer); } } catch (IOException ex) { LOG.warn("Html file not saved"); return false; } LOG.info("Html file saved"); return true; } private void writeHeader(final BufferedWriter writer) throws IOException { writer.write("\r\n"); writer.write("\r\n"); writer.write("
\r\n"); writeComment(writer); writer.write("\r\n"); writer.write("
\r\n"); writer.write("\r\n"); } private void writeFooter(final BufferedWriter writer) throws IOException { writer.write("\r\n"); writer.write("\r\n"); } private void writeComment(final BufferedWriter writer) throws IOException { writer.write("\r\n"); writer.write("\r\n"); writer.write("\r\n"); } private void writeTableHeader(final BufferedWriter writer, List> header, boolean igb) throws IOException { writer.write("\r\n"); for (EnumTableColumn column : header) { writer.write("\t"); writer.write(column.getColumnName()); writer.write("\r\n"); } if (igb) { writer.write("\t"); writer.write("Links"); writer.write("\r\n"); } writer.write("\r\n"); } private void writeTableRows(final BufferedWriter writer, final List, String>> data, final List> header, final List items, final boolean htmlStyled, final int htmlRepeatHeader, final boolean treetable) throws IOException { boolean even = false; boolean wait = true; int count = 0; int index = 0; for (Map, String> map : data) { boolean level0 = false; boolean level1 = false; boolean level2 = false; boolean level3 = false; if (treetable && htmlStyled) { for (EnumTableColumn column : header) { if (HierarchyColumn.class.isAssignableFrom(column.getType())) { if (map.get(column).contains(TreeAsset.SPACE + TreeAsset.SPACE + TreeAsset.SPACE + "+") && treetable) { //Level 2 level3 = true; } else if (map.get(column).startsWith(TreeAsset.SPACE + TreeAsset.SPACE + "+") && treetable) { //Level 2 level2 = true; break; } else if (map.get(column).startsWith(TreeAsset.SPACE + "+") && treetable) { //Level 1 level1 = true; break; } else if (map.get(column).startsWith("+") && treetable) { //Level 0 level0 = true; break; } } } } if (level0 || level1 || level2 || level3) { //Parent if (!wait) { writeTableHeader(writer, header, items != null); wait = true; count = 0; } } else if (htmlRepeatHeader != 0 && htmlRepeatHeader == count && !wait) { //Repeat writeTableHeader(writer, header, items != null); count = 0; } else { //item row wait = false; } if (level0 && htmlStyled) { writer.write("\t"); } else if (level1 && htmlStyled) { writer.write("\t"); } else if (level2 && htmlStyled) { writer.write("\t"); } else if (level3 && htmlStyled) { writer.write("\t"); } else if (even && htmlStyled) { writer.write("\t"); } else { writer.write("\t"); } for (EnumTableColumn column : header) { if ((Number.class.isAssignableFrom(column.getType()) || NumberValue.class.isAssignableFrom(column.getType()))) { writer.write("\t"); } else { writer.write("\t"); } writer.write(map.get(column).replace(" ", " ").replace("+", "").replace("_", " ")); //.replace("-", "‑") writer.write("\r\n"); } if (items != null) { writer.write("\t\r\n"); Object object = items.get(index); if (object instanceof LocationType) { LocationType locationType = (LocationType) object; MyLocation location = locationType.getLocation(); if (location != null && !location.isEmpty()) { //Region writer.write("\t\tRegion:\r\n"); writer.write("\t\t\r\n"); if (!location.isRegion()) { //System writer.write("\t\tSystem:\r\n"); writer.write("\t\t\r\n"); writer.write("\t\t\r\n"); writer.write("\t\t\r\n"); } if (location.isStation()) { writer.write("\t\tStation:\r\n"); writer.write("\t\t\r\n"); } } } if (object instanceof LocationsType) { LocationsType locationType = (LocationsType) object; Set locations = locationType.getLocations(); for (MyLocation location : locations) { if (location != null && !location.isEmpty()) { //Region writer.write("\t\tRegion:\r\n"); writer.write("\t\t\r\n"); if (!location.isRegion()) { //System writer.write("\t\tSystem:\r\n"); writer.write("\t\t\r\n"); writer.write("\t\t\r\n"); writer.write("\t\t\r\n"); } if (location.isStation()) { writer.write("\t\tStation:\r\n"); writer.write("\t\t\r\n"); } } } } if (object instanceof MyAsset) { MyAsset asset = (MyAsset) object; Item item = asset.getItem(); if (item != null && !item.isEmpty()) { writer.write("\t\tItem:\r\n"); writer.write("\t\t\r\n"); if (item.isMarketGroup()) { writer.write("\t\t\r\n"); } } } else if (object instanceof ItemType) { ItemType itemType = (ItemType) object; Item item = itemType.getItem(); if (item != null && !item.isEmpty()) { writer.write("\t\tItem:\r\n"); writer.write("\t\t\r\n"); if (item.isMarketGroup()) { writer.write("\t\t\r\n"); } } } writer.write("\t\r\n"); } writer.write("\r\n"); even = !even; if (!level0 && !level1 && !level2 && !level3) { count++; } index++; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/ItemsReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.util.HashMap; import java.util.Map; import net.nikr.eve.jeveasset.data.sde.IndustryMaterial; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.ReprocessedMaterial; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public final class ItemsReader extends AbstractXmlReader { private final Map items; public ItemsReader(Map items) { this.items = items; } public static void load(Map items) { ItemsReader reader = new ItemsReader(items); reader.read("Items Updates", FileUtil.getPathItemsUpdates(), AbstractXmlReader.XmlType.DYNAMIC_BACKUP); reader.read("Items", FileUtil.getPathItems(), AbstractXmlReader.XmlType.STATIC); } @Override protected Boolean parse(Element element) throws XmlException { parseItems(element); return true; } @Override protected Boolean failValue() { return false; } @Override protected Boolean doNotExistValue() { return false; } private void parseItems(final Element element) throws XmlException { NodeList nodes = element.getElementsByTagName("row"); Map blueprints = new HashMap<>(); for (int i = 0; i < nodes.getLength(); i++) { Element itemElement = (Element) nodes.item(i); Item item = parseItem(itemElement); parseMaterials(itemElement, item); parseManufacturing(itemElement, item); parseReaction(itemElement, item); items.put(item.getTypeID(), item); if (item.isBlueprint()) { blueprints.put(item.getTypeID(), item.getProductTypeID()); } } for (Map.Entry entry : blueprints.entrySet()) { Item item = items.get(entry.getValue()); if (item != null) { item.addBlueprintID(entry.getKey()); } } } private Item parseItem(final Node node) throws XmlException { int id = getInt(node, "id"); String version = getStringOptional(node, "version"); if (haveAttribute(node, "empty")) { return new Item(id, version); } String name = getString(node, "name"); String group = getString(node, "group"); String category = getString(node, "category"); long basePrice = getLong(node, "price"); float volume = getFloat(node, "volume"); float packagedVolume = getFloatNotNull(node, "packagedvolume", volume); float capacity = getFloatNotNull(node, "capacity", 0f); int meta = getInt(node, "meta"); String tech = getString(node, "tech"); boolean marketGroup = getBoolean(node, "marketgroup"); int portion = getInt(node, "portion"); int product = getIntNotNull(node, "product", 0); int productQuantity = getIntNotNull(node, "productquantity", 1); String slot = getStringOptional(node, "slot"); String chargeSize = getChargeSize(getIntOptional(node, "charges")); return new Item(id, name, group, category, basePrice, volume, packagedVolume, capacity, meta, tech, marketGroup, portion, product, productQuantity, slot, chargeSize, version); } private void parseMaterials(final Element element, final Item item) throws XmlException { NodeList nodes = element.getElementsByTagName("material"); for (int i = 0; i < nodes.getLength(); i++) { parseMaterial(nodes.item(i), item); } } private void parseMaterial(final Node node, final Item item) throws XmlException { int id = getInt(node, "id"); int quantity = getInt(node, "quantity"); int portionSize = getInt(node, "portionsize"); item.addReprocessedMaterial(new ReprocessedMaterial(id, quantity, portionSize)); } private void parseManufacturing(final Element element, final Item item) throws XmlException { NodeList nodes = element.getElementsByTagName("mfg"); for (int i = 0; i < nodes.getLength(); i++) { IndustryMaterial material = parseIndustryMaterial(nodes.item(i)); item.addManufacturingMaterial(material); } } private void parseReaction(final Element element, final Item item) throws XmlException { NodeList nodes = element.getElementsByTagName("rxn"); for (int i = 0; i < nodes.getLength(); i++) { IndustryMaterial material = parseIndustryMaterial(nodes.item(i)); item.addReactionMaterial(material); } } private IndustryMaterial parseIndustryMaterial(final Node node) throws XmlException { int typeID = getInt(node, "id"); int quantity = getInt(node, "q"); return new IndustryMaterial(typeID, quantity); } public static String getChargeSize(Integer chargeSize) { if (chargeSize == null) { return null; } switch (chargeSize) { case 1: return "Small"; case 2: return "Medium"; case 3: return "Large"; case 4: return "Extra Large"; default: return "Unknown (" + chargeSize + ")"; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/ItemsWriter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.util.Collection; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; public class ItemsWriter extends AbstractXmlWriter { private static final Logger LOG = LoggerFactory.getLogger(ItemsWriter.class); public static boolean save() { ItemsWriter writer = new ItemsWriter(); return writer.write(StaticData.get().getItems().values(), FileUtil.getPathItemsUpdates()); } private boolean write(final Collection items, final String filename) { Document xmldoc; try { xmldoc = getXmlDocument("rows"); } catch (XmlException ex) { LOG.error("Items updates not saved " + ex.getMessage(), ex); return false; } writeItems(xmldoc, items); try { writeXmlFile(xmldoc, filename, true); } catch (XmlException ex) { LOG.error("Items updates not saved " + ex.getMessage(), ex); return false; } LOG.info("Items updates saved"); return true; } private void writeItems(final Document xmldoc, final Collection items) { for (Item item : items) { if (item.getVersion() == null) { //From static data continue; } Element node = xmldoc.createElement("row"); setAttribute(node, "id", item.getTypeID()); setAttribute(node, "version", item.getVersion()); if (item.isEmpty()) { setAttribute(node, "empty", String.valueOf(true)); } else { setAttribute(node, "name", item.getTypeName()); setAttribute(node, "group", item.getGroup()); setAttribute(node, "category", item.getCategory()); setAttribute(node, "price", (long) item.getPriceBase()); setAttribute(node, "volume", item.getVolume()); if (item.getVolumePackaged() > 0) { setAttribute(node, "packagedvolume", item.getVolumePackaged()); } if (item.getCapacity() > 0) { setAttribute(node, "capacity", item.getCapacity()); } setAttribute(node, "meta", item.getMeta()); setAttribute(node, "tech", item.getTech()); setAttribute(node, "marketgroup", item.isMarketGroup()); setAttribute(node, "portion", item.getPortion()); setAttribute(node, "product", item.getProductTypeID()); setAttribute(node, "productquantity", item.getProductQuantity()); } xmldoc.getDocumentElement().appendChild(node); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/JumpsReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.util.List; import net.nikr.eve.jeveasset.data.sde.Jump; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public final class JumpsReader extends AbstractXmlReader { private final List jumps; public JumpsReader(List jumps) { this.jumps = jumps; } public static void load(List jumps) { JumpsReader reader = new JumpsReader(jumps); reader.read("Jumps", FileUtil.getPathJumps(), AbstractXmlReader.XmlType.STATIC); } @Override protected Boolean parse(Element element) throws XmlException { parseJumps(element); return true; } @Override protected Boolean failValue() { return false; } @Override protected Boolean doNotExistValue() { return false; } private void parseJumps(final Element element) throws XmlException { NodeList nodes = element.getElementsByTagName("row"); Jump jump; for (int i = 0; i < nodes.getLength(); i++) { jump = parseEdge(nodes.item(i)); jumps.add(jump); } } private Jump parseEdge(final Node node) throws XmlException { long from = getLong(node, "from"); long to = getLong(node, "to"); Jump j = new Jump(StaticData.get().getLocation(from), StaticData.get().getLocation(to)); return j; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/LocationsReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.util.Map; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public final class LocationsReader extends AbstractXmlReader { private final Map locations; public LocationsReader(Map locations) { this.locations = locations; } public static void load(Map locations) { LocationsReader reader = new LocationsReader(locations); reader.read("Locations", FileUtil.getPathLocations(), AbstractXmlReader.XmlType.STATIC); } @Override protected Boolean parse(Element element) throws XmlException { parseLocations(element); return true; } @Override protected Boolean failValue() { return false; } @Override protected Boolean doNotExistValue() { return false; } private void parseLocations(final Element element) throws XmlException { NodeList nodes = element.getElementsByTagName("row"); MyLocation location; for (int i = 0; i < nodes.getLength(); i++) { location = parseLocation(nodes.item(i)); locations.put(location.getLocationID(), location); } } private MyLocation parseLocation(final Node node) throws XmlException { long stationID = getLong(node, "si"); String station = getString(node, "s"); long systemID = getLong(node, "syi"); String system = getString(node, "sy"); long constellationID = getLongNotNull(node, "ci", 0); String constellation = getStringNotNull(node, "c", ""); long regionID = getLong(node, "ri"); String region = getString(node, "r"); String security = getString(node, "se"); return MyLocation.create(stationID, station, systemID, system, constellationID, constellation, regionID, region, security, false, false); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/MarketLogReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.filechooser.FileSystemView; import net.nikr.eve.jeveasset.data.api.raw.RawPublicMarketOrder; import net.nikr.eve.jeveasset.gui.shared.Formatter.DateFormatThreadSafe; import net.nikr.eve.jeveasset.gui.tabs.orders.MarketLog; import net.nikr.eve.jeveasset.gui.tabs.orders.OutbidProcesser; import net.nikr.eve.jeveasset.gui.tabs.orders.OutbidProcesser.OutbidProcesserInput; import net.nikr.eve.jeveasset.gui.tabs.orders.OutbidProcesser.OutbidProcesserOutput; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.supercsv.cellprocessor.CellProcessorAdaptor; import org.supercsv.cellprocessor.Optional; import org.supercsv.cellprocessor.ParseBool; import org.supercsv.cellprocessor.ParseDouble; import org.supercsv.cellprocessor.ParseInt; import org.supercsv.cellprocessor.ParseLong; import org.supercsv.cellprocessor.ift.CellProcessor; import org.supercsv.cellprocessor.ift.StringCellProcessor; import org.supercsv.exception.SuperCsvCellProcessorException; import org.supercsv.io.CsvBeanReader; import org.supercsv.io.ICsvBeanReader; import org.supercsv.prefs.CsvPreference; import org.supercsv.util.CsvContext; public class MarketLogReader { private static final Logger LOG = LoggerFactory.getLogger(MarketLogReader.class); private static final int RETRIES = 3; private static final DateFormatThreadSafe FILE_DATE_FORMAT = new DateFormatThreadSafe("yyyy.MM.dd hhmmss", true); private static final DateFormatThreadSafe DATE_FORMAT = new DateFormatThreadSafe("yyyy-MM-dd HH:mm:ss,SSS"); private final OutbidProcesserInput input; public MarketLogReader(OutbidProcesserInput input) { this.input = input; } public static List read(File file, OutbidProcesserInput input, OutbidProcesserOutput output) { MarketLogReader reader = new MarketLogReader(input); List orders = reader.read(file); OutbidProcesser.process(input, output); return orders; } private List read(final File logFile) { final String filename = logFile.getName(); LOG.info("Reading: " + filename); String[] values = filename.split("-"); if (values.length < 3) { LOG.warn("Failed to read: " + filename); return null; } Date date; try { date = FILE_DATE_FORMAT.parse(values[values.length-1]); } catch (ParseException ex) { LOG.error("Failed to read: " + filename, ex); return null; } List marketLogs = parse(logFile); if (marketLogs == null || marketLogs.isEmpty()) { LOG.warn("Failed to read: " + filename); return null; } Integer typeID = marketLogs.get(0).getTypeID(); if (typeID == null) { LOG.warn("Failed to read: " + filename); return null; } Set marketOrders = new HashSet<>(); for (MarketLog marketLog : marketLogs) { marketOrders.add(new RawPublicMarketOrder(marketLog)); } Map> orders = new HashMap<>(); orders.put(typeID, marketOrders); input.addOrders(orders, date); LOG.info("Read: " + filename); return marketLogs; } private List parse(File file) { return parse(file, 0); } private List parse(File file, int retries) { Reader reader = null; ICsvBeanReader beanReader = null; try { beanReader = new CsvBeanReader(new FileReader(file), CsvPreference.STANDARD_PREFERENCE); beanReader.getHeader(true); // the header elements are used to map the values to the bean (names must match) final String[] header = {"price","volRemaining","typeID","range","orderID","volEntered","minVolume","bid","issueDate","duration","stationID","regionID","solarSystemID","jumps", "empty"}; List marketLogs = new ArrayList<>(); MarketLog marketLog; while ((marketLog = beanReader.read(MarketLog.class, header, getProcessors())) != null) { marketLogs.add(marketLog); } if (marketLogs.isEmpty()) { throw new IllegalArgumentException("Empty file"); } return marketLogs; } catch (SuperCsvCellProcessorException | IOException | IllegalArgumentException ex) { if (retries < RETRIES) { retries++; try { Thread.sleep(retries * 500L); } catch (InterruptedException ex1) { //Keep calm and carry on } LOG.info("Retrying: " + retries + " of " + RETRIES + " (" + retries * 500 + ")"); return parse(file, retries); } else { LOG.error(ex.getMessage(), ex); return null; } } finally { if (beanReader != null) { try { beanReader.close(); } catch (IOException ex) { //No problem } } if (reader != null) { try { reader.close(); } catch (IOException ex) { //No problem } } } } private static CellProcessor[] getProcessors() { return new CellProcessor[]{ new ParseDouble(), // price new ParseDouble(), // volRemaining new ParseInt(), // typeID new ParseInt(), // range new ParseLong(), // orderID new ParseInt(), // volEntered new ParseInt(), // minVolume new ParseBool(), // bid new ParseDate(), // issueDate new ParseInt(), // duration new ParseLong(), // stationID new ParseLong(), // regionID new ParseLong(), // solarSystemID new ParseInt(), // jumps new Optional() }; } public static File getMarketlogsDirectory() { //https://wiki.eveuniversity.org/EVE_logs File documents = FileSystemView.getFileSystemView().getDefaultDirectory(); String home = System.getProperty("user.home"); // can be null StringBuilder builder = new StringBuilder(); if (documents.exists()) { builder.append(documents.getPath()); } else { builder.append(home); } if (!new File(documents.getAbsolutePath() + File.separator + "EVE").exists() && new File(documents.getAbsolutePath() + File.separator + "Documents").exists()) { builder.append(File.separator); builder.append("Documents"); } builder.append(File.separator); builder.append("EVE"); builder.append(File.separator); builder.append("logs"); builder.append(File.separator); builder.append("Marketlogs"); return new File(builder.toString()); } @SuppressWarnings("unchecked") public static class ParseDate extends CellProcessorAdaptor implements StringCellProcessor { public static final DateFormatThreadSafe DATETIME = new DateFormatThreadSafe("yyyy-MM-dd hh:mm:ss", true); public static final DateFormatThreadSafe DATE = new DateFormatThreadSafe("yyyy-MM-dd", true); public ParseDate() { super(); } public ParseDate(CellProcessor next) { // this constructor allows other processors to be chained after ParseDay super(next); } @Override public Object execute(Object value, CsvContext context) { if (value == null) { throw new SuperCsvCellProcessorException( "this processor does not accept null input - if the column is optional then chain an Optional() processor before this one", context, this); } Date result; if (value instanceof Date) { result = (Date) value; } else if (value instanceof String) { try { result = DATETIME.parse((String)value); } catch (ParseException ex) { try { result = DATE.parse((String)value); } catch (ParseException ex2) { throw new SuperCsvCellProcessorException( String.format("'%s' could not be parsed as an Date", value), context, this, ex2); } } } else { final String actualClassName = value.getClass().getName(); throw new SuperCsvCellProcessorException(String.format( "the input value should be of type Date or String but is of type %s", actualClassName), context, this); } return next.execute(result, context); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/NpcCorporationsReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.util.Map; import net.nikr.eve.jeveasset.data.sde.NpcCorporation; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public final class NpcCorporationsReader extends AbstractXmlReader { private final Map npcCorporations; public NpcCorporationsReader(Map npcCorporations) { this.npcCorporations = npcCorporations; } public static void load(Map npcCorporations) { NpcCorporationsReader reader = new NpcCorporationsReader(npcCorporations); reader.read("Npc Corporations", FileUtil.getPathNpcCorporation(), AbstractXmlReader.XmlType.STATIC); } @Override protected Boolean parse(Element element) throws XmlException { parseNpcCorporations(element); return true; } @Override protected Boolean failValue() { return false; } @Override protected Boolean doNotExistValue() { return false; } private void parseNpcCorporations(final Element element) throws XmlException { NodeList nodes = element.getElementsByTagName("row"); for (int i = 0; i < nodes.getLength(); i++) { Element itemElement = (Element) nodes.item(i); NpcCorporation npcCorporation = parseNpcCorporation(itemElement); npcCorporations.put(npcCorporation.isFaction() ? npcCorporation.getFactionID() : npcCorporation.getCorporationID(), npcCorporation); } } private NpcCorporation parseNpcCorporation(final Node node) throws XmlException { String faction = getStringOptional(node, "faction"); int factionID = getInt(node, "factionid"); String corporation = getStringOptional(node, "corporation"); int corporationID = getIntNotNull(node, "corporationid", 0); boolean connections = getBooleanNotNull(node, "c", false); boolean criminalConnections = getBooleanNotNull(node, "cc", false); return new NpcCorporation(faction, factionID, corporation, corporationID, connections, criminalConnections); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/ProfileFinder.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.File; import java.io.FileFilter; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; import net.nikr.eve.jeveasset.data.profile.Profile; import net.nikr.eve.jeveasset.data.profile.Profile.ProfileType; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class ProfileFinder { private static final Logger LOG = LoggerFactory.getLogger(ProfileFinder.class); private ProfileFinder() { } public static boolean load(final ProfileManager profileManager) { ProfileFinder reader = new ProfileFinder(); return reader.read(profileManager); } private boolean read(final ProfileManager profileManager) { backwardCompatibility(); List profiles = new ArrayList<>(); File profilesDirectory = new File(FileUtil.getPathProfilesDirectory()); FileFilter profileFilter = new ProfileFileFilter(); File[] files = profilesDirectory.listFiles(profileFilter); if (files != null) { boolean defaultProfileFound = false; Set unique = new TreeSet<>(StringComparators.CASE_INSENSITIVE); for (File file : files) { String filename = file.getName(); String profileName = formatName(filename); if (!profileName.matches("[\\w\\s]+")) { LOG.warn("Ignoring invalid profile name: {} ({})", profileName, filename); continue; //Ignore invalid names } if (unique.contains(profileName)) { LOG.warn("Ignoring duplicated profile name: {} ({})", profileName, filename); continue; //ignore duplicates } unique.add(profileName); ProfileType type = getProfileType(filename); if (type == null) { continue; } Profile profile = new Profile(profileName, defaultProfile(filename), activeProfile(filename), type); if (profile.isDefaultProfile() && !defaultProfileFound) { LOG.info("Default profile found: {} ({})", profileName, filename); defaultProfileFound = true; profiles.add(0, profile); profileManager.setActiveProfile(profile); } else if (profile.isDefaultProfile() && defaultProfileFound) { LOG.warn("Default profile found (again): {} ({})", profileName, filename); profile.setDefaultProfile(false); profile.setActiveProfile(false); profiles.add(profile); } else { LOG.info("Profile found: {} ({})", profileName, filename); profiles.add(profile); } } if (!defaultProfileFound && !profiles.isEmpty()) { LOG.warn("No default profile found: Using first available"); profiles.get(0).setDefaultProfile(true); profiles.get(0).setActiveProfile(true); profileManager.setActiveProfile(profiles.get(0)); } else if (!defaultProfileFound && profiles.isEmpty()) { LOG.info("No default profile found: Using default profile"); } if (!profiles.isEmpty()) { //At least one profile file found profileManager.setProfiles(profiles); return true; } } return false; } private void backwardCompatibility() { //Create profiles directory File dir = new File(FileUtil.getPathProfilesDirectory()); if (!dir.exists()) { if (dir.mkdirs()) { LOG.info("Created profiles directory"); } else { LOG.error("Failed to make profiles directory"); } } //Move assets.xml to new location File assets = new File(FileUtil.getPathAssetsOld()); if (assets.exists()) { if (assets.renameTo(new File(FileUtil.getPathProfilesDirectory(), "#Default.xml"))) { LOG.info("Moved assets.xml to new location"); } else { LOG.error("Failed to move assets.xml to new location"); } } //Move assets.bac to new location String filename = FileUtil.getPathAssetsOld(); int end = filename.lastIndexOf("."); filename = filename.substring(0, end) + ".bac"; File backup = new File(filename); if (backup.exists()) { if (backup.renameTo(new File(FileUtil.getPathProfilesDirectory(), "#Default.bac"))) { LOG.info("Moved assets.xml to new location"); } else { LOG.error("Failed to move assets.xml to new location"); } } } private String formatName(String name) { if (name.contains(".")) { int end = name.lastIndexOf("."); name = name.substring(0, end); } name = name.replace("_", " "); name = name.replace("#", ""); return name; } private boolean defaultProfile(final String name) { return name.startsWith("#"); } private boolean activeProfile(final String name) { return name.startsWith("#"); } private class ProfileFileFilter implements FileFilter { @Override public boolean accept(final File file) { return !file.isDirectory() && (isXML(file.getName()) || isSQLite(file.getName())); } } private static boolean isXML(String filename) { return filename.endsWith(".xml"); } private static boolean isSQLite(String filename) { return filename.endsWith(".db"); } private static ProfileType getProfileType(String filename) { if(isXML(filename)) { return ProfileType.XML; } else if (isSQLite(filename)) { return ProfileType.SQLITE; } return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/ProfileReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.util.ArrayList; import java.util.Date; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyAccountBalance; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyExtraction; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.data.api.my.MyShip; import net.nikr.eve.jeveasset.data.api.my.MySkill; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.api.raw.RawAccountBalance; import net.nikr.eve.jeveasset.data.api.raw.RawAsset; import net.nikr.eve.jeveasset.data.api.raw.RawBlueprint; import net.nikr.eve.jeveasset.data.api.raw.RawContract; import net.nikr.eve.jeveasset.data.api.raw.RawContract.ContractStatus; import net.nikr.eve.jeveasset.data.api.raw.RawContractItem; import net.nikr.eve.jeveasset.data.api.raw.RawExtraction; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob; import net.nikr.eve.jeveasset.data.api.raw.RawJournal; import net.nikr.eve.jeveasset.data.api.raw.RawJournalRefType; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.Change; import net.nikr.eve.jeveasset.data.api.raw.RawMining; import net.nikr.eve.jeveasset.data.api.raw.RawSkill; import net.nikr.eve.jeveasset.data.api.raw.RawTransaction; import net.nikr.eve.jeveasset.data.profile.Profile; import net.nikr.eve.jeveasset.data.sde.ItemFlag; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.io.esi.EsiCallbackURL; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.DataConverter; import net.nikr.eve.jeveasset.io.shared.RawConverter; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public final class ProfileReader extends AbstractXmlReader { private final Profile profile; public static boolean load(final Profile profile) { return load(profile, profile.getXmlFilename()); } public static boolean load(final Profile profile, final String filename) { ProfileReader reader = new ProfileReader(profile); Boolean ok = reader.read(filename, filename, XmlType.DYNAMIC_BACKUP); if (!ok) { profile.clear(); } return ok; } public ProfileReader(final Profile profile) { this.profile = profile; } @Override protected Boolean parse(Element element) throws XmlException { profile.clear(); //Clear before load (may happen more than once) parseProfile(element, profile); return true; } @Override protected Boolean failValue() { return false; } @Override protected Boolean doNotExistValue() { return true; } private void parseProfile(final Element element, Profile profile) throws XmlException { if (!element.getNodeName().equals("assets")) { throw new XmlException("Wrong root element name."); } //Stockpiles NodeList stockpilesNodes = element.getElementsByTagName("stockpiles"); if (stockpilesNodes.getLength() == 1) { Element stockpilesElement = (Element) stockpilesNodes.item(0); parseStockpiles(stockpilesElement, profile); } //Esi NodeList esiOwnersNodes = element.getElementsByTagName("esiowners"); if (esiOwnersNodes.getLength() == 1) { Element esiElement = (Element) esiOwnersNodes.item(0); parseEsiOwners(esiElement, profile.getEsiOwners()); Map> contracts = new HashMap<>(); for (EsiOwner esiOwner : profile.getEsiOwners()) { for (Map.Entry> entry : esiOwner.getContracts().entrySet()) { if (!entry.getValue().isEmpty()) { contracts.put(entry.getKey(), entry.getValue()); } } } for (Map.Entry> entry : contracts.entrySet()) { for (EsiOwner esiOwner : profile.getEsiOwners()) { if (esiOwner.getContracts().containsKey(entry.getKey())) { esiOwner.getContracts().put(entry.getKey(), entry.getValue()); } } } } } private void parseStockpiles(final Element element, final Profile profile) throws XmlException { NodeList stockpilesNodes = element.getElementsByTagName("stockpile"); Set stockpileIDs = new HashSet<>(); for (int i = 0; i < stockpilesNodes.getLength(); i++) { Element currentNode = (Element) stockpilesNodes.item(i); long id = getLong(currentNode, "id"); stockpileIDs.add(id); } profile.getStockpileIDs().setShown(stockpileIDs); } private void parseEsiOwners(final Element element, final List esiOwners) throws XmlException { NodeList ownerNodes = element.getElementsByTagName("esiowner"); for (int i = 0; i < ownerNodes.getLength(); i++) { Element currentNode = (Element) ownerNodes.item(i); String accountName = getString(currentNode, "accountname"); String refreshToken = getString(currentNode, "refreshtoken"); String scopes = getString(currentNode, "scopes"); Date structuresNextUpdate = getDate(currentNode, "structuresnextupdate"); Date accountNextUpdate = getDate(currentNode, "accountnextupdate"); EsiCallbackURL callbackURL; try { callbackURL = EsiCallbackURL.valueOf(getString(currentNode, "callbackurl")); } catch (IllegalArgumentException ex) { throw new XmlException(ex); } Set roles = EnumSet.noneOf(RolesEnum.class); if (haveAttribute(currentNode, "characterroles")) { for (String role : getString(currentNode, "characterroles").split(",")) { try { roles.add(RolesEnum.valueOf(role)); } catch (IllegalArgumentException ex) { } } } EsiOwner owner = EsiOwner.create(); owner.setRoles(roles); owner.setAccountName(accountName); owner.setScopes(scopes); owner.setStructuresNextUpdate(structuresNextUpdate); owner.setAccountNextUpdate(accountNextUpdate); owner.setAuth(callbackURL, refreshToken, null); parseOwnerType(currentNode, owner); esiOwners.add(owner); } } private void parseOwnerType(final Element node, OwnerType owner) throws XmlException { String ownerName = getString(node, "name"); String corporationName = getStringOptional(node, "corp"); long ownerID = getLong(node, "id"); Date assetsNextUpdate = getDateNotNull(node, "assetsnextupdate"); Date assetsLastUpdate = getDateOptional(node, "assetslastupdate"); Date balanceNextUpdate = getDateNotNull(node, "balancenextupdate"); Date balanceLastUpdate = getDateOptional(node, "balancelastupdate"); boolean showOwner = getBooleanNotNull(node, "show", true) ; boolean invalid = getBooleanNotNull(node, "invalid", false); Date marketOrdersNextUpdate = getDateNotNull(node, "marketordersnextupdate"); Date journalNextUpdate = getDateNotNull(node, "journalnextupdate"); Date transactionsNextUpdate = getDateNotNull(node, "wallettransactionsnextupdate"); Date industryJobsNextUpdate = getDateNotNull(node, "industryjobsnextupdate"); Date contractsNextUpdate = getDateNotNull(node, "contractsnextupdate"); Date locationsNextUpdate = getDateNotNull(node, "locationsnextupdate"); Date blueprintsNextUpdate = getDateNotNull(node, "blueprintsnextupdate"); Date skillsNextUpdate = getDateNotNull(node, "skillsnextupdate"); Date miningNextUpdate = getDateNotNull(node, "miningnextupdate"); owner.setOwnerName(ownerName); owner.setCorporationName(corporationName); owner.setOwnerID(ownerID); owner.setAssetNextUpdate(assetsNextUpdate); owner.setAssetLastUpdate(assetsLastUpdate); owner.setBalanceNextUpdate(balanceNextUpdate); owner.setBalanceLastUpdate(balanceLastUpdate); owner.setShowOwner(showOwner); owner.setInvalid(invalid); owner.setMarketOrdersNextUpdate(marketOrdersNextUpdate); owner.setJournalNextUpdate(journalNextUpdate); owner.setTransactionsNextUpdate(transactionsNextUpdate); owner.setIndustryJobsNextUpdate(industryJobsNextUpdate); owner.setContractsNextUpdate(contractsNextUpdate); owner.setLocationsNextUpdate(locationsNextUpdate); owner.setBlueprintsNextUpdate(blueprintsNextUpdate); owner.setSkillsNextUpdate(skillsNextUpdate); owner.setMiningNextUpdate(miningNextUpdate); NodeList assetNodes = node.getElementsByTagName("assets"); if (assetNodes.getLength() == 1) { parseAssets(assetNodes.item(0), owner, owner.getAssets(), null); } parseActiveShip(node, owner); parseContracts(node, owner); parseBalances(node, owner); parseMarketOrders(node, owner); parseJournals(node, owner); parseTransactions(node, owner); parseIndustryJobs(node, owner); parseBlueprints(node, owner); parseAssetDivisions(node, owner); parseWalletDivisions(node, owner); parseSkills(node, owner); parseMining(node, owner); } private void parseActiveShip(final Element element, final OwnerType owner) throws XmlException { NodeList activeShipNodes = element.getElementsByTagName("activeship"); if(activeShipNodes.getLength() == 1) { Element activeShipNode = (Element) activeShipNodes.item(0); long itemId = getLong(activeShipNode, "itemid"); int typeId = getInt(activeShipNode, "typeid"); long locationId = getLong(activeShipNode, "locationid"); MyShip activeShip = new MyShip(itemId, typeId, locationId); owner.setActiveShip(activeShip); } } private void parseContracts(final Element element, final OwnerType owner) throws XmlException { NodeList contractsNodes = element.getElementsByTagName("contracts"); Map> contracts = new HashMap<>(); for (int a = 0; a < contractsNodes.getLength(); a++) { Element contractsNode = (Element) contractsNodes.item(a); boolean archivedMigrated = getBooleanNotNull(contractsNode, "archived", false); NodeList contractNodes = contractsNode.getElementsByTagName("contract"); for (int b = 0; b < contractNodes.getLength(); b++) { Element contractNode = (Element) contractNodes.item(b); MyContract contract = parseContract(contractNode); if (!archivedMigrated && !contract.isESI() && (contract.isOpen() || contract.isInProgress())) { contract.setStatus(ContractStatus.ARCHIVED); } NodeList itemNodes = contractNode.getElementsByTagName("contractitem"); List contractItems = new ArrayList<>(); for (int c = 0; c < itemNodes.getLength(); c++) { Element currentNode = (Element) itemNodes.item(c); RawContractItem rawContractItem = parseContractItem(currentNode); MyContractItem contractItem = DataConverter.toMyContractItem(rawContractItem, contract); contractItems.add(contractItem); } contracts.put(contract, contractItems); } } owner.setContracts(contracts); } private MyContract parseContract(final Element element) throws XmlException { RawContract rawContract = RawContract.create(); int acceptorID = getInt(element, "acceptorid"); int assigneeID = getInt(element, "assigneeid"); String availabilityString = getStringOptional(element, "availabilitystring"); String availabilityEnum = getStringOptional(element, "availability"); Double buyout = getDoubleOptional(element, "buyout"); Double collateral = getDoubleOptional(element, "collateral"); int contractID = getInt(element, "contractid"); Date dateAccepted = getDateOptional(element, "dateaccepted"); Date dateCompleted = getDateOptional(element, "datecompleted"); Date dateExpired = getDate(element, "dateexpired"); Date dateIssued = getDate(element, "dateissued"); Long endLocationID = getLongOptional(element, "endstationid"); int issuerCorporationID = getInt(element, "issuercorpid"); int issuerID = getInt(element, "issuerid"); Integer daysToComplete = getIntOptional(element, "numdays"); Double price = getDoubleOptional(element, "price"); Double reward = getDoubleOptional(element, "reward"); Long startLocationID = getLongOptional(element, "startstationid"); String statusString = getStringOptional(element, "statusstring"); String statusEnum = getStringOptional(element, "status"); String title = getStringOptional(element, "title"); String typeString = getStringOptional(element, "typestring"); String typeEnum = getStringOptional(element, "type"); Double volume = getDoubleOptional(element, "volume"); boolean forCorporation = getBoolean(element, "forcorp"); boolean esi = getBooleanNotNull(element, "esi", true); rawContract.setAcceptorID(acceptorID); rawContract.setAssigneeID(assigneeID); rawContract.setAvailability(RawConverter.toContractAvailability(availabilityEnum, availabilityString)); rawContract.setAvailabilityString(availabilityString); rawContract.setBuyout(buyout); rawContract.setCollateral(collateral); rawContract.setContractID(contractID); rawContract.setDateAccepted(dateAccepted); rawContract.setDateCompleted(dateCompleted); rawContract.setDateExpired(dateExpired); rawContract.setDateIssued(dateIssued); rawContract.setDaysToComplete(daysToComplete); rawContract.setEndLocationID(endLocationID); rawContract.setForCorporation(forCorporation); rawContract.setIssuerCorporationID(issuerCorporationID); rawContract.setIssuerID(issuerID); rawContract.setPrice(price); rawContract.setReward(reward); rawContract.setStartLocationID(startLocationID); rawContract.setStatus(RawConverter.toContractStatus(statusEnum, statusString)); rawContract.setStatusString(statusString); rawContract.setTitle(title); rawContract.setTypeString(typeString); rawContract.setType(RawConverter.toContractType(typeEnum, typeString)); rawContract.setVolume(volume); MyContract contract = DataConverter.toMyContract(rawContract); contract.setESI(esi); return contract; } private RawContractItem parseContractItem(final Element element) throws XmlException { RawContractItem contractItem = RawContractItem.create(); boolean included = getBoolean(element, "included"); int quantity = getInt(element, "quantity"); long recordID = getLong(element, "recordid"); boolean singleton = getBoolean(element, "singleton"); int typeID = getInt(element, "typeid"); Integer rawQuantity = getIntOptional(element, "rawquantity"); Long itemID = getLongOptional(element, "itemid"); Integer runs = getIntOptional(element, "runs"); Integer materialEfficiency = getIntOptional(element, "me"); Integer timeEfficiency = getIntOptional(element, "te"); contractItem.setIncluded(included); contractItem.setQuantity(quantity); contractItem.setRecordID(recordID); contractItem.setSingleton(singleton); contractItem.setTypeID(typeID); contractItem.setRawQuantity(rawQuantity); contractItem.setItemID(itemID); contractItem.setLicensedRuns(runs); contractItem.setME(materialEfficiency); contractItem.setTE(timeEfficiency); return contractItem; } private void parseBalances(final Element element, final OwnerType owner) throws XmlException { List accountBalances = new ArrayList<>(); NodeList balancesNodes = element.getElementsByTagName("balances"); for (int a = 0; a < balancesNodes.getLength(); a++) { Element currentBalancesNode = (Element) balancesNodes.item(a); NodeList balanceNodes = currentBalancesNode.getElementsByTagName("balance"); for (int b = 0; b < balanceNodes.getLength(); b++) { Element currentNode = (Element) balanceNodes.item(b); RawAccountBalance rawAccountBalance = parseBalance(currentNode); MyAccountBalance accountBalance = DataConverter.toMyAccountBalance(rawAccountBalance, owner); accountBalances.add(accountBalance); } } owner.setAccountBalances(accountBalances); } private RawAccountBalance parseBalance(final Element element) throws XmlException { RawAccountBalance accountBalance = RawAccountBalance.create(); int accountKey = getInt(element, "accountkey"); double balance = getDouble(element, "balance"); accountBalance.setAccountKey(accountKey); accountBalance.setBalance(balance); return accountBalance; } private void parseMarketOrders(final Element element, final OwnerType owner) throws XmlException { NodeList marketOrdersNodes = element.getElementsByTagName("markerorders"); Set marketOrders = new HashSet<>(); for (int a = 0; a < marketOrdersNodes.getLength(); a++) { Element currentMarketOrdersNode = (Element) marketOrdersNodes.item(a); NodeList marketOrderNodes = currentMarketOrdersNode.getElementsByTagName("markerorder"); for (int b = 0; b < marketOrderNodes.getLength(); b++) { Element currentNode = (Element) marketOrderNodes.item(b); MyMarketOrder marketOrder = parseMarketOrder(currentNode, owner); marketOrders.add(marketOrder); } } owner.setMarketOrders(marketOrders); } private MyMarketOrder parseMarketOrder(final Element element, final OwnerType owner) throws XmlException { RawMarketOrder rawMarketOrder = RawMarketOrder.create(); long orderID = getLong(element, "orderid"); long locationID = getLong(element, "stationid"); int volEntered = getInt(element, "volentered"); int volRemaining = getInt(element, "volremaining"); int minVolume = getInt(element, "minvolume"); Integer stateInt = getIntOptional(element, "orderstate"); String stateEnum = getStringOptional(element, "orderstateenum"); String stateString = getStringOptional(element, "orderstatestring"); int typeID = getInt(element, "typeid"); Integer rangeInt = getIntOptional(element, "range"); String rangeEnum = getStringOptional(element, "rangeenum"); String rangeString = getStringOptional(element, "rangestring"); int accountID = getInt(element, "accountkey"); int duration = getInt(element, "duration"); double escrow = getDouble(element, "escrow"); double price = getDouble(element, "price"); int bid = getInt(element, "bid"); Date issued = getDate(element, "issued"); Date created = getDateOptional(element, "created"); String changed = getStringOptional(element, "changed"); Integer issuedBy = getIntOptional(element, "issuedby"); boolean corp = getBooleanNotNull(element, "corp", owner.isCorporation()); boolean esi = getBooleanNotNull(element, "esi", true); NodeList changeNodes = element.getElementsByTagName("change"); Set changes = new HashSet<>(); for (int a = 0; a < changeNodes.getLength(); a++) { Element changeNode = (Element) changeNodes.item(a); Date date = getDate(changeNode, "date"); Double changePrice = getDoubleOptional(changeNode, "price"); Integer changeVolRemaining = getIntOptional(changeNode, "volremaining"); changes.add(new Change(date, changePrice, changeVolRemaining)); } rawMarketOrder.setWalletDivision(accountID); rawMarketOrder.setDuration(duration); rawMarketOrder.setEscrow(escrow); rawMarketOrder.setBuyOrder(bid > 0); rawMarketOrder.setCorp(corp); rawMarketOrder.setIssued(issued); rawMarketOrder.addChanges(changes); rawMarketOrder.addChangesLegacy(created); if (changed != null) { String[] array = changed.split(","); for (String s : array) { try { rawMarketOrder.addChangesLegacy(new Date(Long.valueOf(s))); } catch (NumberFormatException ex) { //No problem.... } } } rawMarketOrder.setIssuedBy(issuedBy); rawMarketOrder.setLocationID(locationID); rawMarketOrder.setMinVolume(minVolume); rawMarketOrder.setOrderID(orderID); rawMarketOrder.setPrice(price); rawMarketOrder.setRange(RawConverter.toMarketOrderRange(rangeInt, rangeEnum, rangeString)); rawMarketOrder.setRangeString(rangeString); rawMarketOrder.setRegionID((int) ApiIdConverter.getLocation(locationID).getRegionID()); rawMarketOrder.setState(RawConverter.toMarketOrderState(stateInt, stateEnum, stateString)); rawMarketOrder.setStateString(stateString); rawMarketOrder.setTypeID(typeID); rawMarketOrder.setVolumeRemain(volRemaining); rawMarketOrder.setVolumeTotal(volEntered); MyMarketOrder marketOrder = DataConverter.toMyMarketOrder(rawMarketOrder, owner); marketOrder.setESI(esi); return marketOrder; } private void parseJournals(final Element element, final OwnerType owner) throws XmlException { NodeList journalsNodes = element.getElementsByTagName("journals"); Set journals = new HashSet<>(); for (int a = 0; a < journalsNodes.getLength(); a++) { Element currentAalletJournalsNode = (Element) journalsNodes.item(a); NodeList journalNodes = currentAalletJournalsNode.getElementsByTagName("journal"); for (int b = 0; b < journalNodes.getLength(); b++) { Element currentNode = (Element) journalNodes.item(b); RawJournal rawJournal = parseJournal(currentNode); MyJournal journal = DataConverter.toMyJournal(rawJournal, owner); journals.add(journal); } } owner.setJournal(journals); } private RawJournal parseJournal(final Element element) throws XmlException { //Base RawJournal rawJournal = RawJournal.create(); Double amount = getDoubleOptional(element, "amount"); Long argID = getLongOptional(element, "argid1"); String argName = getStringOptional(element, "argname1"); Double balance = getDoubleOptional(element, "balance"); Long contextID = getLongOptional(element, "contextid"); String contextType = getStringOptional(element, "contexttype"); String contextTypeString = getStringOptional(element, "contexttypestring"); Date date = getDate(element, "date"); String description; if (haveAttribute(element, "description")) { description = getString(element, "description"); } else { description = argName; } Integer firstPartyID = getIntOptional(element, "ownerid1"); Integer secondPartyID = getIntOptional(element, "ownerid2"); String reason = getStringOptional(element, "reason"); long refID = getLong(element, "refid"); Integer refTypeInt = getIntOptional(element, "reftypeid"); String refTypeString = getStringOptional(element, "reftypestring"); Double taxAmount = getDoubleOptional(element, "taxamount"); Integer taxReceiverID = getIntOptional(element, "taxreceiverid"); //Extra int accountKey = getInt(element, "accountkey"); rawJournal.setAmount(amount); rawJournal.setBalance(balance); rawJournal.setDate(date); rawJournal.setDescription(description); rawJournal.setFirstPartyID(firstPartyID); rawJournal.setReason(reason); rawJournal.setRefID(refID); RawJournalRefType refType = RawConverter.toJournalRefType(refTypeInt, refTypeString); rawJournal.setRefType(refType); rawJournal.setRefTypeString(refTypeString); rawJournal.setSecondPartyID(secondPartyID); rawJournal.setTax(taxAmount); rawJournal.setTaxReceiverID(taxReceiverID); if (argID != null || argName != null) { rawJournal.setContextID(RawConverter.toJournalContextID(argID, argName, refType)); rawJournal.setContextType(RawConverter.toJournalContextType(refType)); } else { rawJournal.setContextID(contextID); rawJournal.setContextType(RawConverter.toJournalContextType(contextType, contextTypeString)); } rawJournal.setContextTypeString(contextTypeString); rawJournal.setAccountKey(accountKey); return rawJournal; } private void parseTransactions(final Element element, final OwnerType owner) throws XmlException { NodeList transactionsNodes = element.getElementsByTagName("wallettransactions"); Set transactions = new HashSet<>(); for (int a = 0; a < transactionsNodes.getLength(); a++) { Element currentTransactionsNode = (Element) transactionsNodes.item(a); NodeList transactionNodes = currentTransactionsNode.getElementsByTagName("wallettransaction"); for (int b = 0; b < transactionNodes.getLength(); b++) { Element currentNode = (Element) transactionNodes.item(b); RawTransaction rawTransaction = parseTransaction(currentNode); MyTransaction transaction = DataConverter.toMyTransaction(rawTransaction, owner); transactions.add(transaction); } } owner.setTransactions(transactions); } private RawTransaction parseTransaction(final Element element) throws XmlException { RawTransaction rawTransaction = RawTransaction.create(); Date date = getDate(element, "transactiondatetime"); long transactionID = getLong(element, "transactionid"); int quantity = getInt(element, "quantity"); int typeID = getInt(element, "typeid"); double price = getDouble(element, "price"); int clientID = getInt(element, "clientid"); long locationID = getLong(element, "stationid"); String transactionType = getString(element, "transactiontype"); String transactionFor = getString(element, "transactionfor"); //New long journalRefID = getLongNotNull(element, "journaltransactionid", 0L); //Extra int accountKey = getIntNotNull(element, "accountkey", 1000); rawTransaction.setClientID(clientID); rawTransaction.setDate(date); rawTransaction.setBuy(RawConverter.toTransactionIsBuy(transactionType)); rawTransaction.setPersonal(RawConverter.toTransactionIsPersonal(transactionFor)); rawTransaction.setJournalRefID(journalRefID); rawTransaction.setLocationID(locationID); rawTransaction.setQuantity(quantity); rawTransaction.setTransactionID(transactionID); rawTransaction.setTypeID(typeID); rawTransaction.setUnitPrice(price); rawTransaction.setAccountKey(accountKey); return rawTransaction; } private void parseIndustryJobs(final Element element, final OwnerType owner) throws XmlException { NodeList industryJobsNodes = element.getElementsByTagName("industryjobs"); Set industryJobs = new HashSet<>(); for (int a = 0; a < industryJobsNodes.getLength(); a++) { Element currentIndustryJobsNode = (Element) industryJobsNodes.item(a); NodeList industryJobNodes = currentIndustryJobsNode.getElementsByTagName("industryjob"); for (int b = 0; b < industryJobNodes.getLength(); b++) { Element currentNode = (Element) industryJobNodes.item(b); if (haveAttribute(currentNode, "blueprintid")) { MyIndustryJob industryJob = parseIndustryJob(currentNode, owner); industryJobs.add(industryJob); } } } owner.setIndustryJobs(industryJobs); } private MyIndustryJob parseIndustryJob(final Element element, final OwnerType owner) throws XmlException { RawIndustryJob rawIndustryJob = RawIndustryJob.create(); int jobID = getInt(element, "jobid"); int installerID = getInt(element, "installerid"); long facilityID = getLong(element, "facilityid"); long stationID = getLong(element, "stationid"); int activityID = getInt(element, "activityid"); long blueprintID = getLong(element, "blueprintid"); int blueprintTypeID = getInt(element, "blueprinttypeid"); long blueprintLocationID = getLong(element, "blueprintlocationid"); long outputLocationID = getLong(element, "outputlocationid"); int runs = getInt(element, "runs"); Double cost = getDoubleOptional(element, "cost"); Integer licensedRuns = getIntOptional(element, "licensedruns"); Float probability = getFloatOptional(element, "probability"); Integer productTypeID = getIntOptional(element, "producttypeid"); Integer statusInt = getIntOptional(element, "status"); String statusEnum = getStringOptional(element, "statusenum"); String statusString = getStringOptional(element, "statusstring"); int duration = getInt(element, "timeinseconds"); Date startDate = getDate(element, "startdate"); Date endDate = getDate(element, "enddate"); Date pauseDate = getDateOptional(element, "pausedate"); Date completedDate = getDateOptional(element, "completeddate"); Integer completedCharacterID = getIntOptional(element, "completedcharacterid"); Integer successfulRuns = getIntOptional(element, "successfulruns"); boolean esi = getBooleanNotNull(element, "esi", true); rawIndustryJob.setActivityID(activityID); rawIndustryJob.setBlueprintID(blueprintID); rawIndustryJob.setBlueprintLocationID(blueprintLocationID); rawIndustryJob.setBlueprintTypeID(blueprintTypeID); rawIndustryJob.setCompletedCharacterID(completedCharacterID); rawIndustryJob.setCompletedDate(completedDate); rawIndustryJob.setCost(cost); rawIndustryJob.setDuration(duration); rawIndustryJob.setEndDate(endDate); rawIndustryJob.setFacilityID(facilityID); rawIndustryJob.setInstallerID(installerID); rawIndustryJob.setJobID(jobID); rawIndustryJob.setLicensedRuns(licensedRuns); rawIndustryJob.setOutputLocationID(outputLocationID); rawIndustryJob.setPauseDate(pauseDate); rawIndustryJob.setProbability(probability); rawIndustryJob.setProductTypeID(productTypeID); rawIndustryJob.setRuns(runs); rawIndustryJob.setStartDate(startDate); rawIndustryJob.setStationID(stationID); rawIndustryJob.setStatus(RawConverter.toIndustryJobStatus(statusInt, statusEnum, statusString)); rawIndustryJob.setStatusString(statusString); rawIndustryJob.setSuccessfulRuns(successfulRuns); MyIndustryJob industryJob = DataConverter.toMyIndustryJob(rawIndustryJob, owner); industryJob.setESI(esi); return industryJob; } private void parseAssets(final Node node, final OwnerType owner, final List assets, final MyAsset parentAsset) throws XmlException { NodeList assetsNodes = node.getChildNodes(); for (int i = 0; i < assetsNodes.getLength(); i++) { Node currentNode = assetsNodes.item(i); if (currentNode.getNodeName().equals("asset")) { RawAsset rawAsset = parseAsset(currentNode, parentAsset); List parents = new ArrayList<>(); if (parentAsset != null) { //Child parents.addAll(parentAsset.getParents()); parents.add(parentAsset); } MyAsset asset = DataConverter.toMyAsset(rawAsset, owner, parents); if (asset == null) { continue; } if (parentAsset == null) { //Root assets.add(asset); } else { //Child parentAsset.addAsset(asset); } parseAssets(currentNode, owner, assets, asset); } } } private RawAsset parseAsset(final Node node, final MyAsset parentAsset) throws XmlException { RawAsset rawAsset = RawAsset.create(); int count = getInt(node, "count"); long itemId = getLong(node, "id"); int typeID = getInt(node, "typeid"); long locationID = getLong(node, "locationid"); if (locationID == 0 && parentAsset != null) { locationID = parentAsset.getLocationID(); } boolean singleton = getBoolean(node, "singleton"); Integer rawQuantity = getIntOptional(node, "rawquantity"); int flagID = 0; if (haveAttribute(node, "flagid")) { flagID = getInt(node, "flagid"); } else { //Workaround for the old system String flag = getString(node, "flag"); for (ItemFlag itemFlag : StaticData.get().getItemFlags().values()) { if (flag.equals(itemFlag.getFlagName())) { flagID = itemFlag.getFlagID(); break; } } } String locationFlagString = getStringOptional(node, "flagstring"); rawAsset.setItemID(itemId); rawAsset.setItemFlag(RawConverter.toFlag(flagID, locationFlagString)); rawAsset.setLocationFlagString(locationFlagString); rawAsset.setLocationID(locationID); rawAsset.setQuantity(RawConverter.toAssetQuantity(count, rawQuantity)); rawAsset.setSingleton(singleton); rawAsset.setTypeID(typeID); return rawAsset; } private void parseBlueprints(final Element element, final OwnerType owners) throws XmlException { Map blueprints = new HashMap<>(); NodeList blueprintsNodes = element.getElementsByTagName("blueprints"); for (int a = 0; a < blueprintsNodes.getLength(); a++) { Element currentBlueprintsNode = (Element) blueprintsNodes.item(a); NodeList blueprintNodes = currentBlueprintsNode.getElementsByTagName("blueprint"); for (int b = 0; b < blueprintNodes.getLength(); b++) { Element currentNode = (Element) blueprintNodes.item(b); RawBlueprint blueprint = parseBlueprint(currentNode); blueprints.put(blueprint.getItemID(), blueprint); } } owners.setBlueprints(blueprints); } private RawBlueprint parseBlueprint(final Node node) throws XmlException { RawBlueprint blueprint = RawBlueprint.create(); long itemID = getLong(node, "itemid"); long locationID = getLong(node, "locationid"); int typeID = getInt(node, "typeid"); int flagID = getInt(node, "flagid"); String locationFlagString = getStringOptional(node, "flagstring"); int quantity = getInt(node, "quantity"); int timeEfficiency = getInt(node, "timeefficiency"); int materialEfficiency = getInt(node, "materialefficiency"); int runs = getInt(node, "runs"); blueprint.setItemID(itemID); blueprint.setItemFlag(RawConverter.toFlag(flagID, locationFlagString)); blueprint.setLocationFlagString(locationFlagString); blueprint.setLocationID(locationID); blueprint.setMaterialEfficiency(materialEfficiency); blueprint.setQuantity(quantity); blueprint.setRuns(runs); blueprint.setTimeEfficiency(timeEfficiency); blueprint.setTypeID(typeID); return blueprint; } private void parseAssetDivisions(final Element element, final OwnerType owners) throws XmlException { Map divisions = new HashMap<>(); NodeList divisionsNodes = element.getElementsByTagName("assetdivisions"); for (int a = 0; a < divisionsNodes.getLength(); a++) { Element currentDivisionsNode = (Element) divisionsNodes.item(a); NodeList divisionNodes = currentDivisionsNode.getElementsByTagName("assetdivision"); for (int b = 0; b < divisionNodes.getLength(); b++) { Element currentNode = (Element) divisionNodes.item(b); int id = getInt(currentNode, "id"); String name = getStringOptional(currentNode, "name"); divisions.put(id, name); } } owners.setAssetDivisions(divisions); } private void parseWalletDivisions(final Element element, final OwnerType owners) throws XmlException { Map divisions = new HashMap<>(); NodeList divisionsNodes = element.getElementsByTagName("walletdivisions"); for (int a = 0; a < divisionsNodes.getLength(); a++) { Element currentDivisionsNode = (Element) divisionsNodes.item(a); NodeList divisionNodes = currentDivisionsNode.getElementsByTagName("walletdivision"); for (int b = 0; b < divisionNodes.getLength(); b++) { Element currentNode = (Element) divisionNodes.item(b); int id = getInt(currentNode, "id"); String name = getStringOptional(currentNode, "name"); divisions.put(id, name); } } owners.setWalletDivisions(divisions); } private void parseSkills(final Element element, final OwnerType owners) throws XmlException { NodeList skillsNodes = element.getElementsByTagName("skills"); for (int a = 0; a < skillsNodes.getLength(); a++) { Element currentSkillsNode = (Element) skillsNodes.item(a); Integer unallocatedSkillPoints = getIntOptional(currentSkillsNode, "unallocated"); Long totalSkillPoints = getLongOptional(currentSkillsNode, "total"); List skills = new ArrayList<>(); NodeList skillNodes = currentSkillsNode.getElementsByTagName("skill"); for (int b = 0; b < skillNodes.getLength(); b++) { Element currentNode = (Element) skillNodes.item(b); int typeID = getInt(currentNode, "id"); long skillpoints = getLong(currentNode, "sp"); int activeSkillLevel = getInt(currentNode, "active"); int trainedSkillLevel = getInt(currentNode, "trained"); RawSkill skill = RawSkill.create(); skill.setTypeID(typeID); skill.setSkillpoints(skillpoints); skill.setActiveSkillLevel(activeSkillLevel); skill.setTrainedSkillLevel(trainedSkillLevel); skills.add(DataConverter.toMySkill(skill, owners)); } owners.setSkills(skills); owners.setTotalSkillPoints(totalSkillPoints); owners.setUnallocatedSkillPoints(unallocatedSkillPoints); } } private void parseMining(final Element element, final OwnerType owners) throws XmlException { NodeList miningsNodes = element.getElementsByTagName("minings"); for (int a = 0; a < miningsNodes.getLength(); a++) { Element currentMiningsNode = (Element) miningsNodes.item(a); List minings = new ArrayList<>(); NodeList miningNodes = currentMiningsNode.getElementsByTagName("mining"); for (int b = 0; b < miningNodes.getLength(); b++) { Element currentNode = (Element) miningNodes.item(b); int typeID = getInt(currentNode, "typeid"); Date date = getDate(currentNode, "date"); long count = getLong(currentNode, "count"); long locationID = getLong(currentNode, "locationid"); Long characterID = getLongOptional(currentNode, "characterid"); if (characterID == null) { characterID = owners.getOwnerID(); } String corporationName = getStringOptional(currentNode, "corporation"); Long corporationID = getLongOptional(currentNode, "corporationid"); boolean forCorporation = getBoolean(currentNode, "forcorp"); RawMining rawMining = RawMining.create(); rawMining.setTypeID(typeID); rawMining.setDate(date); rawMining.setCount(count); rawMining.setLocationID(locationID); rawMining.setCharacterID(characterID); rawMining.setCorporationID(corporationID); rawMining.setCorporationName(corporationName); rawMining.setForCorporation(forCorporation); MyMining mining = DataConverter.toMyMining(rawMining); int index = minings.indexOf(mining); if (index >= 0) { //Duplicate MyMining oldMining = minings.get(index); //Current value if (mining.getCount() > oldMining.getCount()) { //New value higher - Replace minings.remove(index); minings.add(mining); } } else { minings.add(mining); } } owners.setMining(new HashSet<>(minings)); Set extractions = new HashSet<>(); NodeList extractionNodes = currentMiningsNode.getElementsByTagName("extraction"); for (int b = 0; b < extractionNodes.getLength(); b++) { Element currentNode = (Element) extractionNodes.item(b); Date arrival = getDate(currentNode, "arrival"); Date start = getDate(currentNode, "start"); Date decay = getDate(currentNode, "decay"); int moon = getInt(currentNode, "moon"); long structure = getLong(currentNode, "structure"); RawExtraction mining = RawExtraction.create(); mining.setChunkArrivalTime(arrival); mining.setExtractionStartTime(start); mining.setMoonID(moon); mining.setNaturalDecayTime(decay); mining.setStructureID(structure); extractions.add(DataConverter.toMyExtraction(mining)); } owners.setExtractions(extractions); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/SettingsReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.awt.Color; import java.awt.Dimension; import java.awt.Point; import java.io.File; import java.net.Proxy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import net.nikr.eve.jeveasset.ToolLoader.ToolTab; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.MarketOrderRange; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.AddedData; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorTheme.ColorThemeTypes; import net.nikr.eve.jeveasset.data.settings.ExportSettings; import net.nikr.eve.jeveasset.data.settings.ExportSettings.ColumnSelection; import net.nikr.eve.jeveasset.data.settings.ExportSettings.DecimalSeparator; import net.nikr.eve.jeveasset.data.settings.ExportSettings.ExportFormat; import net.nikr.eve.jeveasset.data.settings.ExportSettings.FilterSelection; import net.nikr.eve.jeveasset.data.settings.ExportSettings.LineDelimiter; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingFacility; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingRigs; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingSecurity; import net.nikr.eve.jeveasset.data.settings.MarketOrdersSettings; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings.PriceMode; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings.PriceSource; import net.nikr.eve.jeveasset.data.settings.ProxyData; import net.nikr.eve.jeveasset.data.settings.ReprocessSettings; import net.nikr.eve.jeveasset.data.settings.RouteAvoidSettings; import net.nikr.eve.jeveasset.data.settings.RouteResult; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.Settings.SettingFlag; import net.nikr.eve.jeveasset.data.settings.Settings.SettingsFactory; import net.nikr.eve.jeveasset.data.settings.Settings.TransactionProfitPrice; import net.nikr.eve.jeveasset.data.settings.StockpileGroupSettings; import net.nikr.eve.jeveasset.data.settings.TrackerData; import net.nikr.eve.jeveasset.data.settings.TrackerSettings; import net.nikr.eve.jeveasset.data.settings.TrackerSettings.DisplayType; import net.nikr.eve.jeveasset.data.settings.TrackerSettings.ShowOption; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.data.settings.tag.Tag; import net.nikr.eve.jeveasset.data.settings.tag.TagColor; import net.nikr.eve.jeveasset.data.settings.tag.TagID; import net.nikr.eve.jeveasset.gui.dialogs.settings.SoundsSettingsPanel.SoundOption; import net.nikr.eve.jeveasset.gui.dialogs.settings.UserNameSettingsPanel.UserName; import net.nikr.eve.jeveasset.gui.dialogs.settings.UserPriceSettingsPanel.UserPrice; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.AllColumn; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.CompareType; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.LogicType; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog.Formula; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuJumps.Jump; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager.FormulaColumn; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager.JumpColumn; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.ResizeMode; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.SimpleColumn; import net.nikr.eve.jeveasset.gui.shared.table.View; import net.nikr.eve.jeveasset.gui.sounds.DefaultSound; import net.nikr.eve.jeveasset.gui.sounds.FileSound; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetTableFormat; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetsTab; import net.nikr.eve.jeveasset.gui.tabs.orders.Outbid; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewGroup; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewLocation; import net.nikr.eve.jeveasset.gui.tabs.routing.SolarSystem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileContainer; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileFlag; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerDate; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerNote; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerSkillPointFilter; import net.nikr.eve.jeveasset.gui.tabs.values.AssetValue; import net.nikr.eve.jeveasset.gui.tabs.values.Value; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.io.local.update.Update; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import uk.me.candle.eve.pricing.options.LocationType; public final class SettingsReader extends AbstractXmlReader { public static final int SETTINGS_VERSION = 2; private static final Logger LOG = LoggerFactory.getLogger(SettingsReader.class); private enum ReaderType { SETTINGS, STOCKPILE, TRACKER, ROUTES } private Settings settings; private SettingsFactory settingsFactory; private List stockpilesList; private Map> trackerDataMap; private Map routes; private final ReaderType readerType; private SettingsReader(ReaderType readerType) { this.readerType = readerType; } public static Settings load(final SettingsFactory settingsFactory, final String filename) { SettingsReader reader = new SettingsReader(ReaderType.SETTINGS); reader.setSettingsFactory(settingsFactory); Update updater = new Update(); try { updater.performUpdates(SETTINGS_VERSION, filename); } catch (XmlException ex) { LOG.error(ex.getMessage(), ex); Settings settings = settingsFactory.create(); settings.setSettingsLoadError(true); return settings; } Boolean ok = reader.read("Settings", filename, XmlType.DYNAMIC_BACKUP); Settings settings = reader.getSettings(); if (!ok || settings == null) { settings = settingsFactory.create(); } if (!ok) { settings.setSettingsLoadError(true); } return settings; } private void setSettingsFactory(SettingsFactory settingsFactory) { this.settingsFactory = settingsFactory; } private Settings getSettings() { return settings; } private List getStockpiles() { return stockpilesList; } private Map> getTrackerDataMap() { return trackerDataMap; } private Map getRoutes() { return routes; } public static List loadStockpile(final String filename) { SettingsReader reader = new SettingsReader(ReaderType.STOCKPILE); if (reader.read(filename, filename, XmlType.IMPORT)) { return reader.getStockpiles(); } else { return null; } } public static Map> loadTracker(final String filename) { SettingsReader reader = new SettingsReader(ReaderType.TRACKER); if (reader.read(filename, filename, XmlType.IMPORT)) { return reader.getTrackerDataMap(); } else { return null; } } public static Map loadRoutes(final String filename) { SettingsReader reader = new SettingsReader(ReaderType.ROUTES); if (reader.read(filename, filename, XmlType.IMPORT)) { return reader.getRoutes(); } else { return null; } } @Override protected Boolean parse(Element element) throws XmlException { switch (readerType) { case SETTINGS: settings = loadSettings(element, settingsFactory.create()); break; case STOCKPILE: stockpilesList = loadStockpile(element); break; case TRACKER: trackerDataMap = loadTracker(element); break; case ROUTES: routes = loadRoutes(element); break; } return true; } @Override protected Boolean failValue() { return false; } @Override protected Boolean doNotExistValue() { return true; } private Map> loadTracker(final Element element) throws XmlException { if (!element.getNodeName().equals("settings")) { throw new XmlException("Wrong root element name."); } //Tracker Data NodeList trackerDataNodes = element.getElementsByTagName("trackerdata"); if (trackerDataNodes.getLength() == 1) { Element trackerDataElement = (Element) trackerDataNodes.item(0); return parseTrackerData(trackerDataElement); } return null; } private List loadStockpile(final Element element) throws XmlException { if (!element.getNodeName().equals("settings")) { throw new XmlException("Wrong root element name."); } //Stockpiles List stockpiles = new ArrayList<>(); NodeList stockpilesNodes = element.getElementsByTagName("stockpiles"); if (stockpilesNodes.getLength() == 1) { Element stockpilesElement = (Element) stockpilesNodes.item(0); parseStockpiles(stockpilesElement, stockpiles, null); } return stockpiles; } private Map loadRoutes(final Element element) throws XmlException { if (!element.getNodeName().equals("settings")) { throw new XmlException("Wrong root element name."); } //Routing Map map = new HashMap<>(); Element routingElement = getNodeOptional(element, "routingsettings"); if (routingElement != null) { parseRoutes(routingElement, map); } return map; } private Settings loadSettings(final Element element, final Settings settings) throws XmlException { if (!element.getNodeName().equals("settings")) { throw new XmlException("Wrong root element name."); } //Manufacturing Prices Element manufacturingElement = getNodeOptional(element, "manufacturing"); if (manufacturingElement != null) { parseManufacturingPriceSettings(manufacturingElement, settings); } //Price History Element priceHistoryElement = getNodeOptional(element, "pricehistory"); if (priceHistoryElement != null) { parsePriceHistorySettings(priceHistoryElement, settings); } //Faction Warfare System Owners Element factionWarfareSystemOwnersElement = getNodeOptional(element, "factionwarfaresystemowners"); if (factionWarfareSystemOwnersElement != null) { parseFactionWarfareSystemOwners(factionWarfareSystemOwnersElement, settings); } //Color Settings Element colorSettingsElement = getNodeOptional(element, "colorsettings"); if (colorSettingsElement != null) { parseColorSettings(colorSettingsElement, settings); } //Sound Settings Element soundSettingsElement = getNodeOptional(element, "soundsettings"); if (soundSettingsElement != null) { parseSoundSettings(soundSettingsElement, settings); } //Tracker Settings Element trackerSettingsElement = getNodeOptional(element, "trackersettings"); if (trackerSettingsElement != null) { parseTrackerSettings(trackerSettingsElement, settings); } //Show Tools Element showToolsElement = getNodeOptional(element, "showtools"); if (showToolsElement != null) { parseShowToolsNodes(showToolsElement, settings); } //Outbid Element marketOrderOutbidElement = getNodeOptional(element, "marketorderoutbid"); if (marketOrderOutbidElement != null) { parseMarketOrderOutbidNodes(marketOrderOutbidElement, settings); } //Routing Element routingElement = getNodeOptional(element, "routingsettings"); if (routingElement != null) { parseRoutingSettings(routingElement, settings); } //Jumps Avoid Element jumpsElement = getNodeOptional(element, "jumpssettings"); if (jumpsElement != null) { parseJumpsSettings(jumpsElement, settings); } //Tags - Must be loaded before stockpiles (and everything else that uses tags) Element tagsElement = getNodeOptional(element, "tags"); if (tagsElement != null) { parseTags(tagsElement, settings); } //Owners Element ownersElement = getNodeOptional(element, "owners"); if (ownersElement != null) { parseOwners(ownersElement, settings); } //Tracker Data Element trackerDataElement = getNodeOptional(element, "trackerdata"); if (trackerDataElement != null) { Map> trackerData = parseTrackerData(trackerDataElement); TrackerData.set(trackerData); } //Tracker Data Element trackerNoteElement = getNodeOptional(element, "trackernotes"); if (trackerNoteElement != null) { parseTrackerNotes(trackerNoteElement, settings); } //Tracker Filters Element trackerFilterElement = getNodeOptional(element, "trackerfilters"); if (trackerFilterElement != null) { parseTrackerFilters(trackerFilterElement, settings); } //Asset Settings Element assetSettingsElement = getNodeOptional(element, "assetsettings"); if (assetSettingsElement != null) { parseAssetSettings(assetSettingsElement, settings); } //Stockpiles Element stockpilesElement = getNodeOptional(element, "stockpiles"); if (stockpilesElement != null) { parseStockpiles(stockpilesElement, settings.getStockpiles(), settings.getStockpileGroupSettings()); } //Stockpile Groups Element stockpileGroupsElement = getNodeOptional(element, "stockpilegroups"); if (stockpileGroupsElement != null) { parseStockpileGroups(stockpileGroupsElement, settings); } //Export Settings //Legacy support for 6.8.0 and later //TODO: Remove support at some future date Element exportElementLegacy = getNodeOptional(element, "csvexport"); if (exportElementLegacy != null) { parseExportSettingsLegacy(exportElementLegacy, settings); } //Export Settings Element exportElement = getNodeOptional(element, "exports"); if (exportElement != null) { parseExportSettings(exportElement, settings); } //Import Settings Element importElement = getNodeOptional(element, "imports"); if (importElement != null) { parseImportSettings(importElement, settings); } //Overview Element overviewElement = getNodeOptional(element, "overview"); if (overviewElement != null) { parseOverview(overviewElement, settings); } //Window Element windowElement = getNodeOptional(element, "window"); if (windowElement != null) { parseWindow(windowElement, settings); } //Reprocessing Element reprocessingElement = getNodeOptional(element, "reprocessing"); if (reprocessingElement != null) { parseReprocessing(reprocessingElement, settings); } //UserPrices Element userPriceElement = getNode(element, "userprices"); parseUserPrices(userPriceElement, settings); //User Item Names Element userItemNameElement = getNodeOptional(element, "itemmames"); if (userItemNameElement != null) { parseUserItemNames(userItemNameElement, settings); } //Eve Item Names Element eveNameElement = getNodeOptional(element, "evenames"); if (eveNameElement != null) { parseEveNames(eveNameElement, settings); } //PriceDataSettings Element priceDataSettingsElement = getNode(element, "marketstat"); parsePriceDataSettings(priceDataSettingsElement, settings); //MarketOrdersSettings Element marketOrdersSettingsElement = getNodeOptional(element, "marketorderssettings"); if (marketOrdersSettingsElement != null) { parseMarketOrdersSettings(marketOrdersSettingsElement, settings); } //Flags Element flagsElement = getNode(element, "flags"); parseFlags(flagsElement, settings); //Table Changes Element tableChangesElement = getNodeOptional(element, "tablechanges"); if (tableChangesElement != null) { parseTableChanges(tableChangesElement, settings); } //Table Formulas (Must be loaded before filters) Element tableFormulasElement = getNodeOptional(element, "tableformulas"); if (tableFormulasElement != null) { parseTableFormulas(tableFormulasElement, settings); } //Table Jumps (Must be loaded before filters) Element tableJumpsElement = getNodeOptional(element, "tablejumps"); if (tableJumpsElement != null) { parseTableJumps(tableJumpsElement, settings); } // Skill Plans Element skillPlansElement = getNodeOptional(element, "skillplans"); if (skillPlansElement != null) { parseSkillPlans(skillPlansElement, settings); } //Table Filters (Must be loaded before Asset Filters) Element tablefiltersElement = getNodeOptional(element, "tablefilters"); if (tablefiltersElement != null) { parseTableFilters(tablefiltersElement, settings); } //Current Table Filters (Must be loaded before Asset Filters) Element currentTableFiltersElement = getNodeOptional(element, "currenttablefilters"); if (currentTableFiltersElement != null) { parseCurrentTableFilters(currentTableFiltersElement, settings); } //Current Table Filters (Must be loaded before Asset Filters) Element currentTableSortingElement = getNodeOptional(element, "currenttablesorting"); if (currentTableSortingElement != null) { parseCurrentTableSorting(currentTableSortingElement, settings); } //Asset Filters Element filtersElement = getNodeOptional(element, "filters"); if (filtersElement != null) { parseAssetFilters(filtersElement, settings); } //Table Columns Element tablecolumnsElement = getNodeOptional(element, "tablecolumns"); if (tablecolumnsElement != null) { parseTableColumns(tablecolumnsElement, settings); } //Table Columns Width Element tableColumnsWidthElement = getNodeOptional(element, "tablecolumnswidth"); if (tableColumnsWidthElement != null) { parseTableColumnsWidth(tableColumnsWidthElement, settings); } //Table Resize Element tableResizeElement = getNodeOptional(element, "tableresize"); if (tableResizeElement != null) { parseTableResize(tableResizeElement, settings); } //Table Views Element tableViewsElement = getNodeOptional(element, "tableviews"); if (tableViewsElement != null) { parseTableViews(tableViewsElement, settings); } //Asset added Element assetaddedElement = getNodeOptional(element, "assetadded"); if (assetaddedElement != null) { parseAssetAdded(assetaddedElement); } // Proxy can have 0 or 1 proxy elements; at 0, the proxy stays as null. Element proxyElement = getNodeOptional(element, "proxy"); if (proxyElement != null) { parseProxy(proxyElement, settings); } return settings; } private void parseSkillPlans(final Element element, final Settings settings) throws XmlException { NodeList planNodes = element.getElementsByTagName("plan"); for (int i = 0; i < planNodes.getLength(); i++) { Element planNode = (Element) planNodes.item(i); String name = getString(planNode, "name"); Map map = new HashMap<>(); NodeList reqNodes = planNode.getElementsByTagName("req"); for (int j = 0; j < reqNodes.getLength(); j++) { Element reqNode = (Element) reqNodes.item(j); int typeId = getInt(reqNode, "typeid"); int level = getInt(reqNode, "level"); map.put(typeId, level); } settings.getSkillPlans().put(name, map); } } private void parseOwners(final Element element, final Settings settings) throws XmlException { long ONE_DAY = 1000 * 60 * 60 * 24; NodeList ownerNodeList = element.getElementsByTagName("owner"); int count = 1; for (int i = 0; i < ownerNodeList.getLength(); i++) { //Read Owner Element ownerNode = (Element) ownerNodeList.item(i); String ownerName = getString(ownerNode, "name"); long ownerID = getLong(ownerNode, "id"); Date date = getDateOptional(ownerNode, "date"); if (date == null) { //1-30 days from now date = new Date(System.currentTimeMillis() + (ONE_DAY * count)); count++; if (count > 30) { count = 1; } } settings.getOwners().put(ownerID, ownerName); settings.getOwnersNextUpdate().put(ownerID, date); } } private Map> parseTrackerData(final Element element) throws XmlException { Map> trackerData = new HashMap<>(); NodeList tableNodeList = element.getElementsByTagName("owner"); for (int a = 0; a < tableNodeList.getLength(); a++) { //Read Owner Element ownerNode = (Element) tableNodeList.item(a); String owner = getString(ownerNode, "name"); //Ignore grand total, not used anymore if (owner.isEmpty()) { continue; } //Data NodeList dataNodeList = ownerNode.getElementsByTagName("data"); for (int b = 0; b < dataNodeList.getLength(); b++) { //Read data Element dataNode = (Element) dataNodeList.item(b); Date date = getDate(dataNode, "date"); double assetsTotal = getDouble(dataNode, "assets"); double escrows = getDouble(dataNode, "escrows"); double escrowstocover = getDouble(dataNode, "escrowstocover"); double sellorders = getDouble(dataNode, "sellorders"); double balanceTotal = getDouble(dataNode, "walletbalance"); double manufacturing = getDoubleNotNull(dataNode, "manufacturing", 0.0); double contractCollateral = getDoubleNotNull(dataNode, "contractcollateral", 0.0); double contractValue = getDoubleNotNull(dataNode, "contractvalue", 0.0); //Add data Value value = new Value(date); //Balance NodeList balanceNodeList = dataNode.getElementsByTagName("balance"); for (int c = 0; c < balanceNodeList.getLength(); c++) { //New data Element balanceNode = (Element) balanceNodeList.item(c); String id = getString(balanceNode, "id"); double balance = getDouble(balanceNode, "value"); value.addBalance(id, balance); } if (balanceNodeList.getLength() == 0) { //Old data value.setBalanceTotal(balanceTotal); } //Assets NodeList assetNodeList = dataNode.getElementsByTagName("asset"); for (int c = 0; c < assetNodeList.getLength(); c++) { //New data Element assetNode = (Element) assetNodeList.item(c); AssetValue assetValue = parseAssetValue(assetNode); double assets = getDouble(assetNode, "value"); value.addAssets(assetValue, assets); } if (assetNodeList.getLength() == 0) { //Old data value.setAssetsTotal(assetsTotal); } value.setEscrows(escrows); value.setEscrowsToCover(escrowstocover); value.setSellOrders(sellorders); value.setManufacturing(manufacturing); value.setContractCollateral(contractCollateral); value.setContractValue(contractValue); List list = trackerData.get(owner); if (list == null) { list = new ArrayList<>(); trackerData.put(owner, list); } list.add(value); } } return trackerData; } private AssetValue parseAssetValue(Element node) throws XmlException { if (haveAttribute(node, "id")) { String id = getString(node, "id"); return AssetValue.create(id); } else { String location = getString(node, "location"); Long locationID = getLongOptional(node, "locationid"); String flag = getStringOptional(node, "flag"); return AssetValue.create(location, flag, locationID); } } private void parseTrackerNotes(final Element element, final Settings settings) throws XmlException { NodeList noteNodeList = element.getElementsByTagName("trackernote"); for (int a = 0; a < noteNodeList.getLength(); a++) { //Read Owner Element noteNode = (Element) noteNodeList.item(a); String note = getString(noteNode, "note"); Date date = getDate(noteNode, "date"); settings.getTrackerSettings().getNotes().put(new TrackerDate(date), new TrackerNote(note)); } } private void parseTrackerFilters(final Element element, final Settings settings) throws XmlException { NodeList tableNodeList = element.getElementsByTagName("trackerfilter"); boolean selectNew = getBoolean(element, "selectnew"); settings.getTrackerSettings().setSelectNew(selectNew); for (int a = 0; a < tableNodeList.getLength(); a++) { Element trackerFilterNode = (Element) tableNodeList.item(a); String id = getString(trackerFilterNode, "id"); boolean selected = getBoolean(trackerFilterNode, "selected"); settings.getTrackerSettings().getFilters().put(id, selected); } NodeList skillPointFiltersList = element.getElementsByTagName("skillpointfilters"); for (int a = 0; a < skillPointFiltersList.getLength(); a++) { Element filterNode = (Element) skillPointFiltersList.item(a); String id = getString(filterNode, "id"); boolean selected = getBoolean(filterNode, "selected"); long mimimum = getLong(filterNode, "mimimum"); settings.getTrackerSettings().getSkillPointFilters().put(id, new TrackerSkillPointFilter(id, selected, mimimum)); } } private void parseAssetSettings(final Element assetSettingsElement, final Settings settings) throws XmlException { int maximumPurchaseAge = getInt(assetSettingsElement, "maximumpurchaseage"); TransactionProfitPrice transactionProfitPrice = TransactionProfitPrice.LASTEST; if (haveAttribute(assetSettingsElement, "transactionprofitprice")) { try { transactionProfitPrice = TransactionProfitPrice.valueOf(getString(assetSettingsElement, "transactionprofitprice")); } catch (IllegalArgumentException ex) { //No problem already set } } int transactionProfitMargin = getIntNotNull(assetSettingsElement, "transactionprofitmargin", 0); settings.setTransactionProfitPrice(transactionProfitPrice); settings.setMaximumPurchaseAge(maximumPurchaseAge); settings.setTransactionProfitMargin(transactionProfitMargin); } private void parseStockpileGroups(final Element stockpilesElement, final Settings settings) throws XmlException { int group2 = getInt(stockpilesElement, "stockpilegroup2"); int group3 = getInt(stockpilesElement, "stockpilegroup3"); if (group2 <= 0) { group2 = 100; } settings.setStockpileColorGroup2(group2); settings.setStockpileColorGroup3(group3); } /** * -!- `!´ IMPORTANT `!´ -!- * StockpileDataWriter and StockpileDataReader needs to be updated too - on any changes!!! */ private void parseStockpiles(final Element stockpilesElement, final List stockpiles, StockpileGroupSettings stockpileGroupSettings) throws XmlException { NodeList stockpileNodes = stockpilesElement.getElementsByTagName("stockpile"); Map stockpileMap = new HashMap<>(); Map> subpileMap = new HashMap<>(); for (int a = 0; a < stockpileNodes.getLength(); a++) { Element stockpileNode = (Element) stockpileNodes.item(a); String name = getString(stockpileNode, "name"); Long stockpileID = getLongOptional(stockpileNode, "id"); //If null > get new id //LEGACY //Owners List ownerIDs = new ArrayList<>(); if (haveAttribute(stockpileNode, "characterid")) { long ownerID = getLong(stockpileNode, "characterid"); if (ownerID > 0) { ownerIDs.add(ownerID); } } //Containers List containers = new ArrayList<>(); if (haveAttribute(stockpileNode, "container")) { String container = getString(stockpileNode, "container"); if (!container.equals(General.get().all())) { containers.add(new StockpileContainer(container, false)); } } //Flags List flags = new ArrayList<>(); if (haveAttribute(stockpileNode, "flagid")) { int flagID = getInt(stockpileNode, "flagid"); if (flagID > 0) { flags.add(new StockpileFlag(flagID, true)); } } //Locations MyLocation location = null; if (haveAttribute(stockpileNode, "locationid")) { long locationID = getLong(stockpileNode, "locationid"); location = ApiIdConverter.getLocation(locationID); } boolean exclude = false; //Include Boolean inventory = getBooleanOptional(stockpileNode, "inventory"); Boolean sellOrders = getBooleanOptional(stockpileNode, "sellorders"); Boolean buyOrders = getBooleanOptional(stockpileNode, "buyorders"); Boolean jobs = getBooleanOptional(stockpileNode, "jobs"); List filters = new ArrayList<>(); if (inventory != null && sellOrders != null && buyOrders != null && jobs != null) { StockpileFilter filter = new StockpileFilter(location, exclude, flags, containers, ownerIDs, null, null, null, inventory, sellOrders, buyOrders, jobs, false, false, false, false, false, false); filters.add(filter); } //NEW NodeList filterNodes = stockpileNode.getElementsByTagName("stockpilefilter"); for (int b = 0; b < filterNodes.getLength(); b++) { Element filterNode = (Element) filterNodes.item(b); //Include boolean filterExclude = getBooleanNotNull(filterNode, "exclude", false); Boolean filterSingleton = getBooleanOptional(filterNode, "singleton"); Integer filterJobsDaysLess = getIntOptional(filterNode, "jobsdaysless"); Integer filterJobsDaysMore = getIntOptional(filterNode, "jobsdaysmore"); boolean filterSellingContracts = getBooleanNotNull(filterNode, "sellingcontracts", false); boolean filterSoldBuy = getBooleanNotNull(filterNode, "soldcontracts", false); boolean filterBuyingContracts = getBooleanNotNull(filterNode, "buyingcontracts", false); boolean filterBoughtContracts = getBooleanNotNull(filterNode, "boughtcontracts", false); boolean filterInventory = getBoolean(filterNode, "inventory"); boolean filterSellOrders = getBoolean(filterNode, "sellorders"); boolean filterBuyOrders = getBoolean(filterNode, "buyorders"); boolean filterBuyTransactions = getBooleanNotNull(filterNode, "buytransactions", false); boolean filterSellTransactions = getBooleanNotNull(filterNode, "selltransactions", false); boolean filterJobs = getBoolean(filterNode, "jobs"); //Location long locationID = getLong(filterNode, "locationid"); location = ApiIdConverter.getLocation(locationID); //Owners List filterOwnerIDs = new ArrayList<>(); NodeList ownerNodes = filterNode.getElementsByTagName("owner"); for (int c = 0; c < ownerNodes.getLength(); c++) { Element ownerNode = (Element) ownerNodes.item(c); long filterOwnerID = getLong(ownerNode, "ownerid"); filterOwnerIDs.add(filterOwnerID); } //Containers List filterContainers = new ArrayList<>(); NodeList containerNodes = filterNode.getElementsByTagName("container"); for (int c = 0; c < containerNodes.getLength(); c++) { Element containerNode = (Element) containerNodes.item(c); String filterContainer = getString(containerNode, "container"); boolean filterIncludeSubs = getBooleanNotNull(containerNode, "includecontainer", false); filterContainers.add(new StockpileContainer(filterContainer, filterIncludeSubs)); } //Flags List filterFlags = new ArrayList<>(); NodeList flagNodes = filterNode.getElementsByTagName("flag"); for (int c = 0; c < flagNodes.getLength(); c++) { Element flagNode = (Element) flagNodes.item(c); int filterFlagID = getInt(flagNode, "flagid"); boolean filterIncludeSubs = getBooleanNotNull(flagNode, "includecontainer", true); filterFlags.add(new StockpileFlag(filterFlagID, filterIncludeSubs)); } StockpileFilter stockpileFilter = new StockpileFilter(location, filterExclude, filterFlags, filterContainers, filterOwnerIDs, filterJobsDaysLess, filterJobsDaysMore, filterSingleton, filterInventory, filterSellOrders, filterBuyOrders, filterJobs, filterBuyTransactions, filterSellTransactions, filterSellingContracts, filterSoldBuy, filterBuyingContracts, filterBoughtContracts); filters.add(stockpileFilter); } //SUBPILES NodeList subpileNodes = stockpileNode.getElementsByTagName("subpile"); Map subpileNames = new HashMap<>(); for (int b = 0; b < subpileNodes.getLength(); b++) { Element subpileNode = (Element) subpileNodes.item(b); String subpileName = getString(subpileNode, "name"); double minimum = getDouble(subpileNode, "minimum"); subpileNames.put(subpileName, minimum); } //MULTIPLIER double multiplier = getDoubleNotNull(stockpileNode, "multiplier", 1); //GROUP String group = getStringOptional(stockpileNode, "stockpilegroup"); //Null is handled by settings //MATCH ALL boolean matchAll; if (haveAttribute(stockpileNode, "contractsmatchall")) { matchAll = getBoolean(stockpileNode, "contractsmatchall"); } else { matchAll = getBooleanNotNull(stockpileNode, "matchall", false); } Stockpile stockpile = new Stockpile(name, stockpileID, filters, multiplier, matchAll); if (stockpileGroupSettings != null) { stockpileGroupSettings.setGroup(stockpile, group); } stockpiles.add(stockpile); subpileMap.put(stockpile, subpileNames); stockpileMap.put(name, stockpile); //ITEMS NodeList itemNodes = stockpileNode.getElementsByTagName("item"); for (int b = 0; b < itemNodes.getLength(); b++) { Element itemNode = (Element) itemNodes.item(b); long id; if (haveAttribute(itemNode, "id")) { id = getLong(itemNode, "id"); } else { id = StockpileItem.getNewID(); } int typeID = getInt(itemNode, "typeid"); boolean runs = getBooleanNotNull(itemNode, "runs", false); boolean ignoreMultiplier = getBooleanNotNull(itemNode, "ignoremultiplier", false); double countMinimum = getDouble(itemNode, "minimum"); if (typeID != 0) { //Ignore Total Item item = ApiIdConverter.getItemUpdate(Math.abs(typeID), true); StockpileItem stockpileItem = new StockpileItem(stockpile, item, typeID, countMinimum, runs, ignoreMultiplier, id); stockpile.add(stockpileItem); } } } for (Map.Entry> entry : subpileMap.entrySet()) { for (Map.Entry entry1 : entry.getValue().entrySet()) { Stockpile stockpile = stockpileMap.get(entry1.getKey()); if (stockpile != null) { entry.getKey().getSubpiles().put(stockpile, entry1.getValue()); stockpile.addSubpileLink(entry.getKey()); } } } subpileMap.clear(); stockpileMap.clear(); Collections.sort(stockpiles); } private void parseManufacturingPriceSettings(Element manufacturingElement, Settings settings) throws XmlException { ManufacturingSettings manufacturingSettings = settings.getManufacturingSettings(); Date nextUpdate = getDate(manufacturingElement, "nextupdate"); ManufacturingFacility facility; try { facility = ManufacturingFacility.valueOf(getString(manufacturingElement, "facility")); } catch (IllegalArgumentException ex) { facility = ManufacturingFacility.getDefault(); } ManufacturingRigs rigs; try { rigs = ManufacturingRigs.valueOf(getString(manufacturingElement, "rigs")); } catch (IllegalArgumentException ex) { rigs = ManufacturingRigs.getDefault(); } ManufacturingSecurity security; try { security = ManufacturingSecurity.valueOf(getString(manufacturingElement, "security")); } catch (IllegalArgumentException ex) { security = ManufacturingSecurity.getDefault(); } int system = getInt(manufacturingElement, "systemid"); int materialEfficiency = getInt(manufacturingElement, "me"); double tax = getDouble(manufacturingElement, "tax"); manufacturingSettings.setNextUpdate(nextUpdate); manufacturingSettings.setFacility(facility); manufacturingSettings.setRigs(rigs); manufacturingSettings.setSecurity(security); manufacturingSettings.setSystemID(system); manufacturingSettings.setMaterialEfficiency(materialEfficiency); manufacturingSettings.setTax(tax); //Manufacturing Adjusted Prices Map manufacturingPrices = new HashMap<>(); NodeList priceNodes = manufacturingElement.getElementsByTagName("price"); for (int a = 0; a < priceNodes.getLength(); a++) { Element priceNode = (Element) priceNodes.item(a); int typeID = getInt(priceNode, "typeid"); double price = getDouble(priceNode, "price"); manufacturingPrices.put(typeID, price); } manufacturingSettings.setPrices(manufacturingPrices); Map manufacturingSystems = new HashMap<>(); NodeList systemNodes = manufacturingElement.getElementsByTagName("system"); for (int a = 0; a < systemNodes.getLength(); a++) { Element systemNode = (Element) systemNodes.item(a); int systemID = getInt(systemNode, "systemid"); float index = getFloat(systemNode, "index"); manufacturingSystems.put(systemID, index); } manufacturingSettings.setSystems(manufacturingSystems); } private void parsePriceHistorySettings(Element priceHistoryElement, Settings settings) throws XmlException { NodeList priceListNodes = priceHistoryElement.getElementsByTagName("set"); for (int a = 0; a < priceListNodes.getLength(); a++) { Element priceListNode = (Element) priceListNodes.item(a); String name = getString(priceListNode, "name"); Set typeIDs = new HashSet<>(); addIntToList(priceListNode, "ids", typeIDs); settings.getPriceHistorySets().put(name, typeIDs); } } private void parseFactionWarfareSystemOwners(Element factionWarfareSystemOwnersElement, Settings settings) throws XmlException { Date factionWarfareNextUpdate = getDateNotNull(factionWarfareSystemOwnersElement, "factionwarfarenextupdate"); settings.setFactionWarfareNextUpdate(factionWarfareNextUpdate); NodeList systemNodes = factionWarfareSystemOwnersElement.getElementsByTagName("system"); settings.getFactionWarfareSystemOwners().clear(); for (int a = 0; a < systemNodes.getLength(); a++) { Element systemNode = (Element) systemNodes.item(a); long systemID = getLong(systemNode, "system"); String faction = getString(systemNode, "faction"); settings.getFactionWarfareSystemOwners().put(systemID, faction); } } private void parseColorSettings(Element colorSettingsElement, Settings settings) throws XmlException { NodeList colorNodes = colorSettingsElement.getElementsByTagName("color"); for (int a = 0; a < colorNodes.getLength(); a++) { Element colorNode = (Element) colorNodes.item(a); try { ColorEntry entry = ColorEntry.valueOf(getString(colorNode, "name")); Color background = getColorOptional(colorNode, "background"); Color foreground = getColorOptional(colorNode, "foreground"); settings.getColorSettings().setBackground(entry, background); settings.getColorSettings().setForeground(entry, foreground); } catch (IllegalArgumentException ex) { LOG.error(ex.getMessage(), ex); } } String theme = getStringOptional(colorSettingsElement, "theme"); ColorThemeTypes colorThemeTypes; try { colorThemeTypes = ColorThemeTypes.valueOf(theme); } catch (IllegalArgumentException ex) { LOG.error(ex.getMessage(), ex); colorThemeTypes = ColorThemeTypes.DEFAULT; } settings.getColorSettings().setColorTheme(colorThemeTypes.getInstance(), false); String lookAndFeelClass = getStringOptional(colorSettingsElement, "lookandfeel"); if (lookAndFeelClass != null) { settings.getColorSettings().setLookAndFeelClass(lookAndFeelClass); } } private void parseSoundSettings(Element colorSettingsElement, Settings settings) throws XmlException { NodeList soundNodes = colorSettingsElement.getElementsByTagName("sound"); for (int a = 0; a < soundNodes.getLength(); a++) { Element soundNode = (Element) soundNodes.item(a); SoundOption option = SoundOption.valueOf(getString(soundNode, "option")); String sound = getString(soundNode, "sound"); try { settings.getSoundSettings().put(option, DefaultSound.valueOf(sound)); } catch (IllegalArgumentException ex) { File file = new File(FileUtil.getPathSounds(sound)); if (file.exists()) { settings.getSoundSettings().put(option, new FileSound(file)); } else { settings.getSoundSettings().put(option, DefaultSound.BEEP); //Fallback } } } } private void parseTrackerSettings(Element trackerSettingsElement, Settings settings) throws XmlException { TrackerSettings trackerSettings = settings.getTrackerSettings(); boolean allProfiles = getBoolean(trackerSettingsElement, "allprofiles"); trackerSettings.setAllProfiles(allProfiles); boolean characterCorporations = getBoolean(trackerSettingsElement, "charactercorporations"); trackerSettings.setCharacterCorporations(characterCorporations); List selectedOwners = getStringListOptional(trackerSettingsElement, "selectedowners"); trackerSettings.setSelectedOwners(selectedOwners); Date fromDate = getDateOptional(trackerSettingsElement, "fromdate"); trackerSettings.setFromDate(fromDate); Date toDate = getDateOptional(trackerSettingsElement, "todate"); trackerSettings.setToDate(toDate); String displayType = getStringOptional(trackerSettingsElement, "displaytype"); if (displayType != null) { try { trackerSettings.setDisplayType(DisplayType.valueOf(displayType)); } catch (IllegalArgumentException e) { LOG.warn("Could not parse trackersettigns displaytype: " + displayType); } } Boolean includeZero = getBooleanOptional(trackerSettingsElement, "includezero"); if (includeZero != null) { trackerSettings.setIncludeZero(includeZero); } List showOptions = getStringListOptional(trackerSettingsElement, "showoptions"); if (showOptions != null) { trackerSettings.getShowOptions().clear(); if (!showOptions.isEmpty()) { for (String showOption : showOptions) { try { trackerSettings.getShowOptions().add(ShowOption.valueOf(showOption)); } catch (IllegalArgumentException e) { LOG.warn("Could not parse trackersettigns showoptions: " + showOption); } } } } } private void parseShowToolsNodes(Element showToolsElement, Settings settings) throws XmlException { boolean saveOnExit = getBoolean(showToolsElement, "saveonexit"); List showTools = getStringList(showToolsElement, "show"); int index = showTools.indexOf("Industry Slots"); if (index >= 0) { showTools.set(index, "Slots"); } settings.setSaveToolsOnExit(saveOnExit); settings.getShowTools().addAll(showTools); } private void parseMarketOrderOutbidNodes(Element marketOrderOutbidElement, Settings settings) throws XmlException { Date nextUpdate = getDate(marketOrderOutbidElement, "nextupdate"); settings.setPublicMarketOrdersNextUpdate(nextUpdate); Date lastUpdate = getDateOptional(marketOrderOutbidElement, "lastupdate"); settings.setPublicMarketOrdersLastUpdate(lastUpdate); MarketOrderRange outbidOrderRange; try { outbidOrderRange = MarketOrderRange.valueOf(getString(marketOrderOutbidElement, "outbidorderrange")); } catch (IllegalArgumentException ex) { outbidOrderRange = MarketOrderRange.REGION; } settings.setOutbidOrderRange(outbidOrderRange); NodeList outbidNodes = marketOrderOutbidElement.getElementsByTagName("outbid"); for (int a = 0; a < outbidNodes.getLength(); a++) { Element outbidNode = (Element) outbidNodes.item(a); long orderID = getLong(outbidNode, "id"); double price = getDouble(outbidNode, "price"); long count = getLong(outbidNode, "count"); settings.getMarketOrdersOutbid().put(orderID, new Outbid(price, count)); } } private void parseRoutingSettings(Element routingElement, Settings settings) throws XmlException { parseRouteAvoidSettings(routingElement, settings.getRoutingSettings().getAvoidSettings()); parseRoutes(routingElement, settings.getRoutingSettings().getRoutes()); } private void parseJumpsSettings(Element jumpsElement, Settings settings) throws XmlException { parseRouteAvoidSettings(jumpsElement, settings.getJumpsAvoidSettings()); } private void parseRouteAvoidSettings(Element avoidElement, RouteAvoidSettings routeAvoidSettings) throws XmlException { double secMax = getDouble(avoidElement, "securitymaximum"); double secMin = getDouble(avoidElement, "securityminimum"); routeAvoidSettings.setSecMax(secMax); routeAvoidSettings.setSecMin(secMin); NodeList systemNodes = avoidElement.getElementsByTagName("routingsystem"); for (int a = 0; a < systemNodes.getLength(); a++) { Element systemNode = (Element) systemNodes.item(a); long systemID = getLong(systemNode, "id"); MyLocation location = ApiIdConverter.getLocation(systemID); routeAvoidSettings.getAvoid().put(systemID, new SolarSystem(location)); } NodeList presetNodes = avoidElement.getElementsByTagName("routingpreset"); for (int a = 0; a < presetNodes.getLength(); a++) { Element presetNode = (Element) presetNodes.item(a); String name = getString(presetNode, "name"); Set systemIDs = new HashSet<>(); NodeList presetSystemNodes = presetNode.getElementsByTagName("presetsystem"); for (int b = 0; b < presetSystemNodes.getLength(); b++) { Element systemNode = (Element) presetSystemNodes.item(b); long systemID = getLong(systemNode, "id"); systemIDs.add(systemID); } routeAvoidSettings.getPresets().put(name, systemIDs); } } private void parseRoutes(Element routingElement, Map map) throws XmlException { NodeList routeNodes = routingElement.getElementsByTagName("route"); for (int a = 0; a < routeNodes.getLength(); a++) { Element routeNode = (Element) routeNodes.item(a); String name = getString(routeNode, "name"); int waypoints = getInt(routeNode, "waypoints"); String algorithmName = getString(routeNode, "algorithmname"); long algorithmTime = getLong(routeNode, "algorithmtime"); int jumps = getInt(routeNode, "jumps"); String avoid = getStringOptional(routeNode, "avoid"); String security = getStringOptional(routeNode, "security"); NodeList routeSystemsNodes = routeNode.getElementsByTagName("routesystems"); List> route = new ArrayList<>(); Map> stationsMap = new HashMap<>(); for (int b = 0; b < routeSystemsNodes.getLength(); b++) { Element routeStartSystemNode = (Element) routeSystemsNodes.item(b); NodeList routeSystemNodes = routeStartSystemNode.getElementsByTagName("routesystem"); List systems = new ArrayList<>(); for (int c = 0; c < routeSystemNodes.getLength(); c++) { Element routeSystemNode = (Element) routeSystemNodes.item(c); long systemID = getLong(routeSystemNode, "systemid"); SolarSystem system = new SolarSystem(ApiIdConverter.getLocation(systemID)); systems.add(system); } route.add(systems); NodeList routeStationNodes = routeStartSystemNode.getElementsByTagName("routestation"); for (int c = 0; c < routeStationNodes.getLength(); c++) { Element routeStationNode = (Element) routeStationNodes.item(c); long stationID = getLong(routeStationNode, "stationid"); SolarSystem station = new SolarSystem(ApiIdConverter.getLocation(stationID)); List stationsList = stationsMap.get(systems.get(0).getSystemID()); if (stationsList == null) { stationsList = new ArrayList<>(); stationsMap.put(systems.get(0).getSystemID(), stationsList); } stationsList.add(station); } } map.put(name, new RouteResult(route, stationsMap, waypoints, algorithmName, algorithmTime, jumps, avoid, security)); } } private void parseTags(Element tagsElement, Settings settings) throws XmlException { NodeList tagNodes = tagsElement.getElementsByTagName("tag"); for (int a = 0; a < tagNodes.getLength(); a++) { Element tagNode = (Element) tagNodes.item(a); String name = getString(tagNode, "name"); String background = getString(tagNode, "background"); String foreground = getString(tagNode, "foreground"); TagColor color = new TagColor(background, foreground); Tag tag = new Tag(name, color); settings.getTags().put(tag.getName(), tag); NodeList idNodes = tagNode.getElementsByTagName("tagid"); for (int b = 0; b < idNodes.getLength(); b++) { Element idNode = (Element) idNodes.item(b); String tool = getString(idNode, "tool"); long id = getLong(idNode, "id"); double d = getDoubleNotNull(idNode, "d", 0); TagID tagID = new TagID(tool, id, d); tag.getIDs().add(tagID); settings.getTags(tagID).add(tag); } } } private void parseOverview(final Element overviewElement, final Settings settings) throws XmlException { NodeList groupNodes = overviewElement.getElementsByTagName("group"); for (int a = 0; a < groupNodes.getLength(); a++) { Element groupNode = (Element) groupNodes.item(a); String name = getString(groupNode, "name"); OverviewGroup overviewGroup = new OverviewGroup(name); settings.getOverviewGroups().put(overviewGroup.getName(), overviewGroup); NodeList locationNodes = groupNode.getElementsByTagName("location"); for (int b = 0; b < locationNodes.getLength(); b++) { Element locationNode = (Element) locationNodes.item(b); String location = getString(locationNode, "name"); String type = getString(locationNode, "type"); overviewGroup.add(new OverviewLocation(location, OverviewLocation.LocationType.valueOf(type))); } } } private void parseReprocessing(final Element windowElement, final Settings settings) throws XmlException { int reprocessing = getInt(windowElement, "refining"); int efficiency = getInt(windowElement, "efficiency"); Integer processing = getIntOptional(windowElement, "processing"); Integer ore = getIntOptional(windowElement, "ore"); Integer scrapmetal = getIntOptional(windowElement, "scrapmetal"); if (scrapmetal == null) { if (processing != null) { scrapmetal = processing; } else { scrapmetal = 0; } } if (ore == null) { if (processing != null) { ore = processing; } else { ore = 0; } } double station = getDouble(windowElement, "station"); settings.setReprocessSettings(new ReprocessSettings(station, reprocessing, efficiency, ore, scrapmetal)); } private void parseWindow(final Element windowElement, final Settings settings) throws XmlException { int x = getInt(windowElement, "x"); int y = getInt(windowElement, "y"); int height = getInt(windowElement, "height"); int width = getInt(windowElement, "width"); boolean maximized = getBoolean(windowElement, "maximized"); boolean autosave = getBoolean(windowElement, "autosave"); boolean alwaysOnTop = getBooleanNotNull(windowElement, "alwaysontop", false); settings.setWindowLocation(new Point(x, y)); settings.setWindowSize(new Dimension(width, height)); settings.setWindowMaximized(maximized); settings.setWindowAutoSave(autosave); settings.setWindowAlwaysOnTop(alwaysOnTop); } private void parseProxy(final Element proxyElement, final Settings settings) throws XmlException { Proxy.Type type; try { type = Proxy.Type.valueOf(getString(proxyElement, "type")); } catch (IllegalArgumentException ex) { type = null; } String address = getString(proxyElement, "address"); int port = getInt(proxyElement, "port"); String username = getStringOptional(proxyElement, "username"); String password = getStringOptional(proxyElement, "password"); if (type != null && type != Proxy.Type.DIRECT && !address.isEmpty() && port != 0) { // check the proxy attributes are all there. settings.setProxyData(new ProxyData(address, type, port, username, password)); } } private void parseUserPrices(final Element element, final Settings settings) throws XmlException { NodeList userPriceNodes = element.getElementsByTagName("userprice"); for (int i = 0; i < userPriceNodes.getLength(); i++) { Element currentNode = (Element) userPriceNodes.item(i); String name = getString(currentNode, "name"); double price = getDouble(currentNode, "price"); int typeID = getInt(currentNode, "typeid"); UserItem userPrice = new UserPrice(price, typeID, name); settings.getUserPrices().put(typeID, userPrice); } } private void parseUserItemNames(final Element element, final Settings settings) throws XmlException { NodeList userPriceNodes = element.getElementsByTagName("itemname"); for (int i = 0; i < userPriceNodes.getLength(); i++) { Element currentNode = (Element) userPriceNodes.item(i); String name = getString(currentNode, "name"); String typeName = getString(currentNode, "typename"); long itemId = getLong(currentNode, "itemid"); UserItem userItemName = new UserName(name, itemId, typeName); settings.getUserItemNames().put(itemId, userItemName); } } private void parseEveNames(final Element element, final Settings settings) throws XmlException { NodeList eveNameNodes = element.getElementsByTagName("evename"); for (int i = 0; i < eveNameNodes.getLength(); i++) { Element currentNode = (Element) eveNameNodes.item(i); String name = getString(currentNode, "name"); long itemId = getLong(currentNode, "itemid"); settings.getEveNames().put(itemId, name); } } private void parsePriceDataSettings(final Element element, final Settings settings) throws XmlException { PriceMode priceType = settings.getPriceDataSettings().getPriceType(); //Default if (haveAttribute(element, "defaultprice")) { priceType = PriceMode.valueOf(getString(element, "defaultprice")); } PriceMode priceReprocessedType = settings.getPriceDataSettings().getPriceReprocessedType(); //Default if (haveAttribute(element, "defaultreprocessedprice")) { priceReprocessedType = PriceMode.valueOf(getString(element, "defaultreprocessedprice")); } PriceMode priceManufacturingType = settings.getPriceDataSettings().getPriceManufacturingType(); //Default if (haveAttribute(element, "defaultmanufacturingprice")) { priceManufacturingType = PriceMode.valueOf(getString(element, "defaultmanufacturingprice")); } //null = default Long locationID = null; LocationType locationType = null; //Backward compatibility if (haveAttribute(element, "regiontype")) { RegionTypeBackwardCompatibility regionType = RegionTypeBackwardCompatibility.valueOf(getString(element, "regiontype")); locationID = regionType.getRegion(); locationType = LocationType.REGION; } //Backward compatibility if (haveAttribute(element, "locations")) { String string = getString(element, "locations"); String[] split = string.split(","); if (split.length == 1) { try { locationID = Long.valueOf(split[0]); } catch (NumberFormatException ex) { LOG.warn("Could not parse locations long: " + split[0]); } } } if (haveAttribute(element, "locationid")) { locationID = getLong(element, "locationid"); } if (haveAttribute(element, "type")) { locationType = LocationType.valueOf(getString(element, "type")); } PriceSource priceSource = PriceDataSettings.getDefaultPriceSource(); if (haveAttribute(element, "pricesource")) { try { priceSource = PriceSource.valueOf(getString(element, "pricesource")); } catch (IllegalArgumentException ex) { //In case a price source is removed: Use the default } } String janiceKey = getStringOptional(element, "janicekey"); //Validate if (!priceSource.isValid(locationType, locationID)) { locationType = priceSource.getDefaultLocationType(); locationID = priceSource.getDefaultLocationID(); } settings.setPriceDataSettings(new PriceDataSettings(locationType, locationID, priceSource, priceType, priceReprocessedType, priceManufacturingType, janiceKey)); } private void parseMarketOrdersSettings(final Element element, final Settings settings) throws XmlException { int expireWarnDays = getIntNotNull(element, "expirewarndays", settings.getMarketOrdersSettings().getExpireWarnDays()); int remainingWarnPercent = getIntNotNull(element, "remainingwarnpercent", settings.getMarketOrdersSettings().getRemainingWarnPercent()); MarketOrdersSettings marketOrdersSettings = settings.getMarketOrdersSettings(); marketOrdersSettings.setExpireWarnDays(expireWarnDays); marketOrdersSettings.setRemainingWarnPercent(remainingWarnPercent); } private void parseFlags(final Element element, final Settings settings) throws XmlException { NodeList flagNodes = element.getElementsByTagName("flag"); for (int i = 0; i < flagNodes.getLength(); i++) { Element currentNode = (Element) flagNodes.item(i); String key = getString(currentNode, "key"); boolean enabled = getBoolean(currentNode, "enabled"); try { if (key.equals("FLAG_INCLUDE_CONTRACTS")) { settings.getFlags().put(SettingFlag.FLAG_INCLUDE_SELL_CONTRACTS, enabled); settings.getFlags().put(SettingFlag.FLAG_INCLUDE_BUY_CONTRACTS, enabled); } if (key.equals("FLAG_STRONG_COLORS")) { if (enabled) { settings.getColorSettings().setColorTheme(ColorThemeTypes.STRONG.getInstance(), true); } else { settings.getColorSettings().setColorTheme(ColorThemeTypes.DEFAULT.getInstance(), true); } } SettingFlag settingFlag = SettingFlag.valueOf(key); settings.getFlags().put(settingFlag, enabled); } catch (IllegalArgumentException ex) { LOG.warn("Removing Setting Flag:" + key); } } settings.cacheFlags(); } private void parseTableColumns(final Element element, final Settings settings) throws XmlException { NodeList tableNodeList = element.getElementsByTagName("table"); for (int a = 0; a < tableNodeList.getLength(); a++) { List columns = new ArrayList<>(); Element tableNode = (Element) tableNodeList.item(a); String tableName = getString(tableNode, "name"); //Ignore old tables if (tableName.equals("marketorderssell") || tableName.equals("marketordersbuy")) { continue; } NodeList columnNodeList = tableNode.getElementsByTagName("column"); for (int b = 0; b < columnNodeList.getLength(); b++) { Element columnNode = (Element) columnNodeList.item(b); String name = getString(columnNode, "name"); boolean shown = getBoolean(columnNode, "shown"); columns.add(new SimpleColumn(name, shown)); } settings.getTableColumns().put(tableName, columns); } } private void parseTableColumnsWidth(final Element element, final Settings settings) throws XmlException { NodeList tableNodeList = element.getElementsByTagName("table"); for (int a = 0; a < tableNodeList.getLength(); a++) { Map columns = new HashMap<>(); Element tableNode = (Element) tableNodeList.item(a); String tableName = getString(tableNode, "name"); NodeList columnNodeList = tableNode.getElementsByTagName("column"); for (int b = 0; b < columnNodeList.getLength(); b++) { Element columnNode = (Element) columnNodeList.item(b); int width = getInt(columnNode, "width"); String column = getString(columnNode, "column"); columns.put(column, width); } settings.getTableColumnsWidth().put(tableName, columns); } } private void parseTableResize(final Element element, final Settings settings) throws XmlException { NodeList tableNodeList = element.getElementsByTagName("table"); for (int i = 0; i < tableNodeList.getLength(); i++) { Element tableNode = (Element) tableNodeList.item(i); String tableName = getString(tableNode, "name"); ResizeMode resizeMode = ResizeMode.valueOf(getString(tableNode, "resize")); settings.getTableResize().put(tableName, resizeMode); } } private void parseTableViews(final Element element, final Settings settings) throws XmlException { NodeList viewToolNodeList = element.getElementsByTagName("viewtool"); for (int a = 0; a < viewToolNodeList.getLength(); a++) { Element viewToolNode = (Element) viewToolNodeList.item(a); String toolName = getString(viewToolNode, "tool"); Map views = new TreeMap<>(StringComparators.CASE_INSENSITIVE); settings.getTableViews().put(toolName, views); NodeList viewNodeList = viewToolNode.getElementsByTagName("view"); for (int b = 0; b < viewNodeList.getLength(); b++) { Element viewNode = (Element) viewNodeList.item(b); String viewName = getString(viewNode, "name"); View view = new View(viewName); views.put(view.getName(), view); NodeList viewColumnList = viewNode.getElementsByTagName("viewcolumn"); for (int c = 0; c < viewColumnList.getLength(); c++) { Element viewColumnNode = (Element) viewColumnList.item(c); String name = getString(viewColumnNode, "name"); boolean shown = getBoolean(viewColumnNode, "shown"); view.getColumns().add(new SimpleColumn(name, shown)); } } } } private void parseTableFormulas(final Element element, final Settings settings) throws XmlException { NodeList formulasNodeList = element.getElementsByTagName("formulas"); for (int a = 0; a < formulasNodeList.getLength(); a++) { Element formulasNode = (Element) formulasNodeList.item(a); String toolName = getString(formulasNode, "tool"); List tableFormulas = settings.getTableFormulas(toolName); NodeList formulaNodeList = formulasNode.getElementsByTagName("formula"); for (int b = 0; b < formulaNodeList.getLength(); b++) { Element formulaNode = (Element) formulaNodeList.item(b); String name = getString(formulaNode, "name"); String expression = getString(formulaNode, "expression"); Integer index = getIntOptional(formulaNode, "index"); tableFormulas.add(new Formula(name, expression, index)); } } } private void parseTableChanges(final Element element, final Settings settings) throws XmlException { NodeList changesList = element.getElementsByTagName("changes"); for (int a = 0; a < changesList.getLength(); a++) { Element changesNode = (Element) changesList.item(a); String toolName = getString(changesNode, "tool"); Date date = getDate(changesNode, "date"); settings.getTableChanged().put(toolName, date); } } private void parseTableJumps(final Element element, final Settings settings) throws XmlException { NodeList jumpsNodeList = element.getElementsByTagName("jumps"); for (int a = 0; a < jumpsNodeList.getLength(); a++) { Element jumpsNode = (Element) jumpsNodeList.item(a); String toolName = getString(jumpsNode, "tool"); List tableJumps = settings.getTableJumps(toolName); NodeList jumpNodeList = jumpsNode.getElementsByTagName("jump"); for (int b = 0; b < jumpNodeList.getLength(); b++) { Element jumpNode = (Element) jumpNodeList.item(b); long systemID = getLong(jumpNode, "systemid"); Integer index = getIntOptional(jumpNode, "index"); MyLocation from = ApiIdConverter.getLocation(systemID); tableJumps.add(new Jump(from, index)); } } } /*** * Parse the table filters elements of the settings file. * * @param element The 'tablefilters' element of the xml. * @param settings The settings to be loaded to. * @throws XmlException */ private void parseTableFilters(final Element element, final Settings settings) throws XmlException { NodeList tableNodeList = element.getElementsByTagName("table"); for (int a = 0; a < tableNodeList.getLength(); a++) { Element tableNode = (Element) tableNodeList.item(a); String tableName = getString(tableNode, "name"); NodeList filterNodeList = tableNode.getElementsByTagName("filter"); Map> filters = new HashMap<>(); for (int b = 0; b < filterNodeList.getLength(); b++) { Element filterNode = (Element) filterNodeList.item(b); String filterName = getString(filterNode, "name"); List filter = parseFilters(filterNode, tableName, settings); if (!filter.isEmpty()) { filters.put(filterName, filter); } else { LOG.warn(filterName + " filter removed (Empty)"); } } settings.getTableFilters().put(tableName, filters); } } /*** * Parse the current table filters elements of the settings file. * * @param element The 'currenttablefilters' element of the xml. * @param settings The settings to be loaded to. * @throws XmlException */ private void parseCurrentTableFilters(final Element element, final Settings settings) throws XmlException { NodeList tableNodeList = element.getElementsByTagName("table"); for (int a = 0; a < tableNodeList.getLength(); a++) { Element tableNode = (Element) tableNodeList.item(a); String tableName = getString(tableNode, "name"); NodeList filterNodeList = tableNode.getElementsByTagName("filter"); List filters = new ArrayList<>(); if (filterNodeList.getLength() == 1) { Element filterNode = (Element) filterNodeList.item(0); if (haveAttribute(filterNode, "show")) { settings.getCurrentTableFiltersShown().put(tableName, getBoolean(filterNode, "show")); } else { settings.getCurrentTableFiltersShown().put(tableName, true); } filters = parseFilters(filterNode, tableName, settings); } else { LOG.warn(tableName + " current filter not found"); } if (filters.isEmpty()) { LOG.warn(tableName + " current filter empty"); } settings.getCurrentTableFilters().put(tableName, filters); } } /*** * Parse the current table filters elements of the settings file. * * @param element The 'currenttablesorting' element of the xml. * @param settings The settings to be loaded to. * @throws XmlException */ private void parseCurrentTableSorting(final Element element, final Settings settings) throws XmlException { NodeList tableNodeList = element.getElementsByTagName("table"); for (int a = 0; a < tableNodeList.getLength(); a++) { Element tableNode = (Element) tableNodeList.item(a); String tableName = getString(tableNode, "name"); String sorting = getString(tableNode, "sorting"); settings.getCurrentTableSorting().put(tableName, sorting); } } /*** * Parse a filter element of the settings file. This can be used on both table and current table filters. * * @param filterNode The node of the filter element of the xml. * @param tableName The name of the table the filter is for. * @return A list of filters if the element had one. If not an empty list is returned. * @throws XmlException */ private List parseFilters(Element filterNode, String tableName, Settings settings) throws XmlException { List filter = new ArrayList<>(); NodeList rowNodes = filterNode.getElementsByTagName("row"); for (int c = 0; c < rowNodes.getLength(); c++) { Element rowNode = (Element) rowNodes.item(c); int group = getIntNotNull(rowNode, "group", 1); boolean enabled = getBooleanNotNull(rowNode, "enabled", true); String text = getString(rowNode, "text"); String columnString = getString(rowNode, "column"); EnumTableColumn column = getColumn(columnString, tableName, settings); if (column != null) { String compare = getString(rowNode, "compare"); String logic = getString(rowNode, "logic"); filter.add(new Filter(group, logic, column, compare, text, enabled)); } else { LOG.warn(columnString + " column removed from filter"); } } return filter; } public static EnumTableColumn getColumn(final String column, final String toolName, Settings settings) { for (ToolTab toolTab : ToolTab.values()) { EnumTableColumn enumTableColumn = toolTab.getColumn(column, toolName); if (enumTableColumn != null) { return enumTableColumn; } } if (settings != null) { for (Formula formula : settings.getTableFormulas(toolName)) { if (formula.getColumnName().equals(column)) { return new FormulaColumn<>(formula); } } for (Jump jump : settings.getTableJumps(toolName)) { if (jump.getName().equals(column)) { return new JumpColumn<>(jump); } } } //All if (column.equals("ALL") || column.equals("all")) { return AllColumn.ALL; } return null; } private void parseAssetFilters(final Element filtersElement, final Settings settings) throws XmlException { NodeList filterNodeList = filtersElement.getElementsByTagName("filter"); for (int a = 0; a < filterNodeList.getLength(); a++) { Element filterNode = (Element) filterNodeList.item(a); String filterName = getString(filterNode, "name"); List filters = new ArrayList<>(); NodeList rowNodeList = filterNode.getElementsByTagName("row"); for (int b = 0; b < rowNodeList.getLength(); b++) { Element rowNode = (Element) rowNodeList.item(b); LogicType logic = convertLogic(getBoolean(rowNode, "and")); EnumTableColumn column = convertColumn(getString(rowNode, "column")); CompareType compare = convertMode(getString(rowNode, "mode")); String text; if (haveAttribute(rowNode, "columnmatch")) { text = convertColumn(getString(rowNode, "columnmatch")).name(); } else { text = getString(rowNode, "text"); } Filter filter = new Filter(logic, column, compare, text); filters.add(filter); } settings.getTableFilters(AssetsTab.NAME).put(filterName, filters); } } private LogicType convertLogic(final boolean logic) { if (logic) { return LogicType.AND; } else { return LogicType.OR; } } private EnumTableColumn convertColumn(final String column) { if (column.equals("Name")) { return AssetTableFormat.NAME; } if (column.equals("Group")) { return AssetTableFormat.GROUP; } if (column.equals("Category")) { return AssetTableFormat.CATEGORY; } if (column.equals("Owner")) { return AssetTableFormat.OWNER; } if (column.equals("Count")) { return AssetTableFormat.COUNT; } if (column.equals("Location")) { return AssetTableFormat.LOCATION; } if (column.equals("Container")) { return AssetTableFormat.CONTAINER; } if (column.equals("Flag")) { return AssetTableFormat.FLAG; } if (column.equals("Price")) { return AssetTableFormat.PRICE; } if (column.equals("Sell Min")) { return AssetTableFormat.PRICE_SELL_MIN; } if (column.equals("Buy Max")) { return AssetTableFormat.PRICE_BUY_MAX; } if (column.equals("Base Price")) { return AssetTableFormat.PRICE_BASE; } if (column.equals("Value")) { return AssetTableFormat.VALUE; } if (column.equals("Meta")) { return AssetTableFormat.META; } if (column.equals("ID")) { return AssetTableFormat.ITEM_ID; } if (column.equals("Volume")) { return AssetTableFormat.VOLUME; } if (column.equals("Type ID")) { return AssetTableFormat.TYPE_ID; } if (column.equals("Region")) { return AssetTableFormat.REGION; } if (column.equals("Type Count")) { return AssetTableFormat.COUNT_TYPE; } if (column.equals("Security")) { return AssetTableFormat.SECURITY; } if (column.equals("Reprocessed")) { return AssetTableFormat.PRICE_REPROCESSED; } if (column.equals("Reprocessed Value")) { return AssetTableFormat.VALUE_REPROCESSED; } if (column.equals("Singleton")) { return AssetTableFormat.SINGLETON; } if (column.equals("Total Volume")) { return AssetTableFormat.VOLUME_TOTAL; } return AllColumn.ALL; //Fallback } private CompareType convertMode(final String compareMixed) { String compare = compareMixed.toUpperCase(); if (compare.equals("MODE_EQUALS")) { return CompareType.EQUALS; } if (compare.equals("MODE_CONTAIN")) { return CompareType.CONTAINS; } if (compare.equals("MODE_CONTAIN_NOT")) { return CompareType.CONTAINS_NOT; } if (compare.equals("MODE_EQUALS_NOT")) { return CompareType.EQUALS_NOT; } if (compare.equals("MODE_GREATER_THAN")) { return CompareType.GREATER_THAN; } if (compare.equals("MODE_LESS_THAN")) { return CompareType.LESS_THAN; } if (compare.equals("MODE_GREATER_THAN_COLUMN")) { return CompareType.GREATER_THAN_COLUMN; } if (compare.equals("MODE_LESS_THAN_COLUMN")) { return CompareType.LESS_THAN_COLUMN; } return CompareType.CONTAINS; } /*** * Old method to process export settings for 6.8.0 and older */ @Deprecated private void parseExportSettingsLegacy(final Element element, final Settings settings) throws XmlException { //Copy String copy = getStringOptional(element, "copy"); if (copy != null) { settings.getCopySettings().setCopyDecimalSeparator(DecimalSeparator.valueOf(copy)); } ExportFormat exportFormat = null; if (haveAttribute(element, "exportformat")) { exportFormat = ExportFormat.valueOf(getString(element, "exportformat")); } //CSV DecimalSeparator decimal = DecimalSeparator.valueOf(getString(element, "decimal")); LineDelimiter line = LineDelimiter.valueOf(getString(element, "line")); //SQL Boolean createTable = getBooleanOptional(element, "sqlcreatetable"); Boolean dropTable = getBooleanOptional(element, "sqldroptable"); Boolean extendedInserts = getBooleanOptional(element, "sqlextendedinserts"); //HTML Boolean htmlStyled = getBooleanOptional(element, "htmlstyled"); Boolean htmlIGB = getBooleanOptional(element, "htmligb"); Integer htmlRepeatHeader = getIntOptional(element, "htmlrepeatheader"); Map tableNames = new HashMap<>(); Map fileNames = new HashMap<>(); Map> columnNames = new HashMap<>(); NodeList tableNamesNodeList = element.getElementsByTagName("sqltablenames"); for (int a = 0; a < tableNamesNodeList.getLength(); a++) { Element tableNameNode = (Element) tableNamesNodeList.item(a); String tool = getString(tableNameNode, "tool"); String tableName = getString(tableNameNode, "tablename"); tableNames.put(tool, tableName); } //Shared NodeList fileNamesNodeList = element.getElementsByTagName("filenames"); for (int a = 0; a < fileNamesNodeList.getLength(); a++) { Element tableNameNode = (Element) fileNamesNodeList.item(a); String tool = getString(tableNameNode, "tool"); String fileName = getString(tableNameNode, "filename"); fileNames.put(tool, fileName); } NodeList tableNodeList = element.getElementsByTagName("table"); for (int a = 0; a < tableNodeList.getLength(); a++) { List columns = new ArrayList<>(); Element tableNode = (Element) tableNodeList.item(a); String tableName = getString(tableNode, "name"); NodeList columnNodeList = tableNode.getElementsByTagName("column"); for (int b = 0; b < columnNodeList.getLength(); b++) { Element columnNode = (Element) columnNodeList.item(b); String name = getString(columnNode, "name"); columns.add(name); } columnNames.put(tableName, columns); } //List of existing tools at the time when the data format was changed 6.8.0 List toolNames = Arrays.asList("industryjobs", "overview", "marketorders", "loadouts", "stockpile", "reprocessed", "contracts", "industryslots", "journal", "assets", "materials", "treeassets", "value", "items", "transaction"); for (String toolName : toolNames) { ExportSettings exportSettings = new ExportSettings(toolName); //Common if (exportFormat != null) { exportSettings.setExportFormat(exportFormat); } //CSV exportSettings.setDecimalSeparator(decimal); exportSettings.setCsvLineDelimiter(line); //SQL if (createTable != null) { exportSettings.setSqlCreateTable(createTable); } if (dropTable != null) { exportSettings.setSqlDropTable(dropTable); } if (extendedInserts != null) { exportSettings.setSqlExtendedInserts(extendedInserts); } //HTML if (htmlStyled != null) { exportSettings.setHtmlStyled(htmlStyled); } if (htmlIGB != null) { exportSettings.setHtmlIGB(htmlIGB); } if (htmlRepeatHeader != null) { exportSettings.setHtmlRepeatHeader(htmlRepeatHeader); } //Lists if (tableNames.containsKey(toolName)) { exportSettings.setSqlTableName(tableNames.get(toolName)); } if (fileNames.containsKey(toolName)) { exportSettings.setFilename(fileNames.get(toolName)); } if (columnNames.containsKey(toolName)) { exportSettings.getTableExportColumns().addAll(columnNames.get(toolName)); } settings.getExportSettings().put(toolName, exportSettings); } } /*** * * @param element * @param settings * @throws XmlException */ private void parseExportSettings(final Element element, final Settings settings) throws XmlException { //Copy String copy = getStringOptional(element, "copy"); if (copy != null) { settings.getCopySettings().setCopyDecimalSeparator(DecimalSeparator.valueOf(copy)); } NodeList tableNodeList = element.getElementsByTagName("export"); for (int a = 0; a < tableNodeList.getLength(); a++) { Element exportNode = (Element) tableNodeList.item(a); String toolName = getString(exportNode, "name"); ExportSettings exportSettings = parseExportSetting(exportNode, toolName); settings.getExportSettings().put(toolName, exportSettings); } } /*** * * @param exportNode * @param toolName * @return * @throws XmlException */ private ExportSettings parseExportSetting(final Element exportNode, final String toolName) throws XmlException { ExportSettings exportSetting = new ExportSettings(toolName); //Common String exportFormat = getStringOptional(exportNode, "exportformat"); if (exportFormat != null) { exportSetting.setExportFormat(ExportFormat.valueOf(exportFormat)); } String fileName = getString(exportNode, "filename"); if (fileName != null) { exportSetting.setFilename(fileName); } String columnSelection = getStringOptional(exportNode, "columnselection"); if (columnSelection != null) { exportSetting.setColumnSelection(ColumnSelection.valueOf(columnSelection)); } String viewName = getStringOptional(exportNode, "viewname"); if (viewName != null) { exportSetting.setViewName(viewName); } String filterSelection = getStringOptional(exportNode, "filterselection"); if (filterSelection != null) { exportSetting.setFilterSelection(FilterSelection.valueOf(filterSelection)); } String filterName = getStringOptional(exportNode, "filtername"); if (filterName != null) { exportSetting.setFilterName(filterName); } Element tableNode = getNodeOptional(exportNode, "table"); if (tableNode != null) { List columns = new ArrayList<>(); NodeList columnNodeList = tableNode.getElementsByTagName("column"); for (int b = 0; b < columnNodeList.getLength(); b++) { Element columnNode = (Element) columnNodeList.item(b); String name = getString(columnNode, "name"); columns.add(name); } exportSetting.putTableExportColumns(columns); } //CSV Element csvElement = getNodeOptional(exportNode, "csv"); if (csvElement != null) { DecimalSeparator decimal = DecimalSeparator.valueOf(getString(csvElement, "decimal")); exportSetting.setDecimalSeparator(decimal); LineDelimiter line = LineDelimiter.valueOf(getString(csvElement, "line")); exportSetting.setCsvLineDelimiter(line); } //SQL Element sqlElement = getNodeOptional(exportNode, "sql"); if (sqlElement != null) { String tableName = getString(sqlElement, "tablename"); exportSetting.setSqlTableName(tableName); boolean createTable = getBoolean(sqlElement, "createtable"); exportSetting.setSqlCreateTable(createTable); boolean dropTable = getBoolean(sqlElement, "droptable"); exportSetting.setSqlDropTable(dropTable); boolean extendedInserts = getBoolean(sqlElement, "extendedinserts"); exportSetting.setSqlExtendedInserts(extendedInserts); } //html Element htmlElement = getNodeOptional(exportNode, "html"); if (htmlElement != null) { boolean htmlStyled = getBoolean(htmlElement, "styled"); exportSetting.setHtmlStyled(htmlStyled); boolean htmlIGB = getBoolean(htmlElement, "igb"); exportSetting.setHtmlIGB(htmlIGB); int htmlRepeatHeader = getInt(htmlElement, "repeatheader"); exportSetting.setHtmlRepeatHeader(htmlRepeatHeader); } return exportSetting; } /*** * * @param element * @param settings * @throws XmlException */ private void parseImportSettings(final Element element, final Settings settings) throws XmlException { NodeList tableNodeList = element.getElementsByTagName("import"); for (int a = 0; a < tableNodeList.getLength(); a++) { Element exportNode = (Element) tableNodeList.item(a); String toolName = getString(exportNode, "name"); String type = getString(exportNode, "type"); settings.getImportSettings().put(toolName, type); } } private void parseAssetAdded(final Element element) throws XmlException { NodeList assetNodes = element.getElementsByTagName("asset"); Map assetAdded = new HashMap<>(); for (int i = 0; i < assetNodes.getLength(); i++) { Element currentNode = (Element) assetNodes.item(i); long itemID = getLong(currentNode, "itemid"); Date date = getDate(currentNode, "date"); assetAdded.put(itemID, date); } AddedData.getAssets().set(assetAdded); //Import from settings.xml } public enum RegionTypeBackwardCompatibility { NOT_CONFIGURABLE(null), EMPIRE(null), MARKET_HUBS(null), ALL_AMARR(null), ALL_GALLENTE(null), ALL_MINMATAR(null), ALL_CALDARI(null), ARIDIA(10000054L), DEVOID(10000036L), DOMAIN(10000043L), GENESIS(10000067L), KADOR(10000052L), KOR_AZOR(10000065L), TASH_MURKON(10000020L), THE_BLEAK_LANDS(10000038L), BLACK_RISE(10000069L), LONETREK(10000016L), THE_CITADEL(10000033L), THE_FORGE(10000002L), ESSENCE(10000064L), EVERYSHORE(10000037L), PLACID(10000048L), SINQ_LAISON(10000032L), SOLITUDE(10000044L), VERGE_VENDOR(10000068L), METROPOLIS(10000042L), HEIMATAR(10000030L), MOLDEN_HEATH(10000028L), DERELIK(10000001L), KHANID(10000049L) ; private final Long region; private RegionTypeBackwardCompatibility(Long region) { this.region = region; } public Long getRegion() { return region; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/SettingsWriter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.File; import java.net.Proxy; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.MarketOrderRange; import net.nikr.eve.jeveasset.data.settings.ColorEntry; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.CopySettings; import net.nikr.eve.jeveasset.data.settings.ExportSettings; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings; import net.nikr.eve.jeveasset.data.settings.MarketOrdersSettings; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings; import net.nikr.eve.jeveasset.data.settings.ProxyData; import net.nikr.eve.jeveasset.data.settings.ReprocessSettings; import net.nikr.eve.jeveasset.data.settings.RouteAvoidSettings; import net.nikr.eve.jeveasset.data.settings.RouteResult; import net.nikr.eve.jeveasset.data.settings.RoutingSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.Settings.SettingFlag; import net.nikr.eve.jeveasset.data.settings.TrackerData; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.data.settings.tag.Tag; import net.nikr.eve.jeveasset.data.settings.tag.TagID; import net.nikr.eve.jeveasset.gui.dialogs.settings.SoundsSettingsPanel.SoundOption; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog.Formula; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuJumps.Jump; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.ResizeMode; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.SimpleColumn; import net.nikr.eve.jeveasset.gui.shared.table.View; import net.nikr.eve.jeveasset.gui.sounds.Sound; import net.nikr.eve.jeveasset.gui.tabs.orders.Outbid; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewGroup; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewLocation; import net.nikr.eve.jeveasset.gui.tabs.routing.SolarSystem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileContainer; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileFlag; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerDate; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerNote; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerSkillPointFilter; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; public class SettingsWriter extends AbstractXmlWriter { private static final Logger LOG = LoggerFactory.getLogger(SettingsWriter.class); private SettingsWriter() { } public static boolean save(final Settings settings, final String filename) { if (!new File(FileUtil.getPathTrackerData()).exists()) { //Make sure the tracker data is saved TrackerData.save("Saving Settings", true); } SettingsWriter writer = new SettingsWriter(); return writer.write(settings, filename); } public static boolean saveStockpiles(final List stockpiles, final String filename) { SettingsWriter writer = new SettingsWriter(); return writer.writeStockpiles(stockpiles, filename); } private boolean writeStockpiles(final List stockpiles, final String filename) { Document xmldoc; try { xmldoc = getXmlDocument("settings"); } catch (XmlException ex) { LOG.error("Stockpile not saved " + ex.getMessage(), ex); return false; } writeStockpiles(xmldoc, stockpiles, new HashMap<>(), true); try { writeXmlFile(xmldoc, filename, false); } catch (XmlException ex) { LOG.error("Stockpile not saved " + ex.getMessage(), ex); return false; } LOG.info("Stockpile saved"); return true; } public static boolean saveRoutes(final Map routes, final String filename) { SettingsWriter writer = new SettingsWriter(); return writer.writeRoutes(routes, filename); } private boolean writeRoutes(final Map routes, final String filename) { Document xmldoc; try { xmldoc = getXmlDocument("settings"); } catch (XmlException ex) { LOG.error("Stockpile not saved " + ex.getMessage(), ex); return false; } Element routingNode = xmldoc.createElementNS(null, "routingsettings"); xmldoc.getDocumentElement().appendChild(routingNode); writeRoutes(xmldoc, routingNode, routes); try { writeXmlFile(xmldoc, filename, false); } catch (XmlException ex) { LOG.error("Stockpile not saved " + ex.getMessage(), ex); return false; } LOG.info("Stockpile saved"); return true; } private boolean write(final Settings settings, final String filename) { Document xmldoc; try { xmldoc = getXmlDocument("settings"); } catch (XmlException ex) { LOG.error("Settings not saved " + ex.getMessage(), ex); return false; } //Add version number setAttribute(xmldoc.getDocumentElement(), "version", SettingsReader.SETTINGS_VERSION); writeAssetSettings(xmldoc, settings); writeStockpileGroups(xmldoc, settings); writeStockpiles(xmldoc, settings.getStockpiles(), settings.getStockpileGroupSettings().getStockpileGroups(), false); writeOverviewGroups(xmldoc, settings.getOverviewGroups()); writeReprocessSettings(xmldoc, settings.getReprocessSettings()); writeWindow(xmldoc, settings); writeProxy(xmldoc, settings.getProxyData()); writePriceDataSettings(xmldoc, settings.getPriceDataSettings()); writeFlags(xmldoc, settings.getFlags()); writeUserPrices(xmldoc, settings.getUserPrices()); writeUserItemNames(xmldoc, settings.getUserItemNames()); writeEveNames(xmldoc, settings.getEveNames()); writeTableFilters(xmldoc, settings.getTableFilters()); writeCurrentTableFilters(xmldoc, settings.getCurrentTableFilters(), settings.getCurrentTableFiltersShown()); writeCurrentSorting(xmldoc, settings.getCurrentTableSorting()); writeTableColumns(xmldoc, settings.getTableColumns()); writeTableColumnsWidth(xmldoc, settings.getTableColumnsWidth()); writeTableResize(xmldoc, settings.getTableResize()); writeTableViews(xmldoc, settings.getTableViews()); writeTableJumps(xmldoc, settings.getTableJumps()); writeTableFormulas(xmldoc, settings.getTableFormulas()); writeTableChanges(xmldoc, settings.getTableChanged()); writeExportSettings(xmldoc, settings.getExportSettings(), settings.getCopySettings()); writeImportSettings(xmldoc, settings.getImportSettings()); writeSkillPlans(xmldoc, settings.getSkillPlans()); writeTrackerNotes(xmldoc, settings.getTrackerSettings().getNotes()); writeTrackerFilters(xmldoc, settings.getTrackerSettings().getFilters(), settings.getTrackerSettings().isSelectNew(), settings.getTrackerSettings().getSkillPointFilters()); writeTrackerSettings(xmldoc, settings); writeOwners(xmldoc, settings.getOwners(), settings.getOwnersNextUpdate()); writeTags(xmldoc, settings.getTags()); writeRoutingSettings(xmldoc, settings.getRoutingSettings()); writeJumpsSettings(xmldoc, settings.getJumpsAvoidSettings()); writeMarketOrderOutbid(xmldoc, settings.getPublicMarketOrdersNextUpdate(), settings.getPublicMarketOrdersLastUpdate(), settings.getOutbidOrderRange(), settings.getMarketOrdersOutbid()); writeMarketOrdersSettings(xmldoc, settings.getMarketOrdersSettings()); writeShowTool(xmldoc, settings.getShowTools(), settings.isSaveToolsOnExit()); writeColorSettings(xmldoc, settings.getColorSettings()); writeSoundSettings(xmldoc, settings.getSoundSettings()); writeFactionWarfareSystemOwners(xmldoc, settings); writePriceHistorySettings(xmldoc, settings); writeManufacturingPriceSettings(xmldoc, settings.getManufacturingSettings()); try { writeXmlFile(xmldoc, filename, true); } catch (XmlException ex) { LOG.error("Settings not saved " + ex.getMessage(), ex); return false; } LOG.info("Settings saved"); return true; } private void writeSkillPlans(final Document xmldoc, final Map> skillPlans) { Element node = xmldoc.createElementNS(null, "skillplans"); xmldoc.getDocumentElement().appendChild(node); for (Map.Entry> entry : skillPlans.entrySet()) { Element planNode = xmldoc.createElementNS(null, "plan"); setAttribute(planNode, "name", entry.getKey()); node.appendChild(planNode); for (Map.Entry req : entry.getValue().entrySet()) { Element reqNode = xmldoc.createElementNS(null, "req"); setAttribute(reqNode, "typeid", req.getKey()); setAttribute(reqNode, "level", req.getValue()); planNode.appendChild(reqNode); } } } private void writeManufacturingPriceSettings(Document xmldoc, ManufacturingSettings settings) { Element manufacturingNode = xmldoc.createElementNS(null, "manufacturing"); setAttributeOptional(manufacturingNode, "nextupdate", settings.getNextUpdate()); setAttributeOptional(manufacturingNode, "facility", settings.getFacility()); setAttributeOptional(manufacturingNode, "rigs", settings.getRigs()); setAttributeOptional(manufacturingNode, "security", settings.getSecurity()); setAttributeOptional(manufacturingNode, "systemid", settings.getSystemID()); setAttributeOptional(manufacturingNode, "me", settings.getMaterialEfficiency()); setAttributeOptional(manufacturingNode, "tax", settings.getTax()); xmldoc.getDocumentElement().appendChild(manufacturingNode); for (Map.Entry entry : settings.getPrices().entrySet()) { Element priceNode = xmldoc.createElementNS(null, "price"); setAttribute(priceNode, "typeid", entry.getKey()); setAttributeOptional(priceNode, "price", entry.getValue()); manufacturingNode.appendChild(priceNode); } for (Map.Entry entry : settings.getSystems().entrySet()) { Element systemNode = xmldoc.createElementNS(null, "system"); setAttribute(systemNode, "systemid", entry.getKey()); setAttributeOptional(systemNode, "index", entry.getValue()); manufacturingNode.appendChild(systemNode); } } private void writePriceHistorySettings(Document xmldoc, Settings settings) { Element priceHistoryNode = xmldoc.createElementNS(null, "pricehistory"); xmldoc.getDocumentElement().appendChild(priceHistoryNode); for (Map.Entry> entry : settings.getPriceHistorySets().entrySet()) { Element setNode = xmldoc.createElementNS(null, "set"); setAttribute(setNode, "name", entry.getKey()); setAttributeOptional(setNode, "ids", entry.getValue()); priceHistoryNode.appendChild(setNode); } } private void writeFactionWarfareSystemOwners(Document xmldoc, Settings settings) { Element factionWarfareSystemOwnersNode = xmldoc.createElementNS(null, "factionwarfaresystemowners"); xmldoc.getDocumentElement().appendChild(factionWarfareSystemOwnersNode); setAttribute(factionWarfareSystemOwnersNode, "factionwarfarenextupdate", settings.getFactionWarfareNextUpdate()); for (Map.Entry entry : settings.getFactionWarfareSystemOwners().entrySet()) { Element systemNode = xmldoc.createElementNS(null, "system"); setAttribute(systemNode, "system", entry.getKey()); setAttributeOptional(systemNode, "faction", entry.getValue()); factionWarfareSystemOwnersNode.appendChild(systemNode); } } private void writeColorSettings(Document xmldoc, ColorSettings colorSettings) { Element colorSettingsNode = xmldoc.createElementNS(null, "colorsettings"); xmldoc.getDocumentElement().appendChild(colorSettingsNode); setAttributeOptional(colorSettingsNode, "theme", colorSettings.getColorTheme().getType()); setAttribute(colorSettingsNode, "lookandfeel", colorSettings.getLookAndFeelClass()); for (ColorEntry colorEntry : ColorEntry.values()) { Element colorNode = xmldoc.createElementNS(null, "color"); setAttribute(colorNode, "name", colorEntry); setAttributeOptional(colorNode, "background", colorSettings.getBackground(colorEntry)); setAttributeOptional(colorNode, "foreground", colorSettings.getForeground(colorEntry)); colorSettingsNode.appendChild(colorNode); } } private void writeSoundSettings(Document xmldoc, Map soundSettings) { Element soundSettingsNode = xmldoc.createElementNS(null, "soundsettings"); xmldoc.getDocumentElement().appendChild(soundSettingsNode); for (Map.Entry entry : soundSettings.entrySet()) { Element soundNode = xmldoc.createElementNS(null, "sound"); setAttribute(soundNode, "option", entry.getKey()); setAttribute(soundNode, "sound", entry.getValue().getID()); soundSettingsNode.appendChild(soundNode); } } private void writeShowTool(Document xmldoc, List showTools, boolean saveToolsOnExit) { Element showToolsNode = xmldoc.createElementNS(null, "showtools"); xmldoc.getDocumentElement().appendChild(showToolsNode); setAttribute(showToolsNode, "saveonexit", saveToolsOnExit); setAttribute(showToolsNode, "show", showTools); } private void writeMarketOrderOutbid(Document xmldoc, Date publicMarketOrdersNextUpdate, Date publicMarketOrdersLastUpdate, MarketOrderRange outbidOrderRange, Map marketOrdersOutbid) { Element marketOrderOutbidNode = xmldoc.createElementNS(null, "marketorderoutbid"); xmldoc.getDocumentElement().appendChild(marketOrderOutbidNode); setAttribute(marketOrderOutbidNode, "nextupdate", publicMarketOrdersNextUpdate); setAttributeOptional(marketOrderOutbidNode, "lastupdate", publicMarketOrdersLastUpdate); setAttribute(marketOrderOutbidNode, "outbidorderrange", outbidOrderRange); for (Map.Entry entry : marketOrdersOutbid.entrySet()) { Element outbidNode = xmldoc.createElementNS(null, "outbid"); setAttribute(outbidNode, "id", entry.getKey()); setAttribute(outbidNode, "price", entry.getValue().getPrice()); setAttribute(outbidNode, "count", entry.getValue().getCount()); marketOrderOutbidNode.appendChild(outbidNode); } } private void writeRoutingSettings(Document xmldoc, RoutingSettings routingSettings) { Element routingNode = xmldoc.createElementNS(null, "routingsettings"); writeRouteAvoidSettings(xmldoc, routingNode, routingSettings.getAvoidSettings()); writeRoutes(xmldoc, routingNode, routingSettings.getRoutes()); } private void writeJumpsSettings(Document xmldoc, RouteAvoidSettings routeAvoidSettings) { Element routingNode = xmldoc.createElementNS(null, "jumpssettings"); writeRouteAvoidSettings(xmldoc, routingNode, routeAvoidSettings); } private void writeRouteAvoidSettings(Document xmldoc, Element routingNode, RouteAvoidSettings routeAvoidSettings) { xmldoc.getDocumentElement().appendChild(routingNode); setAttribute(routingNode, "securitymaximum", routeAvoidSettings.getSecMax()); setAttribute(routingNode, "securityminimum", routeAvoidSettings.getSecMin()); for (long systemID : routeAvoidSettings.getAvoid().keySet()) { Element systemNode = xmldoc.createElementNS(null, "routingsystem"); setAttribute(systemNode, "id", systemID); routingNode.appendChild(systemNode); } for (Map.Entry> entry : routeAvoidSettings.getPresets().entrySet()) { Element presetNode = xmldoc.createElementNS(null, "routingpreset"); setAttribute(presetNode, "name", entry.getKey()); routingNode.appendChild(presetNode); for (Long systemID : entry.getValue()) { Element systemNode = xmldoc.createElementNS(null, "presetsystem"); setAttribute(systemNode, "id", systemID); presetNode.appendChild(systemNode); } } } private void writeRoutes(Document xmldoc, Element routingNode, Map routes) { for (Map.Entry entry : routes.entrySet()) { Element routeNode = xmldoc.createElementNS(null, "route"); RouteResult routeResult = entry.getValue(); setAttribute(routeNode, "name", entry.getKey()); setAttribute(routeNode, "waypoints", routeResult.getWaypoints()); setAttribute(routeNode, "algorithmname", routeResult.getAlgorithmName()); setAttribute(routeNode, "algorithmtime",routeResult.getAlgorithmTime()); setAttribute(routeNode, "jumps", routeResult.getJumps()); setAttribute(routeNode, "avoid", routeResult.getAvoid()); setAttribute(routeNode, "security", routeResult.getSecurity()); routingNode.appendChild(routeNode); for (List systems : routeResult.getRoute()) { Element systemsNode = xmldoc.createElementNS(null, "routesystems"); for (SolarSystem system : systems) { Element systemNode = xmldoc.createElementNS(null, "routesystem"); setAttribute(systemNode, "systemid", system.getSystemID()); systemsNode.appendChild(systemNode); } List stations = routeResult.getStations().get(systems.get(0).getSystemID()); if (stations != null) { for (SolarSystem station : stations) { Element stationNode = xmldoc.createElementNS(null, "routestation"); setAttribute(stationNode, "stationid", station.getLocationID()); systemsNode.appendChild(stationNode); } } routeNode.appendChild(systemsNode); } } } private void writeTags(Document xmldoc, Map tags) { Element tagsNode = xmldoc.createElementNS(null, "tags"); xmldoc.getDocumentElement().appendChild(tagsNode); for (Tag tag : tags.values()) { Element tagNode = xmldoc.createElementNS(null, "tag"); setAttribute(tagNode, "name", tag.getName()); setAttribute(tagNode, "background", tag.getColor().getBackgroundHtml()); setAttribute(tagNode, "foreground", tag.getColor().getForegroundHtml()); tagsNode.appendChild(tagNode); for (TagID tagID : tag.getIDs()) { Element tagIdNode = xmldoc.createElementNS(null, "tagid"); setAttribute(tagIdNode, "tool", tagID.getTool()); setAttribute(tagIdNode, "id", tagID.getID()); setAttribute(tagIdNode, "d", tagID.getDouble()); tagNode.appendChild(tagIdNode); } } } private void writeOwners(final Document xmldoc, final Map owners, final Map ownersNextUpdate) { Element trackerDataNode = xmldoc.createElementNS(null, "owners"); xmldoc.getDocumentElement().appendChild(trackerDataNode); for (Map.Entry entry : owners.entrySet()) { Element ownerNode = xmldoc.createElementNS(null, "owner"); setAttribute(ownerNode, "name", entry.getValue()); setAttribute(ownerNode, "id", entry.getKey()); setAttributeOptional(ownerNode, "date", ownersNextUpdate.get(entry.getKey())); trackerDataNode.appendChild(ownerNode); } } private void writeTrackerFilters(final Document xmldoc, final Map trackerFilters, boolean selectNew, Map trackerSkillPointFilters) { Element trackerDataNode = xmldoc.createElementNS(null, "trackerfilters"); xmldoc.getDocumentElement().appendChild(trackerDataNode); setAttribute(trackerDataNode, "selectnew", selectNew); for (Map.Entry entry : trackerFilters.entrySet()) { Element ownerNode = xmldoc.createElementNS(null, "trackerfilter"); setAttribute(ownerNode, "id", entry.getKey()); setAttribute(ownerNode, "selected", entry.getValue()); trackerDataNode.appendChild(ownerNode); } for (Map.Entry entry : trackerSkillPointFilters.entrySet()) { Element ownerNode = xmldoc.createElementNS(null, "skillpointfilters"); TrackerSkillPointFilter filter = entry.getValue(); setAttribute(ownerNode, "id", entry.getKey()); setAttribute(ownerNode, "selected", filter.isEnabled()); setAttribute(ownerNode, "mimimum", filter.getMinimum()); trackerDataNode.appendChild(ownerNode); } } private void writeTrackerSettings(final Document xmldoc, Settings settings) { Element trackerSettingsNode = xmldoc.createElementNS(null, "trackersettings"); xmldoc.getDocumentElement().appendChild(trackerSettingsNode); setAttribute(trackerSettingsNode, "allprofiles", settings.getTrackerSettings().isAllProfiles()); setAttribute(trackerSettingsNode, "charactercorporations", settings.getTrackerSettings().isCharacterCorporations()); setAttributeOptional(trackerSettingsNode, "selectedowners", settings.getTrackerSettings().getSelectedOwners()); setAttributeOptional(trackerSettingsNode, "fromdate", settings.getTrackerSettings().getFromDate()); setAttributeOptional(trackerSettingsNode, "todate", settings.getTrackerSettings().getToDate()); setAttribute(trackerSettingsNode, "displaytype", settings.getTrackerSettings().getDisplayType()); setAttribute(trackerSettingsNode, "includezero", settings.getTrackerSettings().isIncludeZero()); setAttribute(trackerSettingsNode, "showoptions", settings.getTrackerSettings().getShowOptions()); } private void writeTrackerNotes(final Document xmldoc, final Map trackerNotes) { Element notesNode = xmldoc.createElementNS(null, "trackernotes"); xmldoc.getDocumentElement().appendChild(notesNode); for (Map.Entry entry : trackerNotes.entrySet()) { Element noteNode = xmldoc.createElementNS(null, "trackernote"); setAttribute(noteNode, "note", entry.getValue().getNote()); setAttribute(noteNode, "date", entry.getKey().getDate()); notesNode.appendChild(noteNode); } } /*** * Write setting for table filters to the xml settings document 'tablefilters' element. * * @param xmldoc Settings document to write to. * @param tableFilters Saved filters to be written to the document zero to many for each table. */ private void writeTableFilters(final Document xmldoc, final Map>> tableFilters) { Element tableFiltersNode = xmldoc.createElementNS(null, "tablefilters"); xmldoc.getDocumentElement().appendChild(tableFiltersNode); for (Map.Entry>> entry : tableFilters.entrySet()) { Element tableNode = xmldoc.createElementNS(null, "table"); setAttribute(tableNode, "name", entry.getKey()); tableFiltersNode.appendChild(tableNode); for (Map.Entry> filters : entry.getValue().entrySet()) { Element filterNode = xmldoc.createElementNS(null, "filter"); setAttribute(filterNode, "name", filters.getKey()); tableNode.appendChild(filterNode); writeFilters(xmldoc, filterNode, filters); } } } /*** * Write setting for current table filters to the xml settings document 'currnettablefilters' element. * * @param xmldoc Settings document to write to. * @param tableFilters Current filters to be written to the document one per table. * @param tableFiltersShow Current filters visibility state to be written to the document one per table. */ private void writeCurrentTableFilters(final Document xmldoc, final Map> tableFilters, final Map tableFiltersShow) { Element currentTableFiltersNode = xmldoc.createElementNS(null, "currenttablefilters"); xmldoc.getDocumentElement().appendChild(currentTableFiltersNode); for (Map.Entry> filters : tableFilters.entrySet()) { Element tableNode = xmldoc.createElementNS(null, "table"); setAttribute(tableNode, "name", filters.getKey()); currentTableFiltersNode.appendChild(tableNode); Element filterNode = xmldoc.createElementNS(null, "filter"); setAttribute(filterNode, "show", tableFiltersShow.getOrDefault(filters.getKey(), true)); tableNode.appendChild(filterNode); writeFilters(xmldoc, filterNode, filters); } } /*** * Write setting for current table filters to the xml settings document 'currnettablefilters' element. * * @param xmldoc Settings document to write to. * @param currentTableSorting Current sorting to be written to the document one per table. */ private void writeCurrentSorting(final Document xmldoc, final Map currentTableSorting) { Element currentTableSortingNode = xmldoc.createElementNS(null, "currenttablesorting"); xmldoc.getDocumentElement().appendChild(currentTableSortingNode); for (Map.Entry filters : currentTableSorting.entrySet()) { Element tableNode = xmldoc.createElementNS(null, "table"); setAttribute(tableNode, "name", filters.getKey()); setAttribute(tableNode, "sorting", filters.getValue()); currentTableSortingNode.appendChild(tableNode); } } /*** * Write settings for individual filters rows to the xml settings document. * * @param xmldoc Settings document to write to. * @param parentNode Node of the xml document to write the filter to. * @param filters Filter to be written to the document row by row. */ private void writeFilters(final Document xmldoc, final Element parentNode, final Map.Entry> filters) { for (Filter filter : filters.getValue()) { Element rowNode = xmldoc.createElementNS(null, "row"); setAttribute(rowNode, "group", filter.getGroup()); setAttribute(rowNode, "text", filter.getText()); setAttribute(rowNode, "column", filter.getColumn().name()); setAttribute(rowNode, "compare", filter.getCompareType()); setAttribute(rowNode, "logic", filter.getLogic()); setAttribute(rowNode, "enabled", filter.isEnabled()); parentNode.appendChild(rowNode); } } private void writeTableColumns(final Document xmldoc, final Map> tableColumns) { Element tableColumnsNode = xmldoc.createElementNS(null, "tablecolumns"); xmldoc.getDocumentElement().appendChild(tableColumnsNode); for (Map.Entry> entry : tableColumns.entrySet()) { Element tableNode = xmldoc.createElementNS(null, "table"); setAttribute(tableNode, "name", entry.getKey()); tableColumnsNode.appendChild(tableNode); for (SimpleColumn column : entry.getValue()) { Element columnNode = xmldoc.createElementNS(null, "column"); setAttribute(columnNode, "name", column.getEnumName()); setAttribute(columnNode, "shown", column.isShown()); tableNode.appendChild(columnNode); } } } private void writeTableColumnsWidth(final Document xmldoc, final Map> tableColumnsWidth) { Element tableColumnsWidthNode = xmldoc.createElementNS(null, "tablecolumnswidth"); xmldoc.getDocumentElement().appendChild(tableColumnsWidthNode); for (Map.Entry> table : tableColumnsWidth.entrySet()) { Element tableNode = xmldoc.createElementNS(null, "table"); setAttribute(tableNode, "name", table.getKey()); tableColumnsWidthNode.appendChild(tableNode); for (Map.Entry column : table.getValue().entrySet()) { Element columnNode = xmldoc.createElementNS(null, "column"); setAttribute(columnNode, "column", column.getKey()); setAttribute(columnNode, "width", column.getValue()); tableNode.appendChild(columnNode); } } } private void writeTableResize(final Document xmldoc, final Map tableResize) { Element tableResizeNode = xmldoc.createElementNS(null, "tableresize"); xmldoc.getDocumentElement().appendChild(tableResizeNode); for (Map.Entry entry : tableResize.entrySet()) { Element tableNode = xmldoc.createElementNS(null, "table"); setAttribute(tableNode, "name", entry.getKey()); setAttribute(tableNode, "resize", entry.getValue()); tableResizeNode.appendChild(tableNode); } } private void writeTableViews(final Document xmldoc, final Map> tableViews) { Element tableViewsNode = xmldoc.createElementNS(null, "tableviews"); xmldoc.getDocumentElement().appendChild(tableViewsNode); for (Map.Entry> entry : tableViews.entrySet()) { Element viewToolNode = xmldoc.createElementNS(null, "viewtool"); setAttribute(viewToolNode, "tool", entry.getKey()); tableViewsNode.appendChild(viewToolNode); for (View view : entry.getValue().values()) { Element viewNode = xmldoc.createElementNS(null, "view"); setAttribute(viewNode, "name", view.getName()); viewToolNode.appendChild(viewNode); for (SimpleColumn column : view.getColumns()) { Element viewColumnNode = xmldoc.createElementNS(null, "viewcolumn"); setAttribute(viewColumnNode, "name", column.getEnumName()); setAttribute(viewColumnNode, "shown", column.isShown()); viewNode.appendChild(viewColumnNode); } } } } private void writeTableFormulas(final Document xmldoc, final Map> formulas) { Element tableFormulasNode = xmldoc.createElementNS(null, "tableformulas"); xmldoc.getDocumentElement().appendChild(tableFormulasNode); for (Map.Entry> entry : formulas.entrySet()) { Element formulasNode = xmldoc.createElementNS(null, "formulas"); setAttribute(formulasNode, "tool", entry.getKey()); tableFormulasNode.appendChild(formulasNode); for (Formula formula : entry.getValue()) { Element formulaNode = xmldoc.createElementNS(null, "formula"); setAttribute(formulaNode, "name", formula.getColumnName()); setAttribute(formulaNode, "expression", formula.getOriginalExpression()); setAttributeOptional(formulaNode, "index", formula.getIndex()); formulasNode.appendChild(formulaNode); } } } private void writeTableChanges(final Document xmldoc, final Map changes) { Element tableChangesNode = xmldoc.createElementNS(null, "tablechanges"); xmldoc.getDocumentElement().appendChild(tableChangesNode); for (Map.Entry entry : changes.entrySet()) { Element changesNode = xmldoc.createElementNS(null, "changes"); setAttribute(changesNode, "tool", entry.getKey()); setAttribute(changesNode, "date", entry.getValue()); tableChangesNode.appendChild(changesNode); } } private void writeTableJumps(final Document xmldoc, final Map> jumps) { Element tableJumpsNode = xmldoc.createElementNS(null, "tablejumps"); xmldoc.getDocumentElement().appendChild(tableJumpsNode); for (Map.Entry> entry : jumps.entrySet()) { Element jumpsNode = xmldoc.createElementNS(null, "jumps"); setAttribute(jumpsNode, "tool", entry.getKey()); tableJumpsNode.appendChild(jumpsNode); for (Jump jump : entry.getValue()) { Element jumpNode = xmldoc.createElementNS(null, "jump"); setAttribute(jumpNode, "systemid", jump.getSystemID()); setAttributeOptional(jumpNode, "index", jump.getIndex()); jumpsNode.appendChild(jumpNode); } } } private void writeAssetSettings(final Document xmldoc, final Settings settings) { Element parentNode = xmldoc.createElementNS(null, "assetsettings"); xmldoc.getDocumentElement().appendChild(parentNode); setAttribute(parentNode, "maximumpurchaseage", settings.getMaximumPurchaseAge()); setAttribute(parentNode, "transactionprofitprice", settings.getTransactionProfitPrice()); setAttribute(parentNode, "transactionprofitmargin", settings.getTransactionProfitMargin()); } private void writeStockpileGroups(final Document xmldoc, final Settings settings) { Element parentNode = xmldoc.createElementNS(null, "stockpilegroups"); xmldoc.getDocumentElement().appendChild(parentNode); setAttribute(parentNode, "stockpilegroup2", settings.getStockpileColorGroup2()); setAttribute(parentNode, "stockpilegroup3", settings.getStockpileColorGroup3()); } /** * -!- `!´ IMPORTANT `!´ -!- * StockpileDataWriter and StockpileDataReader needs to be updated too - on any changes!!! */ private void writeStockpiles(final Document xmldoc, final List stockpiles, Map groups, boolean export) { Element parentNode = xmldoc.createElementNS(null, "stockpiles"); xmldoc.getDocumentElement().appendChild(parentNode); for (Stockpile stockpile : stockpiles) { //STOCKPILE Element stockpileNode = xmldoc.createElementNS(null, "stockpile"); setAttribute(stockpileNode, "name", stockpile.getName()); if (!export) { //Risk of collision, better to generate a new one on import setAttribute(stockpileNode, "id", stockpile.getStockpileID()); } setAttribute(stockpileNode, "multiplier", stockpile.getMultiplier()); String group = groups.get(stockpile); if (group != null && !group.isEmpty()) { setAttribute(stockpileNode, "stockpilegroup", group); } setAttribute(stockpileNode, "matchall", stockpile.isMatchAll()); //ITEMS for (StockpileItem item : stockpile.getItems()) { if (item.isTotal()) { continue; //Ignore Total } Element itemNode = xmldoc.createElementNS(null, "item"); if (!export) { //Risk of collision, better to generate a new one on import setAttribute(itemNode, "id", item.getID()); } setAttribute(itemNode, "typeid", item.getItemTypeID()); setAttribute(itemNode, "minimum", item.getCountMinimum()); setAttribute(itemNode, "runs", item.isRuns()); setAttribute(itemNode, "ignoremultiplier", item.isIgnoreMultiplier()); stockpileNode.appendChild(itemNode); } //SUBPILES for (Map.Entry entry : stockpile.getSubpiles().entrySet()) { Element subpileNode = xmldoc.createElementNS(null, "subpile"); subpileNode.setAttributeNS(null, "name", entry.getKey().getName()); subpileNode.setAttributeNS(null, "minimum", String.valueOf(entry.getValue())); stockpileNode.appendChild(subpileNode); } //FILTERS for (StockpileFilter filter : stockpile.getFilters()) { Element filterNode = xmldoc.createElementNS(null, "stockpilefilter"); setAttribute(filterNode, "locationid", filter.getLocation().getLocationID()); setAttribute(filterNode, "sellingcontracts", filter.isSellingContracts()); setAttribute(filterNode, "soldcontracts", filter.isSoldContracts()); setAttribute(filterNode, "buyingcontracts", filter.isBuyingContracts()); setAttribute(filterNode, "boughtcontracts", filter.isBoughtContracts()); setAttribute(filterNode, "exclude", filter.isExclude()); setAttributeOptional(filterNode, "singleton", filter.isSingleton()); setAttributeOptional(filterNode, "jobsdaysless", filter.getJobsDaysLess()); setAttributeOptional(filterNode, "jobsdaysmore", filter.getJobsDaysMore()); setAttribute(filterNode, "inventory", filter.isAssets()); setAttribute(filterNode, "sellorders", filter.isSellOrders()); setAttribute(filterNode, "buyorders", filter.isBuyOrders()); setAttribute(filterNode, "buytransactions", filter.isBuyTransactions()); setAttribute(filterNode, "selltransactions", filter.isSellTransactions()); setAttribute(filterNode, "jobs", filter.isJobs()); stockpileNode.appendChild(filterNode); for (Long ownerID : filter.getOwnerIDs()) { Element ownerNode = xmldoc.createElementNS(null, "owner"); setAttribute(ownerNode, "ownerid", ownerID); filterNode.appendChild(ownerNode); } for (StockpileContainer container : filter.getContainers()) { Element containerNode = xmldoc.createElementNS(null, "container"); setAttribute(containerNode, "container", container.getContainer()); setAttribute(containerNode, "includecontainer", container.isIncludeSubs()); filterNode.appendChild(containerNode); } for (StockpileFlag flag : filter.getFlags()) { Element flagNode = xmldoc.createElementNS(null, "flag"); setAttribute(flagNode, "flagid", flag.getFlagID()); setAttribute(flagNode, "includecontainer", flag.isIncludeSubs()); filterNode.appendChild(flagNode); } } parentNode.appendChild(stockpileNode); } } private void writeOverviewGroups(final Document xmldoc, final Map overviewGroups) { Element parentNode = xmldoc.createElementNS(null, "overview"); xmldoc.getDocumentElement().appendChild(parentNode); for (Map.Entry entry : overviewGroups.entrySet()) { OverviewGroup overviewGroup = entry.getValue(); Element node = xmldoc.createElementNS(null, "group"); setAttribute(node, "name", overviewGroup.getName()); parentNode.appendChild(node); for (OverviewLocation location : overviewGroup.getLocations()) { Element nodeLocation = xmldoc.createElementNS(null, "location"); setAttribute(nodeLocation, "name", location.getName()); setAttribute(nodeLocation, "type", location.getType()); node.appendChild(nodeLocation); } } } private void writeUserItemNames(final Document xmldoc, final Map> userPrices) { Element parentNode = xmldoc.createElementNS(null, "itemmames"); xmldoc.getDocumentElement().appendChild(parentNode); for (Map.Entry> entry : userPrices.entrySet()) { UserItem userItemName = entry.getValue(); Element node = xmldoc.createElementNS(null, "itemname"); setAttribute(node, "name", userItemName.getValue()); setAttribute(node, "typename", userItemName.getName()); setAttribute(node, "itemid", userItemName.getKey()); parentNode.appendChild(node); } } private void writeEveNames(final Document xmldoc, final Map eveNames) { Element parentNode = xmldoc.createElementNS(null, "evenames"); xmldoc.getDocumentElement().appendChild(parentNode); for (Map.Entry entry : eveNames.entrySet()) { Element node = xmldoc.createElementNS(null, "evename"); setAttribute(node, "name", entry.getValue()); setAttribute(node, "itemid", entry.getKey()); parentNode.appendChild(node); } } private void writeReprocessSettings(final Document xmldoc, final ReprocessSettings reprocessSettings) { Element parentNode = xmldoc.createElementNS(null, "reprocessing"); xmldoc.getDocumentElement().appendChild(parentNode); setAttribute(parentNode, "refining", reprocessSettings.getReprocessingLevel()); setAttribute(parentNode, "efficiency", reprocessSettings.getReprocessingEfficiencyLevel()); setAttribute(parentNode, "ore", reprocessSettings.getOreProcessingLevel()); setAttribute(parentNode, "scrapmetal", reprocessSettings.getScrapmetalProcessingLevel()); setAttribute(parentNode, "station", reprocessSettings.getStation()); } private void writeWindow(final Document xmldoc, final Settings settings) { Element parentNode = xmldoc.createElementNS(null, "window"); xmldoc.getDocumentElement().appendChild(parentNode); setAttribute(parentNode, "x", settings.getWindowLocation().x); setAttribute(parentNode, "y", settings.getWindowLocation().y); setAttribute(parentNode, "height", settings.getWindowSize().height); setAttribute(parentNode, "width", settings.getWindowSize().width); setAttribute(parentNode, "maximized", settings.isWindowMaximized()); setAttribute(parentNode, "autosave", settings.isWindowAutoSave()); setAttribute(parentNode, "alwaysontop", settings.isWindowAlwaysOnTop()); } private void writeUserPrices(final Document xmldoc, final Map> userPrices) { Element parentNode = xmldoc.createElementNS(null, "userprices"); xmldoc.getDocumentElement().appendChild(parentNode); for (Map.Entry> entry : userPrices.entrySet()) { UserItem userPrice = entry.getValue(); Element node = xmldoc.createElementNS(null, "userprice"); setAttribute(node, "name", userPrice.getName()); setAttribute(node, "price", userPrice.getValue()); setAttribute(node, "typeid", userPrice.getKey()); parentNode.appendChild(node); } } private void writePriceDataSettings(final Document xmldoc, final PriceDataSettings priceDataSettings) { Element parentNode = xmldoc.createElementNS(null, "marketstat"); setAttribute(parentNode, "defaultprice", priceDataSettings.getPriceType()); setAttribute(parentNode, "defaultreprocessedprice", priceDataSettings.getPriceReprocessedType()); setAttribute(parentNode, "defaultmanufacturingprice", priceDataSettings.getPriceReprocessedType()); setAttribute(parentNode, "pricesource", priceDataSettings.getSource()); setAttribute(parentNode, "locationid", priceDataSettings.getLocationID()); setAttribute(parentNode, "type", priceDataSettings.getLocationType()); setAttributeOptional(parentNode, "janicekey", priceDataSettings.getJaniceKey()); xmldoc.getDocumentElement().appendChild(parentNode); } private void writeMarketOrdersSettings(final Document xmldoc, final MarketOrdersSettings marketOrdersSettings) { Element parentNode = xmldoc.createElementNS(null, "marketorderssettings"); setAttribute(parentNode, "expirewarndays", marketOrdersSettings.getExpireWarnDays()); setAttribute(parentNode, "remainingwarnpercent", marketOrdersSettings.getRemainingWarnPercent()); xmldoc.getDocumentElement().appendChild(parentNode); } private void writeFlags(final Document xmldoc, final Map flags) { Element parentNode = xmldoc.createElementNS(null, "flags"); xmldoc.getDocumentElement().appendChild(parentNode); for (Map.Entry entry : flags.entrySet()) { Element node = xmldoc.createElementNS(null, "flag"); setAttribute(node, "key", entry.getKey()); setAttribute(node, "enabled", entry.getValue()); parentNode.appendChild(node); } } private void writeProxy(final Document xmldoc, final ProxyData proxy) { if (proxy.getType() != Proxy.Type.DIRECT) { // Only adds proxy tag if there is anything to save... (To prevent an error when the proxy tag doesn't have any attributes) Element node = xmldoc.createElementNS(null, "proxy"); setAttribute(node, "address", proxy.getAddress()); setAttribute(node, "port", proxy.getPort()); setAttribute(node, "type", proxy.getType()); if (proxy.isAuth()) { setAttribute(node, "username", proxy.getUsername()); setAttribute(node, "password", proxy.getPassword()); } xmldoc.getDocumentElement().appendChild(node); } } private void writeExportSettings(final Document xmldoc, final Map exportSettings, final CopySettings copySettings) { Element node = xmldoc.createElementNS(null, "exports"); //Copy setAttribute(node, "copy", copySettings.getCopyDecimalSeparator()); for(Map.Entry exportSetting : exportSettings.entrySet()) { //Common Element exportNode = xmldoc.createElementNS(null, "export"); setAttribute(exportNode, "name", exportSetting.getKey()); setAttributeOptional(exportNode, "exportformat", exportSetting.getValue().getExportFormat()); setAttributeOptional(exportNode, "filename", exportSetting.getValue().getFilename()); setAttributeOptional(exportNode, "columnselection", exportSetting.getValue().getColumnSelection()); setAttributeOptional(exportNode, "viewname", exportSetting.getValue().getViewName()); setAttributeOptional(exportNode, "filterselection", exportSetting.getValue().getFilterSelection()); setAttributeOptional(exportNode, "filtername", exportSetting.getValue().getFilterName()); node.appendChild(exportNode); if (!exportSetting.getValue().getTableExportColumns().isEmpty()) { Element tableNode = xmldoc.createElementNS(null, "table"); for (String column : exportSetting.getValue().getTableExportColumns()) { Element columnNode = xmldoc.createElementNS(null, "column"); setAttribute(columnNode, "name", column); tableNode.appendChild(columnNode); } exportNode.appendChild(tableNode); } //CSV Element csvNode = xmldoc.createElementNS(null, "csv"); setAttribute(csvNode, "decimal", exportSetting.getValue().getDecimalSeparator()); setAttribute(csvNode, "line", exportSetting.getValue().getCsvLineDelimiter()); exportNode.appendChild(csvNode); //SQL Element sqlNode = xmldoc.createElementNS(null, "sql"); setAttribute(sqlNode, "tablename", exportSetting.getValue().getSqlTableName()); setAttribute(sqlNode, "createtable", exportSetting.getValue().isSqlCreateTable()); setAttribute(sqlNode, "droptable", exportSetting.getValue().isSqlDropTable()); setAttribute(sqlNode, "extendedinserts", exportSetting.getValue().isSqlExtendedInserts()); exportNode.appendChild(sqlNode); //Html Element htmlNode = xmldoc.createElementNS(null, "html"); setAttribute(htmlNode, "styled", exportSetting.getValue().isHtmlStyled()); setAttribute(htmlNode, "igb", exportSetting.getValue().isHtmlIGB()); setAttribute(htmlNode, "repeatheader", exportSetting.getValue().getHtmlRepeatHeader()); exportNode.appendChild(htmlNode); } xmldoc.getDocumentElement().appendChild(node); } private void writeImportSettings(final Document xmldoc, final Map importSettings) { Element node = xmldoc.createElementNS(null, "imports"); for (Map.Entry exportSetting : importSettings.entrySet()) { Element importNode = xmldoc.createElementNS(null, "import"); setAttribute(importNode, "name", exportSetting.getKey()); setAttribute(importNode, "type", exportSetting.getValue()); node.appendChild(importNode); } xmldoc.getDocumentElement().appendChild(node); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/SoundFinder.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.File; import java.io.FileFilter; import java.util.ArrayList; import java.util.List; import net.nikr.eve.jeveasset.gui.sounds.FileSound; import net.nikr.eve.jeveasset.gui.sounds.Sound; import net.nikr.eve.jeveasset.io.shared.FileUtil; public final class SoundFinder { private SoundFinder() { } public static List load() { SoundFinder reader = new SoundFinder(); return reader.read(); } private List read() { List sounds = new ArrayList<>(); File soundsDirectory = new File(FileUtil.getPathSoundsDirectory()); if (!soundsDirectory.exists()) { soundsDirectory.mkdirs(); } FileFilter fileFilter = new Mp3FileFilter(); File[] files = soundsDirectory.listFiles(fileFilter); if (files != null) { for (File file : files) { sounds.add(new FileSound(file)); } } return sounds; } private class Mp3FileFilter implements FileFilter { @Override public boolean accept(final File file) { return !file.isDirectory() && file.getName().endsWith(".mp3"); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/SqlWriter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.BufferedWriter; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Map; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.HierarchyColumn; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class SqlWriter { private static final Logger LOG = LoggerFactory.getLogger(SqlWriter.class); private final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("0.##", new DecimalFormatSymbols(Locale.ENGLISH)); private final DecimalFormat FLOAT_FORMAT = new DecimalFormat("0.####", new DecimalFormatSymbols(Locale.ENGLISH)); private final DecimalFormat LONG_FORMAT = new DecimalFormat("0", new DecimalFormatSymbols(Locale.ENGLISH)); private final int MAX_LENGTH = 944000; //a little less than 1MB private final DateFormat SQL_DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); private final String SQL_IDENTIFIER = "\""; //` private final String SQL_STRING = "'"; private final String SQL_NULL = "NULL"; private SqlWriter() { } public static boolean save(final String filename, final List, Object>> rows, final List> header, final String tableName, final boolean dropTable, final boolean createTable, final boolean extendedInserts) { SqlWriter writer = new SqlWriter(); return writer.write(filename, rows, header, tableName, dropTable, createTable, extendedInserts); } private boolean write(final String filename, final List, Object>> rows, final List> header, final String tableName, final boolean dropTable, final boolean createTable, final boolean extendedInserts) { try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename), "UTF-8"))) { writeComment(writer); writeTable(writer, rows, header, tableName, dropTable, createTable); writeRows(writer, rows, header, tableName, extendedInserts); } catch (IOException ex) { LOG.warn("SQL file not saved"); return false; } LOG.info("SQL file saved"); return true; } private void writeComment(final BufferedWriter writer) throws IOException { writer.write("-- " + Program.PROGRAM_NAME + " Sql Export\r\n"); writer.write("-- version " + Program.PROGRAM_VERSION + "\r\n"); writer.write("-- " + Program.PROGRAM_HOMEPAGE + "\r\n"); } private String getType(final Object object) { if (object instanceof Short) { return "smallint"; } else if (object instanceof Integer) { return "int"; } else if (object instanceof Long) { return "bigint"; } else if (object instanceof Float) { return "float"; } else if (object instanceof Double) { return "double"; } else if (object instanceof Date) { return "datetime"; } else { return "text"; } } private void writeTable(final BufferedWriter writer, final List, Object>> rows, final List> header, final String tableName, final boolean dropTable, final boolean createTable) throws IOException { if (dropTable) { writer.write("DROP TABLE IF EXISTS " + SQL_IDENTIFIER + tableName + SQL_IDENTIFIER + ";\r\n"); } if (createTable && !rows.isEmpty()) { writer.write("CREATE TABLE IF NOT EXISTS " + SQL_IDENTIFIER + tableName + SQL_IDENTIFIER + " (\r\n"); boolean first = true; for (EnumTableColumn column : header) { if (first) { first = false; } else { writer.write(",\r\n"); } writer.write(SQL_IDENTIFIER + column.name() + SQL_IDENTIFIER + " " + getType(rows.get(0).get(column))); } writer.write("\r\n"); writer.write(");\r\n"); } } private void writeRows(final BufferedWriter writer, final List, Object>> rows, final List> header, final String tableName, final boolean extendedInserts) throws IOException { if (!rows.isEmpty()) { //Create INSERT statement String insert = "INSERT INTO " + SQL_IDENTIFIER + tableName + SQL_IDENTIFIER + " ("; boolean firstInsert = true; for (EnumTableColumn column : header) { if (firstInsert) { firstInsert = false; } else { insert = insert + ", "; } insert = insert + SQL_IDENTIFIER + column.name() + SQL_IDENTIFIER; } insert = insert + ") VALUES\r\n"; if (extendedInserts) { writer.write(insert); } boolean firstRow = true; boolean firstCell; //Add values String values; int length = insert.getBytes("UTF-8").length; for (Map, Object> map : rows) { values = ""; if (extendedInserts && length > MAX_LENGTH) { length = insert.getBytes("UTF-8").length; firstRow = true; writer.write(";\r\n"); writer.write(insert); } //End Line if (firstRow) { firstRow = false; } else if (extendedInserts) { values = values + ",\r\n"; } //Values values = values + " ("; firstCell = true; for (EnumTableColumn column : header) { if (firstCell) { firstCell = false; } else { values = values + ", "; } values = values + format(map.get(column)); } values = values + ")"; if (!extendedInserts) { values = values + ";\r\n"; writer.write(insert); } length = length + values.getBytes("UTF-8").length; //Bytes writer.write(values); } writer.write(";\r\n"); } } private String format(final Object object) { if (object == null) { return SQL_NULL; } else if (object instanceof HierarchyColumn) { HierarchyColumn column = (HierarchyColumn) object; return SQL_STRING + column.getExport().replace("'", "\\'") + SQL_STRING; } else if (object instanceof Double) { //Double return DOUBLE_FORMAT.format(object); } else if (object instanceof Float) { //Float return FLOAT_FORMAT.format(object); } else if (object instanceof Number) { //Number (Short/Integer/Long) return LONG_FORMAT.format(object); } else if (object instanceof Date) { //Date return SQL_STRING + SQL_DATETIME_FORMATTER.format(object) + SQL_STRING; } else if (object instanceof String) { return SQL_STRING + ((String)object).replace("'", "''") + SQL_STRING; } else { //String etc. return SQL_STRING + String.valueOf(object).replace("'", "''") + SQL_STRING; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/StockpileReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Base64; import java.util.List; import java.util.zip.InflaterInputStream; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileContainer; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileFlag; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class StockpileReader extends AbstractBackup { private static final Logger LOG = LoggerFactory.getLogger(StockpileReader.class); public static List load(String data) { StockpileReader reader = new StockpileReader(); return reader.read(data); } private List read(String data) { data = data.trim(); ByteArrayInputStream inputStream = null; try { inputStream = new ByteArrayInputStream(Base64.getUrlDecoder().decode(data)); BufferedReader reader = new BufferedReader(new InputStreamReader(new InflaterInputStream(inputStream))); StringBuilder sb = new StringBuilder(); String str; while((str = reader.readLine())!= null) { sb.append(str); sb.append("\n"); } Gson gson = new GsonBuilder().registerTypeAdapter(Stockpile.class, new StockpileDeserializerGson()).create(); return gson.fromJson(sb.toString(), new TypeToken>() {}.getType()); } catch (IllegalArgumentException | JsonSyntaxException | IOException ex) { LOG.error(ex.getMessage(), ex); return null; } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException ex) { //No problem } } } } public static class StockpileDeserializerGson implements JsonDeserializer { @Override public Stockpile deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { //Stockpile JsonObject stockpileObject = json.getAsJsonObject(); String name = stockpileObject.get("n").getAsString(); double multiplier = stockpileObject.get("m").getAsDouble(); boolean matchAll = false; //NotNull if (stockpileObject.has("ma")) { matchAll = stockpileObject.get("ma").getAsBoolean(); } else if (stockpileObject.has("cma")) { matchAll = stockpileObject.get("cma").getAsBoolean(); } //Filters List filters = new ArrayList<>(); JsonElement filtersElement = stockpileObject.get("sf"); for (JsonElement filterElement : filtersElement.getAsJsonArray()) { JsonObject filterObject = filterElement.getAsJsonObject(); boolean assets = filterObject.get("a").getAsBoolean(); boolean boughtContracts = filterObject.get("bbc").getAsBoolean(); boolean buyingContracts = filterObject.get("bc").getAsBoolean(); boolean sellingContracts = filterObject.get("sc").getAsBoolean(); boolean soldContracts = filterObject.get("ssc").getAsBoolean(); boolean buyOrders = filterObject.get("bo").getAsBoolean(); boolean sellOrders = filterObject.get("so").getAsBoolean(); boolean buyTransactions = filterObject.get("bt").getAsBoolean(); boolean sellTransactions = filterObject.get("st").getAsBoolean(); boolean exclude = filterObject.get("e").getAsBoolean(); boolean jobs = filterObject.get("j").getAsBoolean(); Integer jobsDaysLess = null; if (filterObject.has("jdl")) { jobsDaysLess = filterObject.get("jdl").getAsInt(); } Integer jobsDaysMore = null; if (filterObject.has("jdm")) { jobsDaysMore = filterObject.get("jdm").getAsInt(); } Boolean singleton = null; if (filterObject.has("s")) { singleton = filterObject.get("s").getAsBoolean(); } long locationID = filterObject.get("id").getAsLong(); //Containers List containers = new ArrayList<>(); JsonElement containersElement = filterObject.get("c"); for (JsonElement containerElement : containersElement.getAsJsonArray()) { JsonObject containerObject = containerElement.getAsJsonObject(); String container = containerObject.get("cc").getAsString(); boolean includeSubs = containerObject.get("ic").getAsBoolean(); containers.add(new StockpileContainer(container, includeSubs)); } //Flags List flags = new ArrayList<>(); JsonElement flagIDsElement = filterObject.get("f"); for (JsonElement flagElement : flagIDsElement.getAsJsonArray()) { if (flagElement.isJsonObject()) { JsonObject flagObject = flagElement.getAsJsonObject(); int flagID = flagObject.get("ff").getAsInt(); boolean includeSubs = flagObject.get("ic").getAsBoolean(); flags.add(new StockpileFlag(flagID, includeSubs)); } else { flags.add(new StockpileFlag(flagElement.getAsInt(), true)); } } //Owners List ownerIDs = new ArrayList<>(); JsonElement ownerIDsElement = filterObject.get("o"); for (JsonElement ownerIdElement : ownerIDsElement.getAsJsonArray()) { ownerIDs.add(ownerIdElement.getAsLong()); } filters.add(new StockpileFilter(ApiIdConverter.getLocation(locationID), exclude, flags, containers, ownerIDs, jobsDaysLess, jobsDaysMore, singleton, assets, sellOrders, buyOrders, jobs, buyTransactions, sellTransactions, sellingContracts, soldContracts, buyingContracts, boughtContracts)); } //Create Stockile (then add items) Stockpile stockpile = new Stockpile(name, null, filters, multiplier, matchAll); //Items JsonElement itemsElement = stockpileObject.get("i"); for (JsonElement itemElement : itemsElement.getAsJsonArray()) { JsonObject itemObject = itemElement.getAsJsonObject(); int itemTypeID = itemObject.get("i").getAsInt(); double countMinimum = itemObject.get("m").getAsDouble(); boolean runs = itemObject.get("r").getAsBoolean(); JsonElement element = itemObject.get("im"); boolean ignoreMultiplier = false; if (element != null) { ignoreMultiplier = element.getAsBoolean(); } stockpile.add(new StockpileItem(stockpile, ApiIdConverter.getItem(Math.abs(itemTypeID)), itemTypeID, countMinimum, runs, ignoreMultiplier)); } return stockpile; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/StockpileWriter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.reflect.Type; import java.util.Base64; import java.util.List; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileContainer; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileFlag; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class StockpileWriter extends AbstractBackup { private static final Logger LOG = LoggerFactory.getLogger(StockpileWriter.class); public static String save(List stockpiles) { StockpileWriter writer = new StockpileWriter(); return writer.write(stockpiles); } private String write(List stockpiles) { DeflaterOutputStream compressOutputStream = null; try { Gson gson = new GsonBuilder().registerTypeAdapter(Stockpile.class, new StockpileSerializerGson()).create(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Deflater deflater = new Deflater(); deflater.setLevel(9); compressOutputStream = new DeflaterOutputStream(outputStream, deflater); compressOutputStream.write(gson.toJson(stockpiles).getBytes()); compressOutputStream.close(); return Base64.getUrlEncoder().encodeToString(outputStream.toByteArray()); } catch (IOException ex) { LOG.error(ex.getMessage(), ex); return null; } finally { if (compressOutputStream != null) { try { compressOutputStream.close(); } catch (IOException ex) { //No problem } } } } public static class StockpileSerializerGson implements JsonSerializer { @Override public JsonElement serialize(Stockpile stockpile, Type typeOfSrc, JsonSerializationContext context) { //Stockpile JsonObject stockpileObject = new JsonObject(); stockpileObject.addProperty("n", stockpile.getName()); stockpileObject.addProperty("m", stockpile.getMultiplier()); stockpileObject.addProperty("ma", stockpile.isMatchAll()); //Filters JsonArray filtersObject = new JsonArray(); stockpileObject.add("sf", filtersObject); for (StockpileFilter stockpileFilter : stockpile.getFilters()) { JsonObject filterObject = new JsonObject(); filtersObject.add(filterObject); filterObject.addProperty("a", stockpileFilter.isAssets()); filterObject.addProperty("bbc", stockpileFilter.isBoughtContracts()); filterObject.addProperty("bc", stockpileFilter.isBuyingContracts()); filterObject.addProperty("sc", stockpileFilter.isSellingContracts()); filterObject.addProperty("ssc", stockpileFilter.isSoldContracts()); filterObject.addProperty("bo", stockpileFilter.isBuyOrders()); filterObject.addProperty("so", stockpileFilter.isSellOrders()); filterObject.addProperty("bt", stockpileFilter.isBuyTransactions()); filterObject.addProperty("st", stockpileFilter.isSellTransactions()); filterObject.addProperty("e", stockpileFilter.isExclude()); filterObject.addProperty("j", stockpileFilter.isJobs()); filterObject.addProperty("jdl", stockpileFilter.getJobsDaysLess()); filterObject.addProperty("jdm", stockpileFilter.getJobsDaysMore()); filterObject.addProperty("s", stockpileFilter.isSingleton()); filterObject.addProperty("id", stockpileFilter.getLocation().getLocationID()); //Containers JsonArray containers = new JsonArray(); filterObject.add("c", containers); for (StockpileContainer stockpileContainer : stockpileFilter.getContainers()) { JsonObject container = new JsonObject(); container.addProperty("cc", stockpileContainer.getContainer()); container.addProperty("ic", stockpileContainer.isIncludeSubs()); containers.add(container); } //Flags JsonArray flags = new JsonArray(); filterObject.add("f", flags); for (StockpileFlag flag : stockpileFilter.getFlags()) { JsonObject flagObject = new JsonObject(); flagObject.addProperty("ff", flag.getFlagID()); flagObject.addProperty("ic", flag.isIncludeSubs()); flags.add(flagObject); } //Owners JsonArray owners = new JsonArray(); filterObject.add("o", owners); for (Long ownerID : stockpileFilter.getOwnerIDs()) { owners.add(ownerID); } } //Items JsonArray items = new JsonArray(); stockpileObject.add("i", items); for (StockpileItem stockpileItem : stockpile.getItems()) { if (stockpileItem.isTotal()) { continue; //Ignore Total } JsonObject item = new JsonObject(); item.addProperty("i", stockpileItem.getItemTypeID()); item.addProperty("m", stockpileItem.getCountMinimum()); item.addProperty("r", stockpileItem.isRuns()); item.addProperty("im", stockpileItem.isIgnoreMultiplier()); items.add(item); } return stockpileObject; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/TrackerReader.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.reflect.TypeToken; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.gui.tabs.values.AssetValue; import net.nikr.eve.jeveasset.gui.tabs.values.Value; import net.nikr.eve.jeveasset.io.local.FileLock.SafeFileIO; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TrackerReader extends AbstractBackup { private static final Logger LOG = LoggerFactory.getLogger(TrackerReader.class); public static Map> load() { return load(FileUtil.getPathTrackerData(), true); } public static Map> load(String filename, boolean backup) { TrackerReader reader = new TrackerReader(); return reader.read(filename, backup); } private Map> read(String filename, boolean backup) { File file = new File(filename); if (!file.exists()) { return null; } if (backup) { backup(filename); } Gson gson = new GsonBuilder().registerTypeAdapter(Value.class, new ValueDeserializerJSon()).create(); try (SafeFileIO io = new SafeFileIO(file)){ Map> trackerData = gson.fromJson(new InputStreamReader(io.getFileInputStream()), new TypeToken>>() {}.getType()); LOG.info("Tracker data loaded"); return trackerData; } catch (IOException | JsonParseException ex) { LOG.warn(ex.getMessage(), ex); if (restoreNewFile(filename)) { //If possible restore from .new (Should be the newest) read(filename, backup); } else if (restoreBackupFile(filename)) { //If possible restore from .bac (Should be the oldest, but, still worth trying) read(filename, backup); } else { //Nothing left to try - throw error restoreFailed(filename); //Backup error file LOG.error(ex.getMessage(), ex); } } return null; } public static class ValueDeserializerJSon implements JsonDeserializer { @Override public Value deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject node = json.getAsJsonObject(); Date date = new Date(node.get("date").getAsLong()); double assetsTotal = node.get("assets").getAsDouble(); double escrows = node.get("escrows").getAsDouble(); double escrowstocover = node.get("escrowstocover").getAsDouble(); double sellorders = node.get("sellorders").getAsDouble(); double balanceTotal = node.get("walletbalance").getAsDouble(); double manufacturing = node.get("manufacturing").getAsDouble(); double contractCollateral = node.get("contractcollateral").getAsDouble(); double contractValue = node.get("contractvalue").getAsDouble(); //Skills JsonElement skillPointElement = node.get("skillpoints"); long skillPoints = 0; if (skillPointElement != null) { skillPoints = skillPointElement.getAsLong(); } //Add data Value value = new Value(date); //Balance JsonElement balanceElement = node.get("balance"); if (balanceElement != null && balanceElement.isJsonArray()) { for (JsonElement itemElement : balanceElement.getAsJsonArray()) { JsonObject itemObject = itemElement.getAsJsonObject(); String id = itemObject.get("id").getAsString(); double balance = itemObject.get("value").getAsDouble(); value.addBalance(id, balance); } } else { value.setBalanceTotal(balanceTotal); } //Assets containers fixed JsonElement assetsContainersFixedElement = node.get("assetscontainersfixed"); boolean assetsContainersFixed = false; if (assetsContainersFixedElement != null) { assetsContainersFixed = assetsContainersFixedElement.getAsBoolean(); } value.setAssetsContainersFixed(assetsContainersFixed); //Assets JsonElement assetElement = node.get("asset"); if (assetElement != null && assetElement.isJsonArray()) { for (JsonElement itemElement : assetElement.getAsJsonArray()) { JsonObject itemObject = itemElement.getAsJsonObject(); String location = itemObject.get("location").getAsString(); Long locationID = null; if (itemObject.get("locationid") != null) { locationID = itemObject.get("locationid").getAsLong(); } String flag = null; if (itemObject.get("flag") != null) { flag = itemObject.get("flag").getAsString(); } Double assets = itemObject.get("value").getAsDouble(); AssetValue assetValue = AssetValue.create(location, flag, locationID); value.addAssets(assetValue, assets); } } else { value.setAssetsTotal(assetsTotal); } //Implants JsonElement implantNode = node.get("implants"); double implants = 0; if (implantNode != null) { implants = implantNode.getAsDouble(); } value.setImplants(implants); //Others value.setEscrows(escrows); value.setEscrowsToCover(escrowstocover); value.setSellOrders(sellorders); value.setManufacturing(manufacturing); value.setContractCollateral(contractCollateral); value.setContractValue(contractValue); value.setSkillPoints(skillPoints); return value; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/TrackerWriter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import java.io.File; import java.io.IOException; import java.lang.reflect.Type; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.data.settings.TrackerData; import net.nikr.eve.jeveasset.gui.tabs.values.AssetValue; import net.nikr.eve.jeveasset.gui.tabs.values.Value; import net.nikr.eve.jeveasset.io.local.FileLock.SafeFileIO; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TrackerWriter extends AbstractBackup { private static final Logger LOG = LoggerFactory.getLogger(TrackerWriter.class); public static void save() { save(FileUtil.getPathTrackerData(), TrackerData.get(), true); } protected static void save(String filename, Map> trackerData, boolean createBackup) { TrackerWriter writer = new TrackerWriter(); writer.write(filename, trackerData, createBackup); } private void write(String filename, Map> trackerData, boolean createBackup) { File file; if (createBackup) { file = getNewFile(filename); //Save to .new file } else { file = new File(filename); } Gson gson = new GsonBuilder().registerTypeAdapter(Value.class, new ValueSerializerGJson()).create(); try (SafeFileIO io = new SafeFileIO(file)) { //gson.toJson(trackerData, io.getOutputStreamWriter()); gson.toJson(trackerData, io.getOutputStreamWriter()); io.unlock(); //Unlock before backupFile() is called //Saving done - create backup and rename new file to target if (createBackup) { backupFile(filename); //Rename .xml => .bac (.new is safe) and .new => .xml (.bac is safe). That way we always have at least one safe file } LOG.info("Tracker data saved"); } catch (IOException | JsonParseException ex) { LOG.error(ex.getMessage(), ex); } } public static class ValueSerializerGJson implements JsonSerializer { @Override public JsonElement serialize(Value value, Type typeOfSrc, JsonSerializationContext context) { JsonObject valueObject = new JsonObject(); valueObject.addProperty("date", value.getDate().getTime()); valueObject.addProperty("assets", value.getAssetsTotal()); valueObject.addProperty("implants", value.getImplants()); valueObject.addProperty("escrows", value.getEscrows()); valueObject.addProperty("escrowstocover", value.getEscrowsToCover()); valueObject.addProperty("sellorders", value.getSellOrders()); valueObject.addProperty("walletbalance", value.getBalanceTotal()); valueObject.addProperty("manufacturing", value.getManufacturing()); valueObject.addProperty("contractcollateral", value.getContractCollateral()); valueObject.addProperty("contractvalue", value.getContractValue()); valueObject.addProperty("skillpoints", value.getSkillPoints()); if (!value.getBalanceFilter().isEmpty()) { JsonArray balanceObject = new JsonArray(); valueObject.add("balance", balanceObject); for (Map.Entry entry : value.getBalanceFilter().entrySet()) { JsonObject itemObject = new JsonObject(); itemObject.addProperty("id", entry.getKey()); itemObject.addProperty("value", entry.getValue()); balanceObject.add(itemObject); } } valueObject.addProperty("assetscontainersfixed", value.isAssetsContainersFixed()); if (!value.getAssetsFilter().isEmpty()) { JsonArray assetObject = new JsonArray(); valueObject.add("asset", assetObject); for (Map.Entry entry : value.getAssetsFilter().entrySet()) { JsonObject itemObject = new JsonObject(); itemObject.addProperty("location", entry.getKey().getLocation()); if (entry.getKey().getLocationID() != null) { itemObject.addProperty("locationid", entry.getKey().getLocationID()); } if (entry.getKey().getFlag() != null) { itemObject.addProperty("flag", entry.getKey().getFlag()); } itemObject.addProperty("value", entry.getValue()); assetObject.add(itemObject); } } return valueObject; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/XmlException.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; public class XmlException extends Exception { public XmlException(final String message) { super(message); } public XmlException(final String message, final Throwable cause) { super(message, cause); } public XmlException(final Throwable cause) { super(cause); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileAccountBalances.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyAccountBalance; import net.nikr.eve.jeveasset.data.api.raw.RawAccountBalance; import net.nikr.eve.jeveasset.io.shared.DataConverter; public class ProfileAccountBalances extends ProfileTable { private static final String ACCOUNT_BALANCES_TABLE = "accountbalances"; @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, ACCOUNT_BALANCES_TABLE); //Insert Data String sql = "INSERT OR REPLACE INTO " + ACCOUNT_BALANCES_TABLE + " (" + " accountid," + " accountkey," + " balance)" + " VALUES (?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner esiOwner) { return esiOwner.getAccountBalances().size(); } }); for (EsiOwner owner : esiOwners) { for (MyAccountBalance accountBalance : owner.getAccountBalances()) { int index = 0; setAttribute(statement, ++index, owner.getAccountID()); setAttribute(statement, ++index, accountBalance.getAccountKey()); setAttribute(statement, ++index, accountBalance.getBalance()); rows.addRow(); } } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { Map> accountBalances = new HashMap<>(); String sql = "SELECT * FROM " + ACCOUNT_BALANCES_TABLE; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { RawAccountBalance accountBalance = RawAccountBalance.create(); String accountID = getString(rs, "accountid"); int accountKey = getInt(rs, "accountkey"); double balance = getDouble(rs, "balance"); accountBalance.setAccountKey(accountKey); accountBalance.setBalance(balance); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } list(owner, accountBalances, DataConverter.toMyAccountBalance(accountBalance, owner)); } for (Map.Entry> entry : accountBalances.entrySet()) { entry.getKey().setAccountBalances(entry.getValue()); } } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, ACCOUNT_BALANCES_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, ACCOUNT_BALANCES_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + ACCOUNT_BALANCES_TABLE + " (\n" + " accountid TEXT,\n" + " accountkey INTEGER,\n" + " balance REAL,\n" + " UNIQUE(accountid, accountkey)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileActiveShip.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyShip; public class ProfileActiveShip extends ProfileTable { private static final String ACTIVE_SHIP_TABLE = "activeship"; @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, ACTIVE_SHIP_TABLE); //Insert Data String sql = "INSERT INTO " + ACTIVE_SHIP_TABLE + " (" + " accountid," + " itemid," + " typeid," + " locationid)" + " VALUES (?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner owner) { return owner.getActiveShip() != null ? 1 : 0; } }); for (EsiOwner owner : esiOwners) { int index = 0; MyShip activeShip = owner.getActiveShip(); if (activeShip == null) { continue; } setAttribute(statement, ++index, owner.getAccountID()); setAttribute(statement, ++index, activeShip.getItemID()); setAttribute(statement, ++index, activeShip.getTypeID()); setAttribute(statement, ++index, activeShip.getLocationID()); rows.addRow(); } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { String sql = "SELECT * FROM " + ACTIVE_SHIP_TABLE; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); long itemID = getLong(rs, "itemid"); int typeID = getInt(rs, "typeid"); long locationID = getLong(rs, "locationid"); MyShip activeShip = new MyShip(itemID, typeID, locationID); EsiOwner owner = owners.get(accountID); if (owner != null) { owner.setActiveShip(activeShip); } } } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, ACTIVE_SHIP_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, ACTIVE_SHIP_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + ACTIVE_SHIP_TABLE + " (\n" + " accountid TEXT,\n" + " itemid INTEGER,\n" + " typeid INTEGER,\n" + " locationid INTEGER,\n" + " UNIQUE(accountid)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileAssetDivisions.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; public class ProfileAssetDivisions extends ProfileTable { private static final String ASSET_DIVISIONS_TABLE = "assetdivisions"; @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, ASSET_DIVISIONS_TABLE); //Insert Data String sql = "INSERT INTO " + ASSET_DIVISIONS_TABLE + " (" + " accountid," + " id," + " name)" + " VALUES (?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner esiOwner) { return esiOwner.getAssetDivisions().size(); } }); for (EsiOwner owner : esiOwners) { for (Map.Entry entry : owner.getAssetDivisions().entrySet()) { int index = 0; setAttribute(statement, ++index, owner.getAccountID()); setAttribute(statement, ++index, entry.getKey()); setAttributeOptional(statement, ++index, entry.getValue()); rows.addRow(); } } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { Map> divisions = new HashMap<>(); String sql = "SELECT * FROM " + ASSET_DIVISIONS_TABLE; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); int id = getInt(rs, "id"); String name = getStringOptional(rs, "name"); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } map(owner, divisions, id, name); } for (Map.Entry> entry : divisions.entrySet()) { entry.getKey().setAssetDivisions(entry.getValue()); } } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, ASSET_DIVISIONS_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, ASSET_DIVISIONS_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + ASSET_DIVISIONS_TABLE + " (\n" + " accountid TEXT,\n" + " id INTEGER," + " name TEXT," + " UNIQUE(accountid, id)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileAssets.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.raw.RawAsset; import net.nikr.eve.jeveasset.io.shared.DataConverter; import net.nikr.eve.jeveasset.io.shared.RawConverter; public class ProfileAssets extends ProfileTable { private static final String ASSETS_TABLE = "assets"; @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, ASSETS_TABLE); //Insert data String sql = "INSERT OR REPLACE INTO " + ASSETS_TABLE + " (" + " accountid," + " count," + " flagid," + " flagstring," + " itemid," + " typeid," + " locationid," + " singleton," + " rawquantity)" + " VALUES (?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner owner) { return getAssetSize(owner.getAssets()); } }); for (EsiOwner owner : esiOwners) { insertAssets(statement, rows, owner.getAssets(), owner.getAccountID(), null); } } } private int getAssetSize(List assets) { int size = assets.size(); for (MyAsset asset : assets) { size += getAssetSize(asset.getAssets()); } return size; } private void insertAssets(PreparedStatement statement, Rows rows, final List assets, String accountID, Long parentID) throws SQLException { if (assets == null || assets.isEmpty()) { return; } for (MyAsset asset : assets) { int index = 0; Integer quantity = asset.getQuantity(); int count; Integer rawQuantity; if (quantity == null || quantity <= 0) { count = 1; rawQuantity = quantity; //Possible values: null, -1, -2 } else { count = quantity; rawQuantity = null; } setAttribute(statement, ++index, accountID); setAttribute(statement, ++index, count); setAttributeOptional(statement, ++index, asset.getFlagID()); setAttributeOptional(statement, ++index, asset.getLocationFlagString()); setAttribute(statement, ++index, asset.getItemID()); setAttribute(statement, ++index, asset.getItem().getTypeID()); if (parentID != null) { setAttribute(statement, ++index, parentID); } else { setAttribute(statement, ++index, asset.getLocationID()); } setAttribute(statement, ++index, asset.isSingleton()); setAttributeOptional(statement, ++index, rawQuantity); rows.addRow(); insertAssets(statement, rows, asset.getAssets(), accountID, asset.getItemID()); } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { Map> assets = new HashMap<>(); String sql = "SELECT * FROM " + ASSETS_TABLE; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { int count = getInt(rs, "count"); String accountID = getString(rs, "accountid"); long itemId = getLong(rs, "itemid"); int typeID = getInt(rs, "typeid"); long locationID = getLong(rs, "locationid"); boolean singleton = getBoolean(rs, "singleton"); Integer rawQuantity = getIntOptional(rs, "rawquantity"); int flagID = getInt(rs, "flagid"); String locationFlagString = getStringOptional(rs, "flagstring"); RawAsset rawAsset = RawAsset.create(); rawAsset.setItemID(itemId); rawAsset.setItemFlag(RawConverter.toFlag(flagID, locationFlagString)); rawAsset.setLocationFlagString(locationFlagString); rawAsset.setLocationID(locationID); rawAsset.setQuantity(RawConverter.toAssetQuantity(count, rawQuantity)); rawAsset.setSingleton(singleton); rawAsset.setTypeID(typeID); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } list(owner, assets, rawAsset); } } for (Map.Entry> entry : assets.entrySet()) { entry.getKey().setAssets(DataConverter.toRawAssets(entry.getValue(), entry.getKey())); } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, ASSETS_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, ASSETS_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + ASSETS_TABLE + " (\n" + " accountid TEXT,\n" + " count INTEGER,\n" + " flagid INTEGER,\n" + " flagstring TEXT,\n" + " itemid INTEGER,\n" + " typeid INTEGER,\n" + " locationid INTEGER,\n" + " singleton NUMERIC,\n" + " rawquantity INTEGER,\n" + " UNIQUE(accountid, itemid)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileBlueprints.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.raw.RawBlueprint; import net.nikr.eve.jeveasset.io.shared.RawConverter; public class ProfileBlueprints extends ProfileTable { private static final String BLUEPRINTS_TABLE = "blueprints"; @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, BLUEPRINTS_TABLE); //Insert data String sql = "INSERT INTO " + BLUEPRINTS_TABLE + " (" + " accountid," + " itemid," + " locationid," + " typeid," + " flagid," + " flagstring," + " quantity," + " timeefficiency," + " materialefficiency," + " runs)" + " VALUES (?,?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner esiOwner) { return esiOwner.getBlueprints().size(); } }); for (EsiOwner owner : esiOwners) { for (RawBlueprint blueprint : owner.getBlueprints().values()) { int index = 0; setAttribute(statement, ++index, owner.getAccountID()); setAttribute(statement, ++index, blueprint.getItemID()); setAttribute(statement, ++index, blueprint.getLocationID()); setAttribute(statement, ++index, blueprint.getTypeID()); setAttribute(statement, ++index, blueprint.getFlagID()); setAttributeOptional(statement, ++index, blueprint.getLocationFlagString()); setAttribute(statement, ++index, blueprint.getQuantity()); setAttribute(statement, ++index, blueprint.getTimeEfficiency()); setAttribute(statement, ++index, blueprint.getMaterialEfficiency()); setAttribute(statement, ++index, blueprint.getRuns()); rows.addRow(); } } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { Map> blueprints = new HashMap<>(); String sql = "SELECT * FROM " + BLUEPRINTS_TABLE; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); RawBlueprint blueprint = RawBlueprint.create(); long itemID = getLong(rs, "itemid"); long locationID = getLong(rs, "locationid"); int typeID = getInt(rs, "typeid"); int flagID = getInt(rs, "flagid"); String locationFlagString = getStringOptional(rs, "flagstring"); int quantity = getInt(rs, "quantity"); int timeEfficiency = getInt(rs, "timeefficiency"); int materialEfficiency = getInt(rs, "materialefficiency"); int runs = getInt(rs, "runs"); blueprint.setItemID(itemID); blueprint.setItemFlag(RawConverter.toFlag(flagID, locationFlagString)); blueprint.setLocationFlagString(locationFlagString); blueprint.setLocationID(locationID); blueprint.setMaterialEfficiency(materialEfficiency); blueprint.setQuantity(quantity); blueprint.setRuns(runs); blueprint.setTimeEfficiency(timeEfficiency); blueprint.setTypeID(typeID); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } map(owner, blueprints, itemID, blueprint); } for (Map.Entry> entry : blueprints.entrySet()) { entry.getKey().setBlueprints(entry.getValue()); } } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, BLUEPRINTS_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, BLUEPRINTS_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + BLUEPRINTS_TABLE + " (\n" + " accountid TEXT,\n" + " itemid INTEGER," + " locationid INTEGER," + " typeid INTEGER," + " flagid INTEGER," + " flagstring TEXT," + " quantity INTEGER," + " timeefficiency INTEGER," + " materialefficiency INTEGER," + " runs NUMERIC," + " UNIQUE(accountid, itemid)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileClones.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.raw.RawClone; public class ProfileClones extends ProfileTable { private static final String CLONES_TABLE = "clones"; private static final String CLONES_IMPLANTS_TABLE = "clonesimplants"; @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, CLONES_TABLE, CLONES_IMPLANTS_TABLE); //Insert data String sql = "INSERT INTO " + CLONES_TABLE + " (" + " accountid," + " locationid," + " jumpcloneid," + " name," + " active)" + " VALUES (?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner owner) { return owner.getClones().size(); } }); for (EsiOwner owner : esiOwners) { for (RawClone rawClone : owner.getClones()) { int index = 0; setAttribute(statement, ++index, owner.getAccountID()); setAttribute(statement, ++index, rawClone.getLocationID()); setAttribute(statement, ++index, rawClone.getJumpCloneID()); setAttributeOptional(statement, ++index, rawClone.getName()); setAttribute(statement, ++index, rawClone.isActive()); rows.addRow(); } } } //Insert data sql = "INSERT INTO " + CLONES_IMPLANTS_TABLE + " (" + " accountid," + " jumpcloneid," + " typeid)" + " VALUES (?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner owner) { int size = 0; for (RawClone clone : owner.getClones()) { size = size + clone.getImplants().size(); } return size; } }); for (EsiOwner owner : esiOwners) { for (RawClone rawClone : owner.getClones()) { for (int typeID : rawClone.getImplants()){ int index = 0; setAttribute(statement, ++index, owner.getAccountID()); setAttribute(statement, ++index, rawClone.getJumpCloneID()); setAttribute(statement, ++index, typeID); rows.addRow(); } } } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { if (!tableExist(connection, CLONES_TABLE)) { return; } Map> clones = new HashMap<>(); String sql = "SELECT * FROM " + CLONES_TABLE; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); RawClone rawClone = RawClone.create(); long locationID = getLong(rs, "locationid"); long jumpCloneID = getLong(rs, "jumpcloneid"); String name = getStringOptional(rs, "name"); boolean active = getBooleanNotNull(rs, "active", false); rawClone.setJumpCloneID(jumpCloneID); rawClone.setLocationID(locationID); rawClone.setName(name); rawClone.setActive(active); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } owner.getClones().add(rawClone); map(owner, clones, jumpCloneID, rawClone); } } sql = "SELECT * FROM " + CLONES_IMPLANTS_TABLE; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); long jumpCloneID = getLong(rs, "jumpcloneid"); int typeID = getInt(rs, "typeid"); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } clones.get(owner).get(jumpCloneID).getImplants().add(typeID); } } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, CLONES_TABLE, CLONES_IMPLANTS_TABLE); } @Override protected void updateTable(Connection connection) throws SQLException { addColumn(connection, CLONES_TABLE, "active", "INTEGER"); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, CLONES_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + CLONES_TABLE + " (\n" + " accountid TEXT,\n" + " locationid INTEGER," + " jumpcloneid INTEGER," + " name TEXT," + " active INTEGER," + " UNIQUE(accountid, locationid, jumpcloneid)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } sql = "CREATE TABLE IF NOT EXISTS " + CLONES_IMPLANTS_TABLE + " (\n" + " accountid TEXT,\n" + " jumpcloneid INTEGER," + " typeid INTEGER," + " UNIQUE(accountid, jumpcloneid, typeid)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileConnection.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.SQLException; public interface ProfileConnection { public void update(Connection connection) throws SQLException; } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileConnectionData.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; public abstract class ProfileConnectionData implements ProfileConnection { private final Collection t; public ProfileConnectionData(Collection t) { this.t = new ArrayList<>(t); } @Override public void update(Connection connection) throws SQLException { update(connection, t); } public abstract void update(Connection connection, Collection data) throws SQLException; } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileContracts.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.raw.RawContract; import net.nikr.eve.jeveasset.data.api.raw.RawContractItem; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.io.shared.DataConverter; import net.nikr.eve.jeveasset.io.shared.RawConverter; public class ProfileContracts extends ProfileTable { private static final String CONTRACTS_OWNERS_TABLE = "contractsowners"; private static final String CONTRACTS_TABLE = "contracts"; private static final String CONTRACT_ITEMS_TABLE = "contractitems"; @Override protected boolean isUpdated() { return Settings.get().isContractHistory(); } private static void set(PreparedStatement statement, MyContract contract) throws SQLException { int index = 0; setAttribute(statement, ++index, contract.getAcceptorID()); setAttribute(statement, ++index, contract.getAssigneeID()); setAttributeOptional(statement, ++index, contract.getAvailability()); setAttributeOptional(statement, ++index, contract.getAvailabilityString()); setAttributeOptional(statement, ++index, contract.getBuyout()); setAttributeOptional(statement, ++index, contract.getCollateral()); setAttribute(statement, ++index, contract.getContractID()); setAttributeOptional(statement, ++index, contract.getDateAccepted()); setAttributeOptional(statement, ++index, contract.getDateCompleted()); setAttribute(statement, ++index, contract.getDateExpired()); setAttribute(statement, ++index, contract.getDateIssued()); setAttributeOptional(statement, ++index, contract.getEndLocationID()); setAttribute(statement, ++index, contract.getIssuerCorpID()); setAttribute(statement, ++index, contract.getIssuerID()); setAttributeOptional(statement, ++index, contract.getDaysToComplete()); setAttributeOptional(statement, ++index, contract.getPrice()); setAttributeOptional(statement, ++index, contract.getReward()); setAttributeOptional(statement, ++index, contract.getStartLocationID()); setAttributeOptional(statement, ++index, contract.getStatus()); setAttributeOptional(statement, ++index, contract.getStatusString()); setAttributeOptional(statement, ++index, contract.getTitle()); setAttributeOptional(statement, ++index, contract.getTypeString()); setAttributeOptional(statement, ++index, contract.getType()); setAttributeOptional(statement, ++index, contract.getVolume()); setAttribute(statement, ++index, contract.isForCorp()); setAttribute(statement, ++index, contract.isESI()); } private static void set(PreparedStatement statement, MyContractItem contractItem) throws SQLException { int index = 0; setAttribute(statement, ++index, contractItem.getContract().getContractID()); setAttribute(statement, ++index, contractItem.isIncluded()); setAttribute(statement, ++index, contractItem.getQuantity()); setAttribute(statement, ++index, contractItem.getRecordID()); setAttribute(statement, ++index, contractItem.isSingleton()); setAttribute(statement, ++index, contractItem.getTypeID()); setAttributeOptional(statement, ++index, contractItem.getRawQuantity()); setAttributeOptional(statement, ++index, contractItem.getItemID()); setAttributeOptional(statement, ++index, contractItem.getLicensedRuns()); setAttributeOptional(statement, ++index, contractItem.getME()); setAttributeOptional(statement, ++index, contractItem.getTE()); } /** * Contract items are immutable (IGNORE) * @param connection * @param contractItemsLists * @throws java.sql.SQLException */ public static void updateContractItems(Connection connection, Collection> contractItemsLists) throws SQLException { //Tables exist if (!tableExist(connection, CONTRACT_ITEMS_TABLE)) { return; } //Insert data String sqlContractItems = "INSERT OR IGNORE INTO " + CONTRACT_ITEMS_TABLE + " (" + " contractid," + " included," + " quantity," + " recordid," + " singleton," + " typeid," + " rawquantity," + " itemid," + " runs," + " me," + " te)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sqlContractItems)) { Rows rows = new Rows(statement, contractItemsLists, new RowSize>() { @Override public int getSize(List contractItems) { return contractItems.size(); } }); for (Collection contractItems : contractItemsLists) { for (MyContractItem contractItem : contractItems) { set(statement, contractItem); rows.addRow(); } } } } /** * Contracts are mutable (REPLACE).Owners are immutable (IGNORE) * @param connection * @param accountID * @param contracts * @throws java.sql.SQLException */ public static void updateContracts(Connection connection, String accountID, Collection contracts) throws SQLException { //Tables exist if (!tableExist(connection, CONTRACTS_OWNERS_TABLE, CONTRACTS_TABLE)) { return; } //Insert data String sqlOwners = "INSERT OR IGNORE INTO " + CONTRACTS_OWNERS_TABLE + " (" + " accountid," + " contractid)" + " VALUES (?,?)" ; try (PreparedStatement statement = connection.prepareStatement(sqlOwners)) { Rows rows = new Rows(statement, contracts.size()); for (MyContract contract : contracts) { int index = 0; setAttribute(statement, ++index, accountID); setAttribute(statement, ++index, contract.getContractID()); rows.addRow(); } } String sqlContracts = "INSERT OR REPLACE INTO " + CONTRACTS_TABLE + " (" + " acceptorid," + " assigneeid," + " availability," + " availabilitystring," + " buyout," + " collateral," + " contractid," + " dateaccepted," + " datecompleted," + " dateexpired," + " dateissued," + " endstationid," + " issuercorpid," + " issuerid," + " numdays," + " price," + " reward," + " startstationid," + " status," + " statusstring," + " title," + " typestring," + " type," + " volume," + " forcorp," + " esi)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sqlContracts)) { Rows rows = new Rows(statement, contracts.size()); for (MyContract contract : contracts) { set(statement, contract); rows.addRow(); } } } @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, CONTRACTS_OWNERS_TABLE, CONTRACTS_TABLE, CONTRACT_ITEMS_TABLE); //Insert data String sqlOwners = "INSERT OR IGNORE INTO " + CONTRACTS_OWNERS_TABLE + " (" + " accountid," + " contractid)" + " VALUES (?,?)" ; try (PreparedStatement statement = connection.prepareStatement(sqlOwners)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner owner) { return owner.getContracts().size(); } }); for (EsiOwner owner : esiOwners) { for (MyContract contract : owner.getContracts().keySet()) { int index = 0; setAttribute(statement, ++index, owner.getAccountID()); setAttribute(statement, ++index, contract.getContractID()); rows.addRow(); } } } String sqlContracts = "INSERT OR REPLACE INTO " + CONTRACTS_TABLE + " (" + " acceptorid," + " assigneeid," + " availability," + " availabilitystring," + " buyout," + " collateral," + " contractid," + " dateaccepted," + " datecompleted," + " dateexpired," + " dateissued," + " endstationid," + " issuercorpid," + " issuerid," + " numdays," + " price," + " reward," + " startstationid," + " status," + " statusstring," + " title," + " typestring," + " type," + " volume," + " forcorp," + " esi)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sqlContracts)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner owner) { return owner.getContracts().keySet().size(); } }); for (EsiOwner owner : esiOwners) { for (MyContract contract : owner.getContracts().keySet()) { set(statement, contract); rows.addRow(); } } } String sqlContractItems = "INSERT OR IGNORE INTO " + CONTRACT_ITEMS_TABLE + " (" + " contractid," + " included," + " quantity," + " recordid," + " singleton," + " typeid," + " rawquantity," + " itemid," + " runs," + " me," + " te)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sqlContractItems)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner owner) { int size = 0; for (List contractItems : owner.getContracts().values()) { size += contractItems.size(); } return size; } }); for (EsiOwner owner : esiOwners) { for (List contractItems : owner.getContracts().values()) { for (MyContractItem contractItem : contractItems) { set(statement, contractItem); rows.addRow(); } } } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { String ownerSQL = "SELECT * FROM " + CONTRACTS_OWNERS_TABLE; Map> contractOwners = new HashMap<>(); Map>> contracts = new HashMap<>(); try (PreparedStatement statement = connection.prepareStatement(ownerSQL); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); int contractID = getInt(rs, "contractid"); Set set = contractOwners.get(contractID); if (set == null) { set = new HashSet<>(); contractOwners.put(contractID, set); } EsiOwner owner = owners.get(accountID); if (owner != null) { set.add(owner); contracts.put(owner, new HashMap<>()); } } } String contractsSQL = "SELECT * FROM " + CONTRACTS_TABLE; Map contractIDs = new HashMap<>(); try (PreparedStatement statement = connection.prepareStatement(contractsSQL); ResultSet rs = statement.executeQuery();) { while (rs.next()) { RawContract rawContract = RawContract.create(); int acceptorID = getInt(rs, "acceptorid"); int assigneeID = getInt(rs, "assigneeid"); String availabilityString = getStringOptional(rs, "availabilitystring"); String availabilityEnum = getStringOptional(rs, "availability"); Double buyout = getDoubleOptional(rs, "buyout"); Double collateral = getDoubleOptional(rs, "collateral"); int contractID = getInt(rs, "contractid"); Date dateAccepted = getDateOptional(rs, "dateaccepted"); Date dateCompleted = getDateOptional(rs, "datecompleted"); Date dateExpired = getDate(rs, "dateexpired"); Date dateIssued = getDate(rs, "dateissued"); Long endLocationID = getLongOptional(rs, "endstationid"); int issuerCorporationID = getInt(rs, "issuercorpid"); int issuerID = getInt(rs, "issuerid"); Integer daysToComplete = getIntOptional(rs, "numdays"); Double price = getDoubleOptional(rs, "price"); Double reward = getDoubleOptional(rs, "reward"); Long startLocationID = getLongOptional(rs, "startstationid"); String statusString = getStringOptional(rs, "statusstring"); String statusEnum = getStringOptional(rs, "status"); String title = getStringOptional(rs, "title"); String typeString = getStringOptional(rs, "typestring"); String typeEnum = getStringOptional(rs, "type"); Double volume = getDoubleOptional(rs, "volume"); boolean forCorporation = getBoolean(rs, "forcorp"); boolean esi = getBooleanNotNull(rs, "esi", true); rawContract.setAcceptorID(acceptorID); rawContract.setAssigneeID(assigneeID); rawContract.setAvailability(RawConverter.toContractAvailability(availabilityEnum, availabilityString)); rawContract.setAvailabilityString(availabilityString); rawContract.setBuyout(buyout); rawContract.setCollateral(collateral); rawContract.setContractID(contractID); rawContract.setDateAccepted(dateAccepted); rawContract.setDateCompleted(dateCompleted); rawContract.setDateExpired(dateExpired); rawContract.setDateIssued(dateIssued); rawContract.setDaysToComplete(daysToComplete); rawContract.setEndLocationID(endLocationID); rawContract.setForCorporation(forCorporation); rawContract.setIssuerCorporationID(issuerCorporationID); rawContract.setIssuerID(issuerID); rawContract.setPrice(price); rawContract.setReward(reward); rawContract.setStartLocationID(startLocationID); rawContract.setStatus(RawConverter.toContractStatus(statusEnum, statusString)); rawContract.setStatusString(statusString); rawContract.setTitle(title); rawContract.setTypeString(typeString); rawContract.setType(RawConverter.toContractType(typeEnum, typeString)); rawContract.setVolume(volume); MyContract contract = DataConverter.toMyContract(rawContract); contract.setESI(esi); contractIDs.put(contractID, contract); Set set = contractOwners.get(contractID); if (set != null) { for (EsiOwner esiOwner : set) { Map> map = contracts.get(esiOwner); map.put(contract, new ArrayList<>()); } } } } String contractItemsSQL = "SELECT * FROM " + CONTRACT_ITEMS_TABLE; try (PreparedStatement statement = connection.prepareStatement(contractItemsSQL); ResultSet rs = statement.executeQuery();) { while (rs.next()) { RawContractItem contractItem = RawContractItem.create(); int contractID = getInt(rs, "contractid"); boolean included = getBoolean(rs, "included"); int quantity = getInt(rs, "quantity"); long recordID = getLong(rs, "recordid"); boolean singleton = getBoolean(rs, "singleton"); int typeID = getInt(rs, "typeid"); Integer rawQuantity = getIntOptional(rs, "rawquantity"); Long itemID = getLongOptional(rs, "itemid"); Integer runs = getIntOptional(rs, "runs"); Integer materialEfficiency = getIntOptional(rs, "me"); Integer timeEfficiency = getIntOptional(rs, "te"); contractItem.setIncluded(included); contractItem.setQuantity(quantity); contractItem.setRecordID(recordID); contractItem.setSingleton(singleton); contractItem.setTypeID(typeID); contractItem.setRawQuantity(rawQuantity); contractItem.setItemID(itemID); contractItem.setLicensedRuns(runs); contractItem.setME(materialEfficiency); contractItem.setTE(timeEfficiency); MyContract contract = contractIDs.get(contractID); if (contract == null) { continue; } Set set = contractOwners.get(contractID); if (set != null) { for (EsiOwner esiOwner : set) { Map> map = contracts.get(esiOwner); List contractItems = map.get(contract); if (contractItems == null) { continue; } contractItems.add(DataConverter.toMyContractItem(contractItem, contract)); } } } } for (Map.Entry>> entry : contracts.entrySet()) { EsiOwner owner = entry.getKey(); owner.setContracts(entry.getValue()); } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, CONTRACTS_OWNERS_TABLE, CONTRACTS_TABLE, CONTRACT_ITEMS_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, CONTRACTS_OWNERS_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + CONTRACTS_OWNERS_TABLE + " (" + " accountid TEXT,\n" + " contractid INTEGER," + " UNIQUE(accountid, contractid)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } if (!tableExist(connection, CONTRACTS_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + CONTRACTS_TABLE + " (" + " acceptorid INTEGER," + " assigneeid INTEGER," + " availability TEXT," + " availabilitystring TEXT," + " buyout REAL," + " collateral REAL," + " contractid INTEGER," + " dateaccepted INTEGER," + " datecompleted INTEGER," + " dateexpired INTEGER," + " dateissued INTEGER," + " endstationid INTEGER," + " issuercorpid INTEGER," + " issuerid INTEGER," + " numdays INTEGER," + " price REAL," + " reward REAL," + " startstationid INTEGER," + " status TEXT," + " statusstring TEXT," + " title TEXT," + " typestring TEXT," + " type TEXT," + " volume REAL," + " forcorp NUMERIC," + " esi NUMERIC," + " UNIQUE(contractid)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } if (!tableExist(connection, CONTRACT_ITEMS_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + CONTRACT_ITEMS_TABLE + " (" + " contractid INTEGER," + " included NUMERIC," + " quantity INTEGER," + " recordid INTEGER," + " singleton NUMERIC," + " typeid INTEGER," + " rawquantity INTEGER," + " itemid INTEGER," + " runs INTEGER," + " me INTEGER," + " te INTEGER," + " UNIQUE(recordid)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileDatabase.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.profile.Profile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ProfileDatabase { private static final Logger LOG = LoggerFactory.getLogger(ProfileDatabase.class); private static final BlockingQueue UPDATES = new LinkedBlockingQueue<>(); public static enum Table { OWNERS(new ProfileOwners()), ASSETS(new ProfileAssets()), CLONES(new ProfileClones()), CONTRACTS(new ProfileContracts()), ACTIVE_SHIP(new ProfileActiveShip()), ACCOUNT_BALANCES(new ProfileAccountBalances()), MARKET_ORDERS(new ProfileMarketOrders()), JOURNALS(new ProfileJournals()), TRANSACTIONS(new ProfileTransactions()), INDUSTRY_JOBS(new ProfileIndustryJobs()), BLUEPRINTS(new ProfileBlueprints()), ASSET_DIVISIONS(new ProfileAssetDivisions()), WALLET_DIVISIONS(new ProfileWalletDivisions()), SKILLS(new ProfileSkills()), LOYALTY_POINTS(new ProfileLoyaltyPoints()), NPC_STANDING(new ProfileNpcStanding()), MINING(new ProfileMining()) ; private final ProfileTable profileTable; private Table(ProfileTable databaseTable) { this.profileTable = databaseTable; } public void insert(Connection connection, List esiOwners, boolean full) throws SQLException { if (esiOwners == null) { esiOwners = new ArrayList<>(); //Ensure never null } if (!full && profileTable.isUpdated()) { return; //Ignore updated } profileTable.insert(connection, esiOwners); } public void select(Connection connection, List esiOwners) throws SQLException { Map owners = new HashMap<>(); for (EsiOwner esiOwner : esiOwners) { owners.put(esiOwner.getAccountID(), esiOwner); } profileTable.select(connection, esiOwners, owners); } public void create(Connection connection) throws SQLException { profileTable.create(connection); } public void updateTable(Connection connection) throws SQLException { profileTable.updateTable(connection); } public boolean isEmpty(Connection connection) throws SQLException { return profileTable.isEmpty(connection); } } private static Connection updateConnection = null; private static String updateConnectionUrl = null; private static Updater updater = null; public static synchronized void setUpdateConnectionUrl(Profile profile) { if (updater == null) { updater = new Updater(); updater.start(); } if (profile == null) { updateConnectionUrl = null; } else { updateConnectionUrl = getConnectionUrl(profile.getSQLiteFilename()); } closeUpdateConnection(); } private static synchronized Connection getUpdateConnection() throws SQLException { if (updateConnectionUrl == null) { return null; } if (updateConnection == null) { updateConnection = DriverManager.getConnection(updateConnectionUrl); updateConnection.setAutoCommit(false); } return updateConnection; } private static synchronized void closeUpdateConnection() { if (updateConnection != null) { try { updateConnection.setAutoCommit(true); updateConnection.close(); } catch (SQLException ex) { logError(ex); } updateConnection = null; } } private static String getConnectionUrl(String filename) { return "jdbc:sqlite:" + filename; } public static boolean load(Profile profile) { backup(profile); String connectionUrl = getConnectionUrl(profile.getSQLiteFilename()); try (Connection connection = DriverManager.getConnection(connectionUrl)) { int loaded = 0; for (Table table : Table.values()) { if (!table.isEmpty(connection)) { table.updateTable(connection); table.select(connection, profile.getEsiOwners()); loaded++; } else if (table == Table.OWNERS) { return false; //Fatal error } else if (table == Table.CLONES || table == Table.LOYALTY_POINTS || table == Table.NPC_STANDING) { loaded++; //No problem (new talbes) } } if (loaded == Table.values().length) { return true; } else { return false; } } catch (SQLException ex) { logError(ex); return false; } } public static void update(ProfileConnection profileConnection) { UPDATES.add(new Update(profileConnection)); synchronized (UPDATES) { UPDATES.notifyAll(); } } public static void waitForUpdates() { while (!UPDATES.isEmpty()) { synchronized (UPDATES) { try { UPDATES.wait(); } catch (InterruptedException ex) { //No problem... } } } closeUpdateConnection(); } public static boolean save(Profile profile) { return save(profile, Table.values()); } public static boolean save(Profile profile, Table table) { return save(profile, Collections.singleton(table)); } private static boolean save(Profile profile, Table[] tables) { return save(profile, Arrays.asList(tables)); } private static boolean save(Profile profile, Collection tables) { String connectionUrl = getConnectionUrl(profile.getSQLiteFilename()); waitForUpdates(); try (Connection connection = DriverManager.getConnection(connectionUrl);) { try { connection.setAutoCommit(false); for (Table profileTable : tables) { boolean full = profileTable.isEmpty(connection); profileTable.create(connection); profileTable.updateTable(connection); profileTable.insert(connection, profile.getEsiOwners(), full); } connection.commit(); connection.setAutoCommit(true); } catch (SQLException ex) { connection.rollback(); throw ex; } return true; } catch (SQLException ex) { logError(ex); return false; } } private static void backup(final Profile profile) { backup(profile.getSQLiteFilename(), profile.getBackupSQLiteFilename()); } private static void backup(final String source, String backup) { File backupFile = new File(backup); File sourceFile = new File(source); if (sourceFile.exists() && !backupFile.exists()) { try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(backupFile)); InputStream in = new FileInputStream(sourceFile)) { ZipEntry e = new ZipEntry(sourceFile.getName()); out.putNextEntry(e); byte[] buffer = new byte[8192]; int len; while ((len = in.read(buffer)) != -1) { out.write(buffer, 0, len); } out.closeEntry(); LOG.info("Backup Created: " + backupFile.getName()); } catch (IOException ex) { LOG.error("Failed to create backup for new program version", ex); } } } private static class Update { private final ProfileConnection profileConnection; public Update(ProfileConnection profileConnection) { this.profileConnection = profileConnection; } public void doUpdate() throws SQLException { Connection connection = getUpdateConnection(); if (connection == null) { return; } try { profileConnection.update(connection); //Only commit once, when everything is done - so we can rollback on any errors connection.commit(); } catch (SQLException ex) { connection.rollback(); logError(ex); } } } private static class Updater extends Thread { @Override public void run() { while (true) { //Get update (null if queue is empty) Update update = UPDATES.peek(); if (update != null) { try { update.doUpdate(); } catch (SQLException ex) { logError(ex); } finally { UPDATES.poll(); //Remove update (completed) synchronized (UPDATES) { UPDATES.notifyAll(); } } } //Wait for new updates while (UPDATES.isEmpty()) { synchronized (UPDATES) { try { UPDATES.wait(); } catch (InterruptedException ex) { //No problem } } } } } } private static void logError(Exception ex) { LOG.error(ex.getMessage(), ex); throw new RuntimeException(ex); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileIndustryJobs.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.io.shared.DataConverter; import net.nikr.eve.jeveasset.io.shared.RawConverter; public class ProfileIndustryJobs extends ProfileTable { private static final String INDUSTRY_JOBS_TABLE = "industryjobs"; @Override protected boolean isUpdated() { return Settings.get().isIndustryJobsHistory(); } private static void set(PreparedStatement statement, MyIndustryJob industryJob, String accountID) throws SQLException { int index = 0; setAttribute(statement, ++index, accountID); setAttribute(statement, ++index, industryJob.getJobID()); setAttribute(statement, ++index, industryJob.getInstallerID()); setAttribute(statement, ++index, industryJob.getFacilityID()); setAttribute(statement, ++index, industryJob.getStationID()); setAttribute(statement, ++index, industryJob.getActivityID()); setAttribute(statement, ++index, industryJob.getBlueprintID()); setAttribute(statement, ++index, industryJob.getBlueprintTypeID()); setAttribute(statement, ++index, industryJob.getBlueprintLocationID()); setAttribute(statement, ++index, industryJob.getOutputLocationID()); setAttribute(statement, ++index, industryJob.getRuns()); setAttributeOptional(statement, ++index, industryJob.getCost()); setAttributeOptional(statement, ++index, industryJob.getLicensedRuns()); setAttributeOptional(statement, ++index, industryJob.getProbability()); setAttributeOptional(statement, ++index, industryJob.getProductTypeID()); setAttributeOptional(statement, ++index, industryJob.getStatus()); setAttributeOptional(statement, ++index, industryJob.getStatusString()); setAttribute(statement, ++index, industryJob.getDuration()); setAttribute(statement, ++index, industryJob.getStartDate()); setAttribute(statement, ++index, industryJob.getEndDate()); setAttributeOptional(statement, ++index, industryJob.getPauseDate()); setAttributeOptional(statement, ++index, industryJob.getCompletedDate()); setAttributeOptional(statement, ++index, industryJob.getCompletedCharacterID()); setAttributeOptional(statement, ++index, industryJob.getSuccessfulRuns()); setAttribute(statement, ++index, industryJob.isESI()); } /** * Industry jobs are mutable (REPLACE) * @param connection * @param accountID * @param industryJobs * @throws java.sql.SQLException */ public static void updateIndustryJobs(Connection connection, String accountID, Collection industryJobs) throws SQLException { //Tables exist if (!tableExist(connection, INDUSTRY_JOBS_TABLE)) { return; } //Insert data String sql = "INSERT OR REPLACE INTO " + INDUSTRY_JOBS_TABLE + " (" + " accountid," + " jobid," + " installerid," + " facilityid," + " stationid," + " activityid," + " blueprintid," + " blueprinttypeid," + " blueprintlocationid," + " outputlocationid," + " runs," + " cost," + " licensedruns," + " probability," + " producttypeid," + " statusenum," + " statusstring," + " timeinseconds," + " startdate," + " enddate," + " pausedate," + " completeddate," + " completedcharacterid," + " successfulruns," + " esi)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, industryJobs.size()); for (MyIndustryJob industryJob : industryJobs) { set(statement, industryJob, accountID); rows.addRow(); } } } @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, INDUSTRY_JOBS_TABLE); //Insert data String sql = "INSERT INTO " + INDUSTRY_JOBS_TABLE + " (" + " accountid," + " jobid," + " installerid," + " facilityid," + " stationid," + " activityid," + " blueprintid," + " blueprinttypeid," + " blueprintlocationid," + " outputlocationid," + " runs," + " cost," + " licensedruns," + " probability," + " producttypeid," + " statusenum," + " statusstring," + " timeinseconds," + " startdate," + " enddate," + " pausedate," + " completeddate," + " completedcharacterid," + " successfulruns," + " esi)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner owner) { return owner.getIndustryJobs().size(); } }); for (EsiOwner owner : esiOwners) { for (MyIndustryJob industryJob : owner.getIndustryJobs()) { set(statement, industryJob, owner.getAccountID()); rows.addRow(); } } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { Map> industryJobs = new HashMap<>(); String sql = "SELECT * FROM " + INDUSTRY_JOBS_TABLE; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); RawIndustryJob rawIndustryJob = RawIndustryJob.create(); int jobID = getInt(rs, "jobid"); int installerID = getInt(rs, "installerid"); long facilityID = getLong(rs, "facilityid"); long stationID = getLong(rs, "stationid"); int activityID = getInt(rs, "activityid"); long blueprintID = getLong(rs, "blueprintid"); int blueprintTypeID = getInt(rs, "blueprinttypeid"); long blueprintLocationID = getLong(rs, "blueprintlocationid"); long outputLocationID = getLong(rs, "outputlocationid"); int runs = getInt(rs, "runs"); Double cost = getDoubleOptional(rs, "cost"); Integer licensedRuns = getIntOptional(rs, "licensedruns"); Float probability = getFloatOptional(rs, "probability"); Integer productTypeID = getIntOptional(rs, "producttypeid"); //Integer statusInt = getIntOptional(rs, "status"); String statusEnum = getStringOptional(rs, "statusenum"); String statusString = getStringOptional(rs, "statusstring"); int duration = getInt(rs, "timeinseconds"); Date startDate = getDate(rs, "startdate"); Date endDate = getDate(rs, "enddate"); Date pauseDate = getDateOptional(rs, "pausedate"); Date completedDate = getDateOptional(rs, "completeddate"); Integer completedCharacterID = getIntOptional(rs, "completedcharacterid"); Integer successfulRuns = getIntOptional(rs, "successfulruns"); boolean esi = getBooleanNotNull(rs, "esi", true); rawIndustryJob.setActivityID(activityID); rawIndustryJob.setBlueprintID(blueprintID); rawIndustryJob.setBlueprintLocationID(blueprintLocationID); rawIndustryJob.setBlueprintTypeID(blueprintTypeID); rawIndustryJob.setCompletedCharacterID(completedCharacterID); rawIndustryJob.setCompletedDate(completedDate); rawIndustryJob.setCost(cost); rawIndustryJob.setDuration(duration); rawIndustryJob.setEndDate(endDate); rawIndustryJob.setFacilityID(facilityID); rawIndustryJob.setInstallerID(installerID); rawIndustryJob.setJobID(jobID); rawIndustryJob.setLicensedRuns(licensedRuns); rawIndustryJob.setOutputLocationID(outputLocationID); rawIndustryJob.setPauseDate(pauseDate); rawIndustryJob.setProbability(probability); rawIndustryJob.setProductTypeID(productTypeID); rawIndustryJob.setRuns(runs); rawIndustryJob.setStartDate(startDate); rawIndustryJob.setStationID(stationID); rawIndustryJob.setStatus(RawConverter.toIndustryJobStatus(null, statusEnum, statusString)); rawIndustryJob.setStatusString(statusString); rawIndustryJob.setSuccessfulRuns(successfulRuns); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } MyIndustryJob industryJob = DataConverter.toMyIndustryJob(rawIndustryJob, owner); industryJob.setESI(esi); set(owner, industryJobs, industryJob); } for (Map.Entry> entry : industryJobs.entrySet()) { entry.getKey().setIndustryJobs(entry.getValue()); } } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, INDUSTRY_JOBS_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, INDUSTRY_JOBS_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + INDUSTRY_JOBS_TABLE + " (\n" + " accountid TEXT,\n" + " jobid INTEGER," + " installerid INTEGER," + " facilityid INTEGER," + " stationid INTEGER," + " activityid INTEGER," + " blueprintid INTEGER," + " blueprinttypeid INTEGER," + " blueprintlocationid INTEGER," + " outputlocationid INTEGER," + " runs INTEGER," + " cost REAL," + " licensedruns INTEGER," + " probability REAL," + " producttypeid INTEGER," + " statusenum TEXT," + " statusstring TEXT," + " timeinseconds INTEGER," + " startdate INTEGER," + " enddate INTEGER," + " pausedate INTEGER," + " completeddate INTEGER," + " completedcharacterid INTEGER," + " successfulruns INTEGER," + " esi NUMERIC," + " UNIQUE(accountid, jobid)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileJournals.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.raw.RawJournal; import net.nikr.eve.jeveasset.data.api.raw.RawJournalRefType; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.io.shared.DataConverter; import net.nikr.eve.jeveasset.io.shared.RawConverter; public class ProfileJournals extends ProfileTable { private static final String JOURNALS_TABLE = "journals"; @Override protected boolean isUpdated() { return Settings.get().isJournalHistory(); } private static void set(PreparedStatement statement, MyJournal journal, String accountID) throws SQLException { int index = 0; setAttributeOptional(statement, ++index, accountID); setAttributeOptional(statement, ++index, journal.getAmount()); setAttributeOptional(statement, ++index, journal.getBalance()); setAttributeOptional(statement, ++index, journal.getContextID()); setAttributeOptional(statement, ++index, journal.getContextType()); setAttributeOptional(statement, ++index, journal.getContextTypeString()); setAttribute(statement, ++index, journal.getDate()); setAttribute(statement, ++index, journal.getDescription()); setAttributeOptional(statement, ++index, journal.getFirstPartyID()); setAttributeOptional(statement, ++index, journal.getSecondPartyID()); setAttributeOptional(statement, ++index, journal.getReason()); setAttribute(statement, ++index, journal.getRefID()); if (journal.getRefType() != null) { setAttributeOptional(statement, ++index, journal.getRefType().getID()); } else { setAttributeNull(statement, ++index); } setAttribute(statement, ++index, journal.getRefTypeString()); setAttributeOptional(statement, ++index, journal.getTaxAmount()); setAttributeOptional(statement, ++index, journal.getTaxReceiverID()); //Extra setAttribute(statement, ++index, journal.getAccountKey()); } /** * Journal entries are immutable (IGNORE) * @param connection * @param accountID * @param journals * @throws java.sql.SQLException */ public static void updateJournals(Connection connection, String accountID, Collection journals) throws SQLException { //Tables exist if (!tableExist(connection, JOURNALS_TABLE)) { return; } //Insert data String sql = "INSERT OR IGNORE INTO " + JOURNALS_TABLE + " (" + " accountid," + " amount," + " balance," + " contextid," + " contexttype," + " contexttypestring," + " date," + " description," + " ownerid1," + " ownerid2," + " reason," + " refid," + " reftypeid," + " reftypestring," + " taxamount," + " taxreceiverid," + " accountkey)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, journals.size()); for (MyJournal journal : journals) { set(statement, journal, accountID); rows.addRow(); } } } @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, JOURNALS_TABLE); //Insert data String sql = "INSERT INTO " + JOURNALS_TABLE + " (" + " accountid," + " amount," + " balance," + " contextid," + " contexttype," + " contexttypestring," + " date," + " description," + " ownerid1," + " ownerid2," + " reason," + " refid," + " reftypeid," + " reftypestring," + " taxamount," + " taxreceiverid," + " accountkey)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner owner) { return owner.getJournal().size(); } }); for (EsiOwner owner : esiOwners) { for (MyJournal journal : owner.getJournal()) { set(statement, journal, owner.getAccountID()); rows.addRow(); } } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { Map> journals = new HashMap<>(); String sql = "SELECT * FROM " + JOURNALS_TABLE; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); RawJournal rawJournal = RawJournal.create(); Double amount = getDoubleOptional(rs, "amount"); Double balance = getDoubleOptional(rs, "balance"); Long contextID = getLongOptional(rs, "contextid"); String contextType = getStringOptional(rs, "contexttype"); String contextTypeString = getStringOptional(rs, "contexttypestring"); Date date = getDate(rs, "date"); String description = getStringNotNull(rs, "description", ""); Integer firstPartyID = getIntOptional(rs, "ownerid1"); Integer secondPartyID = getIntOptional(rs, "ownerid2"); String reason = getStringOptional(rs, "reason"); long refID = getLong(rs, "refid"); Integer refTypeEnum = getIntOptional(rs, "reftypeid"); String refTypeString = getStringOptional(rs, "reftypestring"); Double taxAmount = getDoubleOptional(rs, "taxamount"); Integer taxReceiverID = getIntOptional(rs, "taxreceiverid"); //Extra int accountKey = getInt(rs, "accountkey"); rawJournal.setAmount(amount); rawJournal.setBalance(balance); rawJournal.setDate(date); rawJournal.setDescription(description); rawJournal.setFirstPartyID(firstPartyID); rawJournal.setReason(reason); rawJournal.setRefID(refID); RawJournalRefType refType = RawConverter.toJournalRefType(refTypeEnum, refTypeString); rawJournal.setRefType(refType); rawJournal.setRefTypeString(refTypeString); rawJournal.setSecondPartyID(secondPartyID); rawJournal.setTax(taxAmount); rawJournal.setTaxReceiverID(taxReceiverID); rawJournal.setContextID(contextID); rawJournal.setContextType(RawConverter.toJournalContextType(contextType, contextTypeString)); rawJournal.setContextTypeString(contextTypeString); rawJournal.setAccountKey(accountKey); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } set(owner, journals, DataConverter.toMyJournal(rawJournal, owner)); } for (Map.Entry> entry : journals.entrySet()) { entry.getKey().setJournal(entry.getValue()); } } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, JOURNALS_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, JOURNALS_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + JOURNALS_TABLE + " (\n" + " accountid TEXT," + " amount REAL," + " balance REAL," + " contextid INTEGER," + " contexttype TEXT," + " contexttypestring TEXT," + " date INTEGER," + " description TEXT," + " ownerid1 INTEGER," + " ownerid2 INTEGER," + " reason TEXT," + " refid INTEGER," + " reftypeid INTEGER," + " reftypestring TEXT," + " taxamount REAL," + " taxreceiverid INTEGER," + " accountkey INTEGER," + " UNIQUE(accountid, refid, amount)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileLoyaltyPoints.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.raw.RawLoyaltyPoints; import net.nikr.eve.jeveasset.io.shared.DataConverter; public class ProfileLoyaltyPoints extends ProfileTable { private static final String LOYALTY_POINTS_TABLE = "loyaltypoints"; @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, LOYALTY_POINTS_TABLE); //Insert Data String sql = "INSERT INTO " + LOYALTY_POINTS_TABLE + " (" + " accountid," + " corporationid," + " loyaltypoints)" + " VALUES (?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner esiOwner) { return esiOwner.getLoyaltyPoints().size(); } }); for (EsiOwner owner : esiOwners) { for (MyLoyaltyPoints loyaltyPoints : owner.getLoyaltyPoints()) { int index = 0; setAttribute(statement, ++index, owner.getAccountID()); setAttribute(statement, ++index, loyaltyPoints.getCorporationID()); setAttribute(statement, ++index, loyaltyPoints.getLoyaltyPoints()); rows.addRow(); } } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { if (!tableExist(connection, LOYALTY_POINTS_TABLE)) { return; } Map> loyaltyPointses = new HashMap<>(); String sql = "SELECT * FROM " + LOYALTY_POINTS_TABLE; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { RawLoyaltyPoints rawLoyaltyPoints = RawLoyaltyPoints.create(); String accountID = getString(rs, "accountid"); int corporationID = getInt(rs, "corporationid"); int loyaltyPoints = getInt(rs, "loyaltypoints"); rawLoyaltyPoints.setCorporationID(corporationID); rawLoyaltyPoints.setLoyaltyPoints(loyaltyPoints); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } set(owner, loyaltyPointses, DataConverter.toMyLoyaltyPoints(rawLoyaltyPoints, owner)); } for (Map.Entry> entry : loyaltyPointses.entrySet()) { entry.getKey().setLoyaltyPoints(entry.getValue()); } } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, LOYALTY_POINTS_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, LOYALTY_POINTS_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + LOYALTY_POINTS_TABLE + " (\n" + " accountid TEXT,\n" + " corporationid INTEGER,\n" + " loyaltypoints INTEGER,\n" + " UNIQUE(accountid, corporationid)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileMarketOrders.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.Change; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.io.shared.DataConverter; import net.nikr.eve.jeveasset.io.shared.RawConverter; public class ProfileMarketOrders extends ProfileTable { private static final String MARKET_ORDERS_TABLE = "marketorders"; private static final String MARKET_ORDER_CHANGES_TABLE = "marketorderchanges"; @Override protected boolean isUpdated() { return Settings.get().isMarketOrderHistory(); } private static void set(PreparedStatement statement, MyMarketOrder marketOrder, RawMarketOrder.Change change) throws SQLException { int index = 0; setAttribute(statement, ++index, marketOrder.getOrderID()); setAttribute(statement, ++index, change.getDate()); setAttributeOptional(statement, ++index, change.getPrice()); setAttributeOptional(statement, ++index, change.getVolumeRemaining()); } private static void set(PreparedStatement statement, MyMarketOrder marketOrder, String accountID) throws SQLException { int index = 0; setAttribute(statement, ++index, accountID); setAttribute(statement, ++index, marketOrder.getOrderID()); setAttribute(statement, ++index, marketOrder.getLocationID()); setAttribute(statement, ++index, marketOrder.getRegionID()); setAttribute(statement, ++index, marketOrder.getVolumeTotal()); setAttribute(statement, ++index, marketOrder.getVolumeRemain()); setAttribute(statement, ++index, marketOrder.getMinVolume()); setAttributeOptional(statement, ++index, marketOrder.getState()); setAttributeOptional(statement, ++index, marketOrder.getStateString()); setAttribute(statement, ++index, marketOrder.getTypeID()); setAttributeOptional(statement, ++index, marketOrder.getRange()); setAttributeOptional(statement, ++index, marketOrder.getRangeString()); setAttribute(statement, ++index, marketOrder.getWalletDivision()); setAttribute(statement, ++index, marketOrder.getDuration()); setAttribute(statement, ++index, marketOrder.getEscrow()); setAttribute(statement, ++index, marketOrder.getPrice()); setAttribute(statement, ++index, RawConverter.fromMarketOrderIsBuyOrder(marketOrder.isBuyOrder())); setAttribute(statement, ++index, marketOrder.getIssued()); setAttributeOptional(statement, ++index, marketOrder.getIssuedBy()); setAttribute(statement, ++index, marketOrder.isCorp()); setAttribute(statement, ++index, marketOrder.isESI()); } /** * Market orders are mutable (REPLACE).Market order changes are immutable (IGNORE) * @param connection * @param accountID * @param marketOrders * @throws java.sql.SQLException */ public static void updateMarketOrders(Connection connection, String accountID, Collection marketOrders) throws SQLException { //Tables exist if (!tableExist(connection, MARKET_ORDERS_TABLE, MARKET_ORDER_CHANGES_TABLE)) { return; } //Insert data String ordersSQL = "INSERT OR REPLACE INTO " + MARKET_ORDERS_TABLE + " (" + " accountid," + " orderid," + " stationid," + " regionid," + " volentered," + " volremaining," + " minvolume," + " orderstateenum," + " orderstatestring," + " typeid," + " rangeenum," + " rangestring," + " accountkey," + " duration," + " escrow," + " price," + " bid," + " issued," + " issuedby," + " corp," + " esi)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)" ; try (PreparedStatement statement = connection.prepareStatement(ordersSQL)) { Rows rows = new Rows(statement, marketOrders.size()); for (MyMarketOrder marketOrder : marketOrders) { set(statement, marketOrder, accountID); rows.addRow(); } } String changesSQL = "INSERT OR IGNORE INTO " + MARKET_ORDER_CHANGES_TABLE + " (" + " orderid," + " date," + " price," + " volremaining)" + " VALUES (?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(changesSQL)) { Rows rows = new Rows(statement, marketOrders.size()); for (MyMarketOrder marketOrder : marketOrders) { for (RawMarketOrder.Change change : marketOrder.getChanges()) { set(statement, marketOrder, change); rows.addRow(); } } } } @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, MARKET_ORDERS_TABLE, MARKET_ORDER_CHANGES_TABLE); //Insert data String ordersSQL = "INSERT INTO " + MARKET_ORDERS_TABLE + " (" + " accountid," + " orderid," + " stationid," + " regionid," + " volentered," + " volremaining," + " minvolume," + " orderstateenum," + " orderstatestring," + " typeid," + " rangeenum," + " rangestring," + " accountkey," + " duration," + " escrow," + " price," + " bid," + " issued," + " issuedby," + " corp," + " esi)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)" ; try (PreparedStatement statement = connection.prepareStatement(ordersSQL)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner owner) { return owner.getMarketOrders().size(); } }); for (EsiOwner owner : esiOwners) { for (MyMarketOrder marketOrder : owner.getMarketOrders()) { set(statement, marketOrder, owner.getAccountID()); rows.addRow(); } } } String changesSQL = "INSERT OR IGNORE INTO " + MARKET_ORDER_CHANGES_TABLE + " (" + " orderid," + " date," + " price," + " volremaining)" + " VALUES (?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(changesSQL)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner owner) { return owner.getMarketOrders().size(); } }); for (EsiOwner owner : esiOwners) { for (MyMarketOrder marketOrder : owner.getMarketOrders()) { for (RawMarketOrder.Change change : marketOrder.getChanges()) { set(statement, marketOrder, change); rows.addRow(); } } } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { Map> marketOrders = new HashMap<>(); Map> changes = new HashMap<>(); String changesSQL = "SELECT * FROM " + MARKET_ORDER_CHANGES_TABLE; try (PreparedStatement statement = connection.prepareStatement(changesSQL); ResultSet rs = statement.executeQuery();) { while (rs.next()) { long orderID = getLong(rs, "orderid"); Date date = getDate(rs, "date"); Double changePrice = getDoubleOptional(rs, "price"); Integer changeVolRemaining = getIntOptional(rs, "volremaining"); Set set = changes.get(orderID); if (set == null) { set = new HashSet<>(); changes.put(orderID, set); } set.add(new Change(date, changePrice, changeVolRemaining)); } for (Map.Entry> entry : marketOrders.entrySet()) { entry.getKey().setMarketOrders(entry.getValue()); } } String ordersSQL = "SELECT * FROM " + MARKET_ORDERS_TABLE; try (PreparedStatement statement = connection.prepareStatement(ordersSQL); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } RawMarketOrder rawMarketOrder = RawMarketOrder.create(); long orderID = getLong(rs, "orderid"); long locationID = getLong(rs, "stationid"); Integer regionID = getIntOptional(rs, "regionid"); int volEntered = getInt(rs, "volentered"); int volRemaining = getInt(rs, "volremaining"); int minVolume = getInt(rs, "minvolume"); String stateEnum = getStringOptional(rs, "orderstateenum"); String stateString = getStringOptional(rs, "orderstatestring"); int typeID = getInt(rs, "typeid"); String rangeEnum = getStringOptional(rs, "rangeenum"); String rangeString = getStringOptional(rs, "rangestring"); int accountkey = getInt(rs, "accountkey"); int duration = getInt(rs, "duration"); double escrow = getDouble(rs, "escrow"); double price = getDouble(rs, "price"); int bid = getInt(rs, "bid"); Date issued = getDate(rs, "issued"); Integer issuedBy = getIntOptional(rs, "issuedby"); boolean corp = getBooleanNotNull(rs, "corp", owner.isCorporation()); boolean esi = getBooleanNotNull(rs, "esi", true); rawMarketOrder.setWalletDivision(accountkey); rawMarketOrder.setDuration(duration); rawMarketOrder.setEscrow(escrow); rawMarketOrder.setBuyOrder(bid > 0); rawMarketOrder.setCorp(corp); rawMarketOrder.setIssued(issued); rawMarketOrder.addChanges(changes.get(orderID)); rawMarketOrder.setIssuedBy(issuedBy); rawMarketOrder.setLocationID(locationID); rawMarketOrder.setMinVolume(minVolume); rawMarketOrder.setOrderID(orderID); rawMarketOrder.setPrice(price); rawMarketOrder.setRange(RawConverter.toMarketOrderRange(null, rangeEnum, rangeString)); rawMarketOrder.setRangeString(rangeString); rawMarketOrder.setRegionID(RawConverter.toMarketOrderRegionID(locationID, typeID, regionID)); rawMarketOrder.setState(RawConverter.toMarketOrderState(null, stateEnum, stateString)); rawMarketOrder.setStateString(stateString); rawMarketOrder.setTypeID(typeID); rawMarketOrder.setVolumeRemain(volRemaining); rawMarketOrder.setVolumeTotal(volEntered); MyMarketOrder marketOrder = DataConverter.toMyMarketOrder(rawMarketOrder, owner); marketOrder.setESI(esi); set(owner, marketOrders, marketOrder); } for (Map.Entry> entry : marketOrders.entrySet()) { entry.getKey().setMarketOrders(entry.getValue()); } } } @Override protected void updateTable(Connection connection) throws SQLException { addColumn(connection, MARKET_ORDERS_TABLE, "regionid", "INTEGER"); } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, MARKET_ORDERS_TABLE, MARKET_ORDER_CHANGES_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, MARKET_ORDERS_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + MARKET_ORDERS_TABLE + " (\n" + " accountid TEXT," + " orderid INTEGER," + " stationid INTEGER," + " regionid INTEGER," + " volentered INTEGER," + " volremaining INTEGER," + " minvolume INTEGER," + " orderstateenum TEXT," + " orderstatestring TEXT," + " typeid INTEGER," + " rangeenum TEXT," + " rangestring TEXT," + " accountkey INTEGER," + " duration INTEGER," + " escrow REAL," + " price REAL," + " bid NUMERIC," + " issued INTEGER," + " issuedby INTEGER," + " corp NUMERIC," + " esi NUMERIC," + " UNIQUE(accountid, orderid)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } if (!tableExist(connection, MARKET_ORDER_CHANGES_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + MARKET_ORDER_CHANGES_TABLE + " (\n" + " orderid INTEGER," + " date INTEGER," + " price REAL," + " volremaining INTEGER, " + " UNIQUE(orderid, date)" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileMining.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyExtraction; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.data.api.raw.RawExtraction; import net.nikr.eve.jeveasset.data.api.raw.RawMining; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.io.shared.DataConverter; public class ProfileMining extends ProfileTable { private static final String MINING_TABLE = "mining"; private static final String MINING_EXTRACTION_TABLE = "miningextraction"; @Override protected boolean isUpdated() { return Settings.get().isMiningHistory(); } private static void set(PreparedStatement statement, MyExtraction extraction, String accountID) throws SQLException { int index = 0; setAttribute(statement, ++index, accountID); setAttribute(statement, ++index, extraction.getChunkArrivalTime()); setAttribute(statement, ++index, extraction.getExtractionStartTime()); setAttribute(statement, ++index, extraction.getMoonID()); setAttribute(statement, ++index, extraction.getNaturalDecayTime()); setAttribute(statement, ++index, extraction.getStructureID()); } private static void set(PreparedStatement statement, MyMining mining, String accountID) throws SQLException { int index = 0; setAttribute(statement, ++index, accountID); setAttribute(statement, ++index, mining.getTypeID()); setAttribute(statement, ++index, mining.getDate()); setAttribute(statement, ++index, mining.getCount()); setAttribute(statement, ++index, mining.getLocationID()); setAttribute(statement, ++index, mining.getCharacterID()); setAttributeOptional(statement, ++index, mining.getCorporationID()); setAttributeOptional(statement, ++index, mining.getCorporationName()); setAttribute(statement, ++index, mining.isForCorporation()); } /** * Minings are mutable (REPLACE) * @param connection * @param accountID * @param minings * @throws java.sql.SQLException */ public static void updateMinings(Connection connection, String accountID, Collection minings) throws SQLException { //Tables exist if (!tableExist(connection, MINING_TABLE)) { return; } //Insert data String miningSQL = "INSERT OR REPLACE INTO " + MINING_TABLE + " (" + " accountid," + " typeid," + " date," + " count," + " locationid," + " characterid," + " corporationid," + " corporation," + " forcorp)" + " VALUES (?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(miningSQL)) { Rows rows = new Rows(statement, minings.size()); for (MyMining mining : minings) { set(statement, mining, accountID); rows.addRow(); } } } /** * Not sure if extractions are immutable or mutable (REPLACE) * @param connection * @param accountID * @param extractions * @throws java.sql.SQLException */ public static void updateExtractions(Connection connection, String accountID, Collection extractions) throws SQLException { //Tables exist if (!tableExist(connection, MINING_EXTRACTION_TABLE)) { return; } String extractionSQL = "INSERT OR REPLACE INTO " + MINING_EXTRACTION_TABLE + " (" + " accountid," + " arrival," + " start," + " moon," + " decay," + " structure)" + " VALUES (?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(extractionSQL)) { Rows rows = new Rows(statement, extractions.size()); for (MyExtraction extraction : extractions) { set(statement, extraction, accountID); rows.addRow(); } } } @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, MINING_TABLE, MINING_EXTRACTION_TABLE); //Insert data String miningSQL = "INSERT OR REPLACE INTO " + MINING_TABLE + " (" + " accountid," + " typeid," + " date," + " count," + " locationid," + " characterid," + " corporationid," + " corporation," + " forcorp)" + " VALUES (?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(miningSQL)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner esiOwner) { return esiOwner.getMining().size(); } }); for (EsiOwner owner : esiOwners) { for (MyMining mining : owner.getMining()) { set(statement, mining, owner.getAccountID()); rows.addRow(); } } } String extractionSQL = "INSERT INTO " + MINING_EXTRACTION_TABLE + " (" + " accountid," + " arrival," + " start," + " moon," + " decay," + " structure)" + " VALUES (?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(extractionSQL)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner esiOwner) { return esiOwner.getExtractions().size(); } }); for (EsiOwner owner : esiOwners) { for (MyExtraction extraction : owner.getExtractions()) { set(statement, extraction, owner.getAccountID()); rows.addRow(); } } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { Map> minings = new HashMap<>(); Map> extractions = new HashMap<>(); String miningSQL = "SELECT * FROM " + MINING_TABLE; try (PreparedStatement statement = connection.prepareStatement(miningSQL); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } int typeID = getInt(rs, "typeid"); Date date = getDate(rs, "date"); long count = getLong(rs, "count"); long locationID = getLong(rs, "locationid"); Long characterID = getLongOptional(rs, "characterid"); if (characterID == null) { characterID = owner.getOwnerID(); } String corporationName = getStringOptional(rs, "corporation"); Long corporationID = getLongOptional(rs, "corporationid"); boolean forCorporation = getBoolean(rs, "forcorp"); RawMining mining = RawMining.create(); mining.setTypeID(typeID); mining.setDate(date); mining.setCount(count); mining.setLocationID(locationID); mining.setCharacterID(characterID); mining.setCorporationID(corporationID); mining.setCorporationName(corporationName); mining.setForCorporation(forCorporation); set(owner, minings, DataConverter.toMyMining(mining)); } for (Map.Entry> entry : minings.entrySet()) { entry.getKey().setMining(entry.getValue()); } } String extractionSQL = "SELECT * FROM " + MINING_EXTRACTION_TABLE; try (PreparedStatement statement = connection.prepareStatement(extractionSQL); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); Date arrival = getDate(rs, "arrival"); Date start = getDate(rs, "start"); Date decay = getDate(rs, "decay"); int moon = getInt(rs, "moon"); long structure = getLong(rs, "structure"); RawExtraction mining = RawExtraction.create(); mining.setChunkArrivalTime(arrival); mining.setExtractionStartTime(start); mining.setMoonID(moon); mining.setNaturalDecayTime(decay); mining.setStructureID(structure); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } set(owner, extractions, DataConverter.toMyExtraction(mining)); } for (Map.Entry> entry : extractions.entrySet()) { entry.getKey().setExtractions(entry.getValue()); } } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, MINING_TABLE, MINING_EXTRACTION_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, MINING_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + MINING_TABLE + " (\n" + " accountid TEXT,\n" + " typeid INTEGER," + " date INTEGER," + " count INTEGER," + " locationid INTEGER," + " characterid INTEGER," + " corporationid INTEGER," + " corporation TEXT," + " forcorp NUMERIC," + " UNIQUE(date, locationid, typeid, characterid, forcorp)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } if (!tableExist(connection, MINING_EXTRACTION_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + MINING_EXTRACTION_TABLE + " (\n" + " accountid TEXT,\n" + " arrival INTEGER," + " start INTEGER," + " moon INTEGER," + " decay INTEGER," + " structure INTEGER," + " UNIQUE(accountid, start, moon)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileNpcStanding.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.api.raw.RawNpcStanding; import net.nikr.eve.jeveasset.io.shared.DataConverter; import net.nikr.eve.jeveasset.io.shared.RawConverter; public class ProfileNpcStanding extends ProfileTable { private static final String NPC_STANDING_TABLE = "npcstanding"; @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, NPC_STANDING_TABLE); //Insert Data String sql = "INSERT INTO " + NPC_STANDING_TABLE + " (" + " accountid," + " fromid," + " fromtype," + " fromtypestring," + " standing)" + " VALUES (?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner esiOwner) { return esiOwner.getNpcStanding().size(); } }); for (EsiOwner owner : esiOwners) { for (MyNpcStanding npcStanding : owner.getNpcStanding()) { int index = 0; setAttribute(statement, ++index, owner.getAccountID()); setAttribute(statement, ++index, npcStanding.getFromID()); setAttribute(statement, ++index, npcStanding.getFromType()); setAttribute(statement, ++index, npcStanding.getFromTypeString()); setAttribute(statement, ++index, npcStanding.getStanding()); rows.addRow(); } } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { if (!tableExist(connection, NPC_STANDING_TABLE)) { return; } Map> npcStandings = new HashMap<>(); String sql = "SELECT * FROM " + NPC_STANDING_TABLE; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { RawNpcStanding rawNpcStanding = RawNpcStanding.create(); String accountID = getString(rs, "accountid"); int fromID = getInt(rs, "fromid"); String fromType = getString(rs, "fromtype"); String fromTypeString = getString(rs, "fromtypestring"); Float standing = getFloat(rs, "standing"); rawNpcStanding.setFromID(fromID); rawNpcStanding.setFromType(RawConverter.toNpcStandingFromType(fromType, fromTypeString)); rawNpcStanding.setFromTypeString(fromTypeString); rawNpcStanding.setStanding(standing); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } set(owner, npcStandings, DataConverter.toMyNpcStanding(rawNpcStanding, owner)); } for (Map.Entry> entry : npcStandings.entrySet()) { entry.getKey().setNpcStanding(entry.getValue()); } } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, NPC_STANDING_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, NPC_STANDING_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + NPC_STANDING_TABLE + " (\n" + " accountid TEXT,\n" + " fromid INTEGER,\n" + " fromtype TEXT,\n" + " fromtypestring TEXT,\n" + " standing REAL,\n" + " UNIQUE(accountid, fromid)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileOwners.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Arrays; import java.util.Date; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.io.esi.EsiCallbackURL; import net.troja.eve.esi.model.CharacterRolesResponse; public class ProfileOwners extends ProfileTable { private static final String OWNERS_TABLE = "owners"; @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, OWNERS_TABLE); //Insert data String sql = "INSERT INTO " + OWNERS_TABLE + " (" + " accountid," + " ownerid," + " name," + " corp," + " show," + " invalid," + " assetslastupdate," + " assetsnextupdate," + " balancelastupdate," + " balancenextupdate," + " marketordersnextupdate," + " journalnextupdate," + " transactionsnextupdate," + " industryjobsnextupdate," + " contractsnextupdate," + " locationsnextupdate," + " blueprintsnextupdate," + " skillsnextupdate," + " loyaltypointsnextupdate," + " npcstandingnextupdate," + " miningnextupdate," + " accountname," + " refreshtoken," + " scopes," + " structuresnextupdate," + " accountnextupdate," + " callbackurl," + " characterroles)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, esiOwners.size()); for (EsiOwner owner : esiOwners) { int index = 0; setAttribute(statement, ++index, owner.getAccountID()); setAttribute(statement, ++index, owner.getOwnerID()); setAttribute(statement, ++index, owner.getOwnerName()); setAttributeOptional(statement, ++index, owner.getCorporationName()); setAttribute(statement, ++index, owner.isShowOwner()); setAttribute(statement, ++index, owner.isInvalid()); setAttributeOptional(statement, ++index, owner.getAssetLastUpdate()); setAttribute(statement, ++index, owner.getAssetNextUpdate()); setAttributeOptional(statement, ++index, owner.getBalanceLastUpdate()); setAttribute(statement, ++index, owner.getBalanceNextUpdate()); setAttribute(statement, ++index, owner.getMarketOrdersNextUpdate()); setAttribute(statement, ++index, owner.getJournalNextUpdate()); setAttribute(statement, ++index, owner.getTransactionsNextUpdate()); setAttribute(statement, ++index, owner.getIndustryJobsNextUpdate()); setAttribute(statement, ++index, owner.getContractsNextUpdate()); setAttribute(statement, ++index, owner.getLocationsNextUpdate()); setAttribute(statement, ++index, owner.getBlueprintsNextUpdate()); setAttribute(statement, ++index, owner.getSkillsNextUpdate()); setAttribute(statement, ++index, owner.getLoyaltyPointsNextUpdate()); setAttribute(statement, ++index, owner.getNpcStandingNextUpdate()); setAttribute(statement, ++index, owner.getMiningNextUpdate()); setAttribute(statement, ++index, owner.getAccountName()); setAttributeOptional(statement, ++index, owner.getRefreshToken()); setAttribute(statement, ++index, owner.getScopes()); setAttribute(statement, ++index, owner.getStructuresNextUpdate()); setAttribute(statement, ++index, owner.getAccountNextUpdate()); setAttribute(statement, ++index, owner.getCallbackURL()); setAttribute(statement, ++index, owner.getRoles()); rows.addRow(); } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { String sql = "SELECT * FROM " + OWNERS_TABLE; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); String ownerName = getString(rs, "name"); String corporationName = getStringOptional(rs, "corp"); long ownerID = getLong(rs, "ownerid"); Date assetsNextUpdate = getDateNotNull(rs, "assetsnextupdate"); Date assetsLastUpdate = getDateOptional(rs, "assetslastupdate"); Date balanceNextUpdate = getDateNotNull(rs, "balancenextupdate"); Date balanceLastUpdate = getDateOptional(rs, "balancelastupdate"); boolean showOwner = getBooleanNotNull(rs, "show", true) ; boolean invalid = getBooleanNotNull(rs, "invalid", false); Date marketOrdersNextUpdate = getDateNotNull(rs, "marketordersnextupdate"); Date journalNextUpdate = getDateNotNull(rs, "journalnextupdate"); Date transactionsNextUpdate = getDateNotNull(rs, "transactionsnextupdate"); Date industryJobsNextUpdate = getDateNotNull(rs, "industryjobsnextupdate"); Date contractsNextUpdate = getDateNotNull(rs, "contractsnextupdate"); Date locationsNextUpdate = getDateNotNull(rs, "locationsnextupdate"); Date blueprintsNextUpdate = getDateNotNull(rs, "blueprintsnextupdate"); Date skillsNextUpdate = getDateNotNull(rs, "skillsnextupdate"); Date loyaltyPointsNextUpdate = getDateNotNull(rs, "loyaltypointsnextupdate"); Date npcStandingNextUpdate = getDateNotNull(rs, "npcstandingnextupdate"); Date miningNextUpdate = getDateNotNull(rs, "miningnextupdate"); String accountName = getString(rs, "accountname"); String refreshToken = getString(rs, "refreshtoken"); String scopes = getString(rs, "scopes"); Date structuresNextUpdate = getDate(rs, "structuresnextupdate"); Date accountNextUpdate = getDate(rs, "accountnextupdate"); EsiCallbackURL callbackURL; try { callbackURL = EsiCallbackURL.valueOf(getString(rs, "callbackurl")); } catch (IllegalArgumentException ex) { continue; } Set roles = EnumSet.noneOf(CharacterRolesResponse.RolesEnum.class); for (String role : getString(rs, "characterroles").split(",")) { try { roles.add(CharacterRolesResponse.RolesEnum.valueOf(role)); } catch (IllegalArgumentException ex) { } } EsiOwner owner = new EsiOwner(accountID); owner.setRoles(roles); owner.setAccountName(accountName); owner.setScopes(new HashSet<>(Arrays.asList(scopes.split(",")))); owner.setStructuresNextUpdate(structuresNextUpdate); owner.setAccountNextUpdate(accountNextUpdate); owner.setAuth(callbackURL, refreshToken, null); owner.setOwnerName(ownerName); owner.setCorporationName(corporationName); owner.setOwnerID(ownerID); owner.setAssetNextUpdate(assetsNextUpdate); owner.setAssetLastUpdate(assetsLastUpdate); owner.setBalanceNextUpdate(balanceNextUpdate); owner.setBalanceLastUpdate(balanceLastUpdate); owner.setShowOwner(showOwner); owner.setInvalid(invalid); owner.setMarketOrdersNextUpdate(marketOrdersNextUpdate); owner.setJournalNextUpdate(journalNextUpdate); owner.setTransactionsNextUpdate(transactionsNextUpdate); owner.setIndustryJobsNextUpdate(industryJobsNextUpdate); owner.setContractsNextUpdate(contractsNextUpdate); owner.setLocationsNextUpdate(locationsNextUpdate); owner.setBlueprintsNextUpdate(blueprintsNextUpdate); owner.setSkillsNextUpdate(skillsNextUpdate); owner.setLoyaltyPointsNextUpdate(loyaltyPointsNextUpdate); owner.setNpcStandingNextUpdate(npcStandingNextUpdate); owner.setMiningNextUpdate(miningNextUpdate); esiOwners.add(owner); } } } @Override protected void updateTable(Connection connection) throws SQLException { addColumn(connection, OWNERS_TABLE, "loyaltypointsnextupdate", "INTEGER"); addColumn(connection, OWNERS_TABLE, "npcstandingnextupdate", "INTEGER"); } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, OWNERS_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, OWNERS_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + OWNERS_TABLE + " (\n" + " accountid TEXT,\n" + " ownerid INTEGER,\n" + " name TEXT,\n" + " corp TEXT,\n" + " show NUMERIC,\n" + " invalid NUMERIC,\n" + " assetslastupdate INTEGER,\n" + " assetsnextupdate INTEGER,\n" + " balancelastupdate INTEGER,\n" + " balancenextupdate INTEGER,\n" + " marketordersnextupdate INTEGER,\n" + " journalnextupdate INTEGER,\n" + " transactionsnextupdate INTEGER,\n" + " industryjobsnextupdate INTEGER,\n" + " contractsnextupdate INTEGER,\n" + " locationsnextupdate INTEGER,\n" + " blueprintsnextupdate INTEGER,\n" + " skillsnextupdate INTEGER,\n" + " miningnextupdate INTEGER,\n" + " accountname TEXT,\n" + " refreshtoken TEXT,\n" + " scopes TEXT,\n" + " structuresnextupdate INTEGER,\n" + " accountnextupdate INTEGER,\n" + " loyaltypointsnextupdate INTEGER,\n" + " npcstandingnextupdate INTEGER,\n" + " callbackurl TEXT,\n" + " characterroles TEXT,\n" + " UNIQUE(accountid)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileSkills.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MySkill; import net.nikr.eve.jeveasset.data.api.raw.RawSkill; import net.nikr.eve.jeveasset.io.shared.DataConverter; public class ProfileSkills extends ProfileTable { private static final String SKILLS_TABLE = "skills"; private static final String SKILLS_TOTAL_TABLE = "skillstotal"; @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, SKILLS_TABLE, SKILLS_TOTAL_TABLE); //Insert data String skillsSQL = "INSERT OR REPLACE INTO " + SKILLS_TABLE + " (" + " accountid," + " id," + " sp," + " active," + " trained)" + " VALUES (?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(skillsSQL)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner esiOwner) { return esiOwner.getSkills().size(); } }); for (EsiOwner owner : esiOwners) { for (MySkill skill : owner.getSkills()) { int index = 0; setAttribute(statement, ++index, owner.getAccountID()); setAttribute(statement, ++index, skill.getTypeID()); setAttribute(statement, ++index, skill.getSkillpoints()); setAttribute(statement, ++index, skill.getActiveSkillLevel()); setAttribute(statement, ++index, skill.getTrainedSkillLevel()); rows.addRow(); } } } String totalSQL = "INSERT OR REPLACE INTO " + SKILLS_TOTAL_TABLE + " (" + " accountid," + " total," + " unallocated)" + " VALUES (?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(totalSQL)) { Rows rows = new Rows(statement, esiOwners.size()); for (EsiOwner owner : esiOwners) { int index = 0; setAttribute(statement, ++index, owner.getAccountID()); setAttributeOptional(statement, ++index, owner.getTotalSkillPoints()); setAttributeOptional(statement, ++index, owner.getUnallocatedSkillPoints()); rows.addRow(); } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { Map> accountBalances = new HashMap<>(); String skillsSQL = "SELECT * FROM " + SKILLS_TABLE; try (PreparedStatement statement = connection.prepareStatement(skillsSQL); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); int typeID = getInt(rs, "id"); long skillpoints = getLong(rs, "sp"); int activeSkillLevel = getInt(rs, "active"); int trainedSkillLevel = getInt(rs, "trained"); RawSkill skill = RawSkill.create(); skill.setTypeID(typeID); skill.setSkillpoints(skillpoints); skill.setActiveSkillLevel(activeSkillLevel); skill.setTrainedSkillLevel(trainedSkillLevel); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } list(owner, accountBalances, DataConverter.toMySkill(skill, owner)); } for (Map.Entry> entry : accountBalances.entrySet()) { entry.getKey().setSkills(entry.getValue()); } } String totalSQL = "SELECT * FROM " + SKILLS_TOTAL_TABLE; try (PreparedStatement statement = connection.prepareStatement(totalSQL); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); Integer unallocatedSkillPoints = getIntOptional(rs, "unallocated"); Long totalSkillPoints = getLongOptional(rs, "total"); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } owner.setTotalSkillPoints(totalSkillPoints); owner.setUnallocatedSkillPoints(unallocatedSkillPoints); } } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, SKILLS_TABLE, SKILLS_TOTAL_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, SKILLS_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + SKILLS_TABLE + " (\n" + " accountid TEXT,\n" + " id INTEGER," + " sp INTEGER," + " active INTEGER," + " trained INTEGER," + " UNIQUE(accountid, id)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } if (!tableExist(connection, SKILLS_TOTAL_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + SKILLS_TOTAL_TABLE + " (\n" + " accountid TEXT,\n" + " total INTEGER," + " unallocated INTEGER," + " UNIQUE(accountid)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileTable.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.awt.Color; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.io.local.AbstractXmlWriter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class ProfileTable { protected static final Logger LOG = LoggerFactory.getLogger(ProfileTable.class); private static final int BATCH_SIZE = 1000; protected abstract boolean isEmpty(Connection connection) throws SQLException; protected abstract void insert(Connection connection, final List esiOwners) throws SQLException; protected abstract void select(Connection connection, List esiOwners, Map owners) throws SQLException; protected abstract void create(Connection connection) throws SQLException; protected void updateTable(Connection connection) throws SQLException { } protected boolean isUpdated() { return false; } protected static boolean tableExist(Connection connection, String ... tableNames) throws SQLException { boolean ok = true; for (String tableName : tableNames) { String sql = "SELECT name FROM sqlite_master WHERE type='table' AND name='" + tableName + "'"; try (Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery(sql)) { ok = rs.next() && ok; } } return ok; } protected static void tableDelete(Connection connection, String ... tableNames) throws SQLException { for (String tableName : tableNames) { String sql = "DELETE FROM " + tableName; try (PreparedStatement statement = connection.prepareStatement(sql)) { statement.execute(); } } } private Set tableColumns(Connection connection, String tableName) throws SQLException { Set columns = new HashSet<>(); String sql = "SELECT name FROM pragma_table_info('" + tableName + "')"; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String columnName = getString(rs, "name"); columns.add(columnName); } } return columns; } protected void addColumn(Connection connection, String tableName, String columnName, String type) throws SQLException { Set tableColumns = tableColumns(connection, tableName); if (!tableColumns.contains(columnName)) { String sql = "ALTER TABLE " + tableName + " ADD COLUMN " + columnName + " " + type; try (PreparedStatement statement = connection.prepareStatement(sql)) { statement.execute(); } } } protected static void setAttributeNull(final PreparedStatement statement, final int index) throws SQLException { statement.setNull(index, Types.NULL); } protected static void setAttributeOptional(final PreparedStatement statement, final int index, final Color object) throws SQLException { if (object == null) { statement.setNull(index, Types.NULL); } else { statement.setInt(index, object.getRGB()); } } protected static void setAttributeOptional(final PreparedStatement statement, final int index, final String object) throws SQLException { if (object == null) { statement.setNull(index, Types.NULL); } else { statement.setString(index, object); } } protected static void setAttributeOptional(final PreparedStatement statement, final int index, final Collection object) throws SQLException { if (object == null) { statement.setNull(index, Types.NULL); } else { List list = new ArrayList<>(); for (Object t : object) { list.add(AbstractXmlWriter.valueOf(t)); } statement.setString(index, String.join(",", list)); } } protected static void setAttributeOptional(final PreparedStatement statement, final int index, final Date object) throws SQLException { if (object == null) { statement.setNull(index, Types.NULL); } else { statement.setLong(index, object.getTime()); } } protected static void setAttributeOptional(final PreparedStatement statement, final int index, final Enum object) throws SQLException { if (object == null) { statement.setNull(index, Types.NULL); } else { statement.setString(index, object.name()); } } protected static void setAttributeOptional(final PreparedStatement statement, final int index, final Boolean object) throws SQLException { if (object == null) { statement.setNull(index, Types.NULL); } else { statement.setBoolean(index, object); } } protected static void setAttributeOptional(final PreparedStatement statement, final int index, final Integer object) throws SQLException { if (object == null) { statement.setNull(index, Types.NULL); } else { statement.setInt(index, object); } } protected static void setAttributeOptional(final PreparedStatement statement, final int index, final Long object) throws SQLException { if (object == null) { statement.setNull(index, Types.NULL); } else { statement.setLong(index, object); } } protected static void setAttributeOptional(final PreparedStatement statement, final int index, final Float object) throws SQLException { if (object == null) { statement.setNull(index, Types.NULL); } else { statement.setFloat(index, object); } } protected static void setAttributeOptional(final PreparedStatement statement, final int index, final Double object) throws SQLException { if (object == null) { statement.setNull(index, Types.NULL); } else { statement.setDouble(index, object); } } protected static void setAttributeOptional(final PreparedStatement statement, final int index, final Object object) throws SQLException { if (object == null) { statement.setNull(index, Types.NULL); } else { statement.setString(index, String.valueOf(object)); } } protected static void setAttribute(final PreparedStatement statement, final int index, final Color object) throws SQLException { notNull(object); statement.setInt(index, object.getRGB()); } protected static void setAttribute(final PreparedStatement statement, final int index, final String object) throws SQLException { notNull(object); statement.setString(index, object); } protected static void setAttribute(final PreparedStatement statement, final int index, final Collection object) throws SQLException { notNull(object); List list = new ArrayList<>(); for (Object t : object) { list.add(AbstractXmlWriter.valueOf(t)); } statement.setString(index, String.join(",", list)); } protected static void setAttribute(final PreparedStatement statement, final int index, final Date object) throws SQLException { notNull(object); statement.setLong(index, object.getTime()); } protected static void setAttribute(final PreparedStatement statement, final int index, final Enum object) throws SQLException { notNull(object); statement.setString(index, object.name()); } protected static void setAttribute(final PreparedStatement statement, final int index, final Boolean object) throws SQLException { notNull(object); statement.setBoolean(index, object); } protected static void setAttribute(final PreparedStatement statement, final int index, final Integer object) throws SQLException { notNull(object); statement.setInt(index, object); } protected static void setAttribute(final PreparedStatement statement, final int index, final Long object) throws SQLException { notNull(object); statement.setLong(index, object); } protected static void setAttribute(final PreparedStatement statement, final int index, final Float object) throws SQLException { notNull(object); statement.setFloat(index, object); } protected static void setAttribute(final PreparedStatement statement, final int index, final Double object) throws SQLException { notNull(object); statement.setDouble(index, object); } protected static void setAttribute(final PreparedStatement statement, final int index, final Object object) throws SQLException { notNull(object); statement.setString(index, String.valueOf(object)); } private static void notNull(final Object object) { if (object == null) { throw new RuntimeException("Can't save null"); } } protected Date getDateNotNull(ResultSet rs, String columnLabel) throws SQLException { long time = rs.getLong(columnLabel); if (rs.wasNull()) { return Settings.getNow(); } else { return new Date(time); } } protected long getLong(ResultSet rs, String columnLabel) throws SQLException { return rs.getLong(columnLabel); } protected String getString(ResultSet rs, String columnLabel) throws SQLException { return rs.getString(columnLabel); } protected Date getDateOptional(ResultSet rs, String columnLabel) throws SQLException { long time = rs.getLong(columnLabel); if (rs.wasNull()) { return null; } else { return new Date(time); } } protected boolean getBooleanNotNull(ResultSet rs, String columnLabel, boolean defaultValue) throws SQLException { boolean value = rs.getBoolean(columnLabel); if (rs.wasNull()) { return defaultValue; } else { return value; } } protected String getStringOptional(ResultSet rs, String columnLabel) throws SQLException { String value = rs.getString(columnLabel); if (rs.wasNull()) { return null; } else { return value; } } protected String getStringNotNull(ResultSet rs, String columnLabel, String defaultValue) throws SQLException { String value = rs.getString(columnLabel); if (rs.wasNull()) { return defaultValue; } else { return value; } } protected Date getDate(ResultSet rs, String columnLabel) throws SQLException { return new Date(rs.getLong(columnLabel)); } protected int getInt(ResultSet rs, String columnLabel) throws SQLException { return rs.getInt(columnLabel); } protected boolean getBoolean(ResultSet rs, String columnLabel) throws SQLException { return rs.getBoolean(columnLabel); } protected Integer getIntOptional(ResultSet rs, String columnLabel) throws SQLException { int value = rs.getInt(columnLabel); if (rs.wasNull()) { return null; } else { return value; } } protected Long getLongOptional(ResultSet rs, String columnLabel) throws SQLException { long value = rs.getLong(columnLabel); if (rs.wasNull()) { return null; } else { return value; } } protected long getLongNotNull(ResultSet rs, String columnLabel, long defaultValue) throws SQLException { long value = rs.getLong(columnLabel); if (rs.wasNull()) { return defaultValue; } else { return value; } } protected int getIntNotNull(ResultSet rs, String columnLabel, int defaultValue) throws SQLException { int value = rs.getInt(columnLabel); if (rs.wasNull()) { return defaultValue; } else { return value; } } protected Double getDoubleOptional(ResultSet rs, String columnLabel) throws SQLException { double value = rs.getDouble(columnLabel); if (rs.wasNull()) { return null; } else { return value; } } protected Float getFloatOptional(ResultSet rs, String columnLabel) throws SQLException { float value = rs.getFloat(columnLabel); if (rs.wasNull()) { return null; } else { return value; } } protected Float getFloat(ResultSet rs, String columnLabel) throws SQLException { return rs.getFloat(columnLabel); } protected double getDouble(ResultSet rs, String columnLabel) throws SQLException { return rs.getDouble(columnLabel); } protected void set(EsiOwner owner, Map> map, T value) { Set set = map.get(owner); if (set == null) { set = new HashSet<>(); map.put(owner, set); } set.add(value); } protected void list(EsiOwner owner, Map> map, T value) { List list = map.get(owner); if (list == null) { list = new ArrayList<>(); map.put(owner, list); } list.add(value); } protected void map(EsiOwner owner, Map> map, K key, T value) { Map hmm = map.get(owner); if (hmm == null) { hmm = new HashMap<>(); map.put(owner, hmm); } hmm.put(key, value); } protected static interface RowSize { public int getSize(E owner); } public static class Rows { private final int size; private final PreparedStatement statement; int row = 0; public Rows(PreparedStatement statement, Collection esiOwners, RowSize rowSize) { this.statement = statement; int tempSize = 0; for (E esiOwner : esiOwners) { tempSize += rowSize.getSize(esiOwner); } this.size = tempSize; } public Rows(PreparedStatement statement, int size) { this.statement = statement; this.size = size; } public void addRow() throws SQLException { statement.addBatch(); row++; if (row % BATCH_SIZE == 0 || row == size) { statement.executeBatch(); // Execute batch for every BATCH_SIZE items. } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileTransactions.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.api.raw.RawTransaction; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.io.shared.DataConverter; import net.nikr.eve.jeveasset.io.shared.RawConverter; public class ProfileTransactions extends ProfileTable { private static final String TRANSACTIONS_TABLE = "transactions"; @Override protected boolean isUpdated() { return Settings.get().isTransactionHistory(); } private static void set(PreparedStatement statement, MyTransaction transaction, String accountID) throws SQLException { int index = 0; setAttribute(statement, ++index, accountID); setAttribute(statement, ++index, transaction.getDate()); setAttribute(statement, ++index, transaction.getTransactionID()); setAttribute(statement, ++index, transaction.getQuantity()); setAttribute(statement, ++index, transaction.getTypeID()); setAttribute(statement, ++index, transaction.getPrice()); setAttribute(statement, ++index, transaction.getClientID()); setAttribute(statement, ++index, transaction.getLocationID()); setAttribute(statement, ++index, RawConverter.fromTransactionIsBuy(transaction.isBuy())); setAttribute(statement, ++index, RawConverter.fromTransactionIsPersonal(transaction.isPersonal())); //New setAttribute(statement, ++index, transaction.getTransactionID()); setAttribute(statement, ++index, transaction.getClientID()); //Extra setAttribute(statement, ++index, transaction.getAccountKey()); } /** * Transactions are immutable (IGNORE) * @param connection * @param accountID * @param transactions * @throws java.sql.SQLException */ public static void updateTransactions(Connection connection, String accountID, Collection transactions) throws SQLException { //Tables exist if (!tableExist(connection, TRANSACTIONS_TABLE)) { return; } //Insert data String sql = "INSERT OR IGNORE INTO " + TRANSACTIONS_TABLE + " (" + " accountid," + " transactiondatetime," + " transactionid," + " quantity," + " typeid," + " price," + " clientid," + " stationid," + " transactiontype," + " transactionfor," + " journaltransactionid," + " clienttypeid," + " accountkey)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, transactions.size()); for (MyTransaction transaction : transactions) { set(statement, transaction, accountID); rows.addRow(); } } } @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, TRANSACTIONS_TABLE); //Insert data String sql = "INSERT INTO " + TRANSACTIONS_TABLE + " (" + " accountid," + " transactiondatetime," + " transactionid," + " quantity," + " typeid," + " price," + " clientid," + " stationid," + " transactiontype," + " transactionfor," + " journaltransactionid," + " clienttypeid," + " accountkey)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner owner) { return owner.getTransactions().size(); } }); for (EsiOwner owner : esiOwners) { for (MyTransaction transaction : owner.getTransactions()) { set(statement, transaction, owner.getAccountID()); rows.addRow(); } } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { Map> transactions = new HashMap<>(); String sql = "SELECT * FROM " + TRANSACTIONS_TABLE; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); RawTransaction rawTransaction = RawTransaction.create(); Date date = getDate(rs, "transactiondatetime"); long transactionID = getLong(rs, "transactionid"); int quantity = getInt(rs, "quantity"); int typeID = getInt(rs, "typeid"); double price = getDouble(rs, "price"); int clientID = getInt(rs, "clientid"); long locationID = getLong(rs, "stationid"); String transactionType = getString(rs, "transactiontype"); String transactionFor = getString(rs, "transactionfor"); //New long journalRefID = getLongNotNull(rs, "journaltransactionid", 0L); //Extra int accountKey = getIntNotNull(rs, "accountkey", 1000); rawTransaction.setClientID(clientID); rawTransaction.setDate(date); rawTransaction.setBuy(RawConverter.toTransactionIsBuy(transactionType)); rawTransaction.setPersonal(RawConverter.toTransactionIsPersonal(transactionFor)); rawTransaction.setJournalRefID(journalRefID); rawTransaction.setLocationID(locationID); rawTransaction.setQuantity(quantity); rawTransaction.setTransactionID(transactionID); rawTransaction.setTypeID(typeID); rawTransaction.setUnitPrice(price); rawTransaction.setAccountKey(accountKey); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } set(owner, transactions, DataConverter.toMyTransaction(rawTransaction, owner)); } for (Map.Entry> entry : transactions.entrySet()) { entry.getKey().setTransactions(entry.getValue()); } } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, TRANSACTIONS_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, TRANSACTIONS_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + TRANSACTIONS_TABLE + " (\n" + " accountid TEXT,\n" + " transactiondatetime INTEGER," + " transactionid INTEGER," + " quantity INTEGER," + " typeid INTEGER," + " price REAL," + " clientid INTEGER," + " stationid INTEGER," + " transactiontype TEXT," + " transactionfor TEXT," + " journaltransactionid INTEGER," + " clienttypeid INTEGER," + " accountkey INTEGER," + " UNIQUE(accountid, transactionid, price)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/profile/ProfileWalletDivisions.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.profile; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; public class ProfileWalletDivisions extends ProfileTable { private static final String WALLET_DIVISIONS_TABLE = "walletdivisions"; @Override protected void insert(Connection connection, List esiOwners) throws SQLException { //Delete all data tableDelete(connection, WALLET_DIVISIONS_TABLE); //Insert data String sql = "INSERT INTO " + WALLET_DIVISIONS_TABLE + " (" + " accountid," + " id," + " name)" + " VALUES (?,?,?)"; try (PreparedStatement statement = connection.prepareStatement(sql)) { Rows rows = new Rows(statement, esiOwners, new RowSize() { @Override public int getSize(EsiOwner esiOwner) { return esiOwner.getWalletDivisions().size(); } }); for (EsiOwner owner : esiOwners) { for (Map.Entry entry : owner.getWalletDivisions().entrySet()) { int index = 0; setAttribute(statement, ++index, owner.getAccountID()); setAttribute(statement, ++index, entry.getKey()); setAttributeOptional(statement, ++index, entry.getValue()); rows.addRow(); } } } } @Override protected void select(Connection connection, List esiOwners, Map owners) throws SQLException { Map> divisions = new HashMap<>(); String sql = "SELECT * FROM " + WALLET_DIVISIONS_TABLE; try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rs = statement.executeQuery();) { while (rs.next()) { String accountID = getString(rs, "accountid"); int id = getInt(rs, "id"); String name = getStringOptional(rs, "name"); EsiOwner owner = owners.get(accountID); if (owner == null) { continue; } map(owner, divisions, id, name); } for (Map.Entry> entry : divisions.entrySet()) { entry.getKey().setWalletDivisions(entry.getValue()); } } } @Override protected boolean isEmpty(Connection connection) throws SQLException { return !tableExist(connection, WALLET_DIVISIONS_TABLE); } @Override protected void create(Connection connection) throws SQLException { if (!tableExist(connection, WALLET_DIVISIONS_TABLE)) { String sql = "CREATE TABLE IF NOT EXISTS " + WALLET_DIVISIONS_TABLE + " (\n" + " accountid TEXT,\n" + " id INTEGER," + " name TEXT," + " UNIQUE(accountid, id)\n" + ");"; try (Statement statement = connection.createStatement()) { statement.execute(sql); } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/text/AbstractTextImport.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.text; import java.util.HashMap; import java.util.Map; import javax.swing.Icon; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; public abstract class AbstractTextImport { private String name = ""; public Map importText(String text) { Map input = doImport(text); if (input == null) { return null; } Map lookup = new HashMap<>(); for (Item item : StaticData.get().getItems().values()) { lookup.put(item.getTypeName().toLowerCase(), item.getTypeID()); } Map data = new HashMap<>(); for (Map.Entry entry : input.entrySet()) { Integer typeID = lookup.get(entry.getKey().toLowerCase()); if (typeID != null) { data.put(typeID, entry.getValue()); } } return data; } protected abstract Map doImport(String data); public abstract String getExample(); public abstract Icon getIcon(); public abstract String getType(); public String getName() { return name; } protected void setName(String name) { this.name = name; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/text/ImportEft.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.text; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.Icon; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.i18n.GuiShared; public class ImportEft extends AbstractTextImport { protected ImportEft() { } @Override public String getExample() { return "[Rifter, Rifter alpha]\n" + "\n" + "200mm AutoCannon I\n" + "200mm AutoCannon I\n" + "200mm AutoCannon I\n" + "\n" + "1MN Afterburner I\n" + "Stasis Webifier I\n" + "Small Capacitor Booster I\n" + "\n" + "Gyrostabilizer I\n" + "Small Armor Repairer I\n" + "Damage Control I\n" + "\n" + "Small Projectile Collision Accelerator I\n" + "Small Projectile Burst Aerator I\n" + "\n" + "Cap Booster 200 x11\n" + "Fusion S x2360" ; } @Override public Icon getIcon() { return Images.TOOL_SHIP_LOADOUTS.getIcon(); } @Override public String getType() { return GuiShared.get().importEft(); } @Override protected Map doImport(String data) { //Format and split List modules = new ArrayList<>(Arrays.asList(data.split("[\r\n]+"))); if (modules.isEmpty()) { return null; //Malformed } if (!modules.get(0).startsWith("[") || !modules.get(0).contains(",") || !modules.get(0).endsWith("]")) { return null;//Malformed } //Get name of fit String[] first = modules.remove(0).split(","); if (first.length != 2) { return null; //Malformed } String ship = first[0].replace("[", "").replace("]", "").trim(); String name = first[1].replace("[", "").replace("]", "").trim(); modules.add(0, ship); setName(name); Map typeNames = new HashMap<>(); for (Item item : StaticData.get().getItems().values()) { typeNames.put(item.getTypeName(), item); } //Add modules Map items = new HashMap<>(); for (String line : modules) { line = line.trim(); //Format line if (line.startsWith("[")) { continue; } double count = getNumber(line); String module = line.replaceAll("x\\d+$", "").trim(); if (typeNames.containsKey(module)) { add(items, module, count); } else if (line.contains(",")) { //Handle module and charge on the same line int index = line.lastIndexOf(","); //Charge is always after the last , if (index > 0 && index + 1 < line.length()) { //Module module = line.substring(0, index).trim(); //Get module part of the line count = getNumber(module); //count module = module.replaceAll("x\\d+$", "").trim(); //Remove number Item moduleItem = typeNames.get(module); if (moduleItem != null) { //module exist add(items, module, count); } //Charge String charge = line.substring(index + 1).trim(); //Get the charge part of the line Item chargeItem = typeNames.get(charge); if (chargeItem != null && moduleItem != null) { //charge exist double chargeCount = Math.floor(moduleItem.getCapacity() / chargeItem.getVolume()); add(items, charge, chargeCount); } } } } return items; } private void add(final Map items, final String module, final double count) { if (module.isEmpty()) { //Skip empty lines return; } //Search for item name Double d = items.get(module); if (d == null) { d = 0.0; } items.put(module, count + d); } private double getNumber(String line) { //Find x[Number] - used for drones and cargo Pattern p = Pattern.compile("x\\d+$"); Matcher m = p.matcher(line); double count = 0; while (m.find()) { String group = m.group().replace("x", ""); count = count + Long.valueOf(group); } if (count == 0) { count = 1; } return count; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/text/ImportEveMultibuy.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.text; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.Icon; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.i18n.GuiShared; public class ImportEveMultibuy extends AbstractTextImport { protected ImportEveMultibuy() { } @Override public String getExample() { return "Supported formats:\n" + "\n" + "\n" + "Hammerhead II 10 1.189.997,05 11.899.970,50\n" + "\n" + "x\n" + "Veldspar x10\n" + "\n" + "\n" + "10 Veldspar\n" + "\n" + "x\n" + "x10 Veldspar\n" ; } @Override public Icon getIcon() { return Images.MISC_EVE.getIcon(); } @Override public String getType() { return GuiShared.get().importEveMultibuy(); } @Override protected Map doImport(String data) { List lines = new ArrayList<>(Arrays.asList(data.split("[\r\n]+"))); Map items = new HashMap<>(); for (String line : lines) { String[] values = line.split("[\\s]"); if (values.length < 2) { continue; } int countIndex = findCountIndex(values); if (countIndex == -1) { continue; } String countStr = values[countIndex]; if (countStr.startsWith("x")) { countStr = countStr.substring(1); } double count; try { count = Integer.parseInt(countStr); } catch (NumberFormatException ex) { continue; } String item; if (countIndex == 0) { //leading count item = String.join(" ", Arrays.copyOfRange(values, 1, values.length)); } else { //trailing count item = String.join(" ", Arrays.copyOfRange(values, 0, countIndex)); } //Search for item name Double d = items.get(item); if (d == null) { d = 0.0; } items.put(item, count + d); } return items; } private int findCountIndex(String[] values) { // The idea here is to look through first and last 3 values we got and find first one which consists only of // digits or x and digits // It is safe to assume that found value corresponds to item count because it can't be part of item name String itemCountRegex = "^x?(\\d+)$"; int n = values.length; for (int i = n - 3; i < n; ++i) { if (i <= 0) { continue; } if (values[i].matches(itemCountRegex)) { return i; } } if (values[0].matches(itemCountRegex)) { return 0; } return -1; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/text/ImportIskPerHour.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.text; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; import javax.swing.Icon; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.i18n.GuiShared; public class ImportIskPerHour extends AbstractTextImport { private static final Integer MATERIAL = 0; private static final Integer QUANTITY = 1; protected ImportIskPerHour() { } @Override public String getExample() { return "Supported formats:\n" + "\n" //Default + " - \n" + "10000MN Afterburner I (ME: 0, NumBPs: 1) - 1\n" + "\n" //EveList + "\n" + "Tritanium 2932280\n" + "\n" //Csv | + "\n" + "||\n" + "Material|Quantity|Cost Per Item|Min Sell|Max Buy|Buy Type|Total m3|Isk/m3|TotalCost\n" + "Tritanium|2932280.00|0.00|0.00|0.00|Unknown|29322.80|0.00|0.00\n" + "\n" //Csv , + "\n" + ",,\n" + "Material, Quantity, Cost Per Item, Total Cost, Location\n" + "Tritanium, 2932280, 2, 5864560\n" + "\n" //Csv ; + "\n" + ";;\n" + "Material; Quantity; Cost Per Item; Total Cost; Location\n" + "Tritanium; 2932280; 2; 5864560\n" ; } @Override public Icon getIcon() { return Images.TOOL_VALUES.getIcon(); } @Override public String getType() { return GuiShared.get().importIskPerHour(); } @Override protected Map doImport(String text) { //Get lines: String[] lines = text.split("[\r\n]+"); //Find format boolean defaultCopy = text.contains("Material - Quantity"); boolean defaultFile = text.contains("Material|"); boolean csv = text.contains("Material,"); boolean ssv = text.contains("Material;"); if (defaultCopy) { return processDefaultCopy(lines); } else if (defaultFile) { return processCsv(lines, "\\|", false); } else if (csv) { return processCsv(lines, ",", false); } else if (ssv) { return processCsv(lines, ";", true); } else { //Eve List return processEveList(lines); } } private Map processDefaultCopy(String[] lines) { Map data = new HashMap<>(); for (String line : lines) { if (line.trim().isEmpty() || (line.contains(":") && !line.contains(" (") && !line.contains(") ")) || line.contains("Material - Quantity")) { continue; } int end = line.lastIndexOf(" - "); if (end < 0) { return null; } String name = line.substring(0, end); name = name.replaceAll("\\([^\\)]+\\)", "").trim(); String number = line.substring(end + 3).trim().replace(",", ""); double d; try { d = Double.valueOf(number); } catch (NumberFormatException ex) { return null; } Double dd = data.get(name); if (dd != null) { d = d + dd; } data.put(name, d); } return data; } private Map processCsv(String[] lines, String separator, boolean decimalComma) { Map data = new HashMap<>(); for (String line : lines) { if (line.trim().isEmpty() || line.contains(":") || !Pattern.compile(separator).matcher(line).find() || line.startsWith("Material") || line.startsWith("Item") || line.startsWith("Build Item")) { continue; } String[] values = line.split(separator); String name = values[MATERIAL].trim(); String number = values[QUANTITY].trim(); if (decimalComma) { number = number.replace(".", "").replace(",", "."); } double d; try { d = Double.valueOf(number); } catch (NumberFormatException ex) { return null; } Double dd = data.get(name); if (dd != null) { d = d + dd; } data.put(name, d); } return data; } private Map processEveList(String[] lines) { Map data = new HashMap<>(); for (String line : lines) { if (line.trim().isEmpty()) { continue; } int end = line.lastIndexOf(" "); if (end < 0) { return null; } String name = line.substring(0, end); String number = line.substring(end + 1); double d; try { d = Double.valueOf(number); } catch (NumberFormatException ex) { return null; } Double dd = data.get(name); if (dd != null) { d = d + dd; } data.put(name, d); } return data; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/text/ImportShoppingList.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.text; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.Icon; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.i18n.GuiShared; public class ImportShoppingList extends AbstractTextImport { protected ImportShoppingList() { } @Override public String getExample() { return "Stockpiles:\n" + "1x Rifter alpha\n" + "\n" + "Items:\n" + "3x 200mm AutoCannon I\n" + "1x Small Projectile Collision Accelerator I\n" + "1x Gyrostabilizer I\n" + "1x Small Projectile Burst Aerator I\n" + "1x Small Armor Repairer I\n" + "1x Rifter\n" + "1x Stasis Webifier I\n" + "1x Small Capacitor Booster I\n" + "1x Damage Control I\n" + "11x Cap Booster 200\n" + "2.360x Fusion S\n" + "1x 1MN Afterburner I\n" + "\n" + "Total m3 to be hauled: 2.648,90\n" + "Estimated market value: 256.613,00 isk" ; } @Override public Icon getIcon() { return Images.STOCKPILE_SHOPPING_LIST.getIcon(); } @Override public String getType() { return GuiShared.get().importStockpilesShoppingList(); } @Override protected Map doImport(String data) { List lines = new ArrayList<>(Arrays.asList(data.split("[\r\n]+"))); Map items = new HashMap<>(); if (!lines.isEmpty()) { setName(lines.get(0)); } for (String line : lines) { if (!Character.isDigit(line.charAt(0))) { continue; } Pattern p = Pattern.compile("^\\d+x"); Matcher m = p.matcher(line); double count = 0; while (m.find()) { String group = m.group().replace("x", ""); count = count + Long.valueOf(group); } if (count == 0) { count = 1; } String module = line.replaceAll("^\\d+x", "").trim(); if (module.isEmpty()) { //Skip empty lines continue; } //Search for item name Double d = items.get(module); if (d == null) { d = 0.0; } items.put(module, count + d); } return items; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/text/TextImportType.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.text; import java.util.Map; import javax.swing.Icon; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog.SimpleTextImport; public enum TextImportType implements SimpleTextImport { EVE_MULTIBUY(new ImportEveMultibuy()), EFT(new ImportEft()), STCOKPILE_SHOPPING_LIST(new ImportShoppingList()), ISK_PER_HOUR(new ImportIskPerHour()); private final AbstractTextImport textImport; private TextImportType(AbstractTextImport textImport) { this.textImport = textImport; } @Override public String getExample() { return textImport.getExample(); } @Override public Icon getIcon() { return textImport.getIcon(); } @Override public String getType() { return textImport.getType(); } public String getName() { return textImport.getName(); } public Map importText(String text) { return textImport.importText(text); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/update/LocalUpdate.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.update; import net.nikr.eve.jeveasset.io.local.XmlException; /** * * @author Candle */ public interface LocalUpdate { void performUpdate(String path) throws XmlException; int getStart(); int getEnd(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/update/Update.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.update; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.List; import net.nikr.eve.jeveasset.io.local.AbstractXmlReader; import net.nikr.eve.jeveasset.io.local.FileLock.SafeFileIO; import net.nikr.eve.jeveasset.io.local.SettingsReader; import net.nikr.eve.jeveasset.io.local.XmlException; import net.nikr.eve.jeveasset.io.local.update.updates.Update1To2; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.XPath; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; import org.dom4j.tree.DefaultAttribute; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Node; /** * * @author Candle */ public class Update extends AbstractXmlReader { private static final Logger LOG = LoggerFactory.getLogger(Update.class); @Override protected Integer parse(org.w3c.dom.Element element) throws XmlException { if (element.getNodeName().equals("settings")) { if (haveAttribute((Node) element, "version")) { return getInt((Node) element, "version"); } } else { throw new XmlException("Wrong root element name."); } return 1; } @Override protected Integer failValue() { return 1; } @Override protected Integer doNotExistValue() { return SettingsReader.SETTINGS_VERSION; } void setVersion(final File xml, final int newVersion) throws DocumentException { try (SafeFileIO io = new SafeFileIO(xml)){ SAXReader xmlReader = new SAXReader(); Document doc = xmlReader.read(io.getFileInputStream()); XPath xpathSelector = DocumentHelper.createXPath("/settings"); List results = xpathSelector.selectNodes(doc); for (Iterator iter = results.iterator(); iter.hasNext();) { Element element = (Element) iter.next(); Attribute attr = element.attribute("version"); if (attr == null) { element.add(new DefaultAttribute("version", String.valueOf(newVersion))); } else { attr.setText(String.valueOf(newVersion)); } } OutputFormat outformat = OutputFormat.createPrettyPrint(); outformat.setEncoding("UTF-16"); XMLWriter writer = new XMLWriter(io.getFileOutputStream(), outformat); writer.write(doc); writer.flush(); } catch (IOException ioe) { LOG.error("Failed to update the serttings.xml version number", ioe); throw new RuntimeException(ioe); } } /** * TODO When more updates are added convert this to a graph-based * search for a suitable list of updates and then perform the updates * in the correct order. - Candle 2010-09-19 * @param requiredVersion current version * @param path settings path * @throws net.nikr.eve.jeveasset.io.local.XmlException on any error */ public void performUpdates(final int requiredVersion, final String path) throws XmlException { File xml = new File(path); if (!xml.exists()) { LOG.info("No settings.xml file found - nothing to update"); return; } try { int currentVersion = read("update settings", path, AbstractXmlReader.XmlType.DYNAMIC); if (requiredVersion > currentVersion) { LOG.info("settings.xml are out of date, updating."); Update1To2 update = new Update1To2(); update.performUpdate(path); setVersion(new File(path), requiredVersion); } else { LOG.info("settings.xml are up to date."); } } catch (DocumentException ex) { LOG.warn("Failed to update settings", ex); throw new XmlException(ex); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/local/update/updates/Update1To2.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.update.updates; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings.PriceMode; import net.nikr.eve.jeveasset.io.local.FileLock.SafeFileIO; import net.nikr.eve.jeveasset.io.local.XmlException; import net.nikr.eve.jeveasset.io.local.update.LocalUpdate; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.XPath; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Simple script to modify the settings, changing the. * * * @author Candle */ public class Update1To2 implements LocalUpdate { private static final Logger LOG = LoggerFactory.getLogger(Update1To2.class); @Override public void performUpdate(final String path) throws XmlException { LOG.info("Performing update from v1 to v2"); LOG.info(" - modifies files:"); LOG.info(" - settings.xml"); try (SafeFileIO io = new SafeFileIO(path)){ // We need to update the settings // current changes are: // 1. XPath: /settings/filters/filter/row[@mode] // changed from (e.g.) "Contains" to the enum value name in AssetFilter.Mode // 2. settings/marketstat[@defaultprice] --> another enum: Asset.PriceMode // 3. settings/columns/column --> settings/tables/table/column // settings/flags/flag --> removed two flags (now in settings/tables/table) SAXReader xmlReader = new SAXReader(); Document doc = xmlReader.read(io.getFileInputStream()); convertDefaultPriceModes(doc); convertModes(doc); convertTableSettings(doc); OutputFormat outformat = OutputFormat.createPrettyPrint(); outformat.setEncoding("UTF-16"); XMLWriter writer = new XMLWriter(io.getFileOutputStream(), outformat); writer.write(doc); writer.flush(); } catch (IOException ex) { LOG.error("", ex); throw new XmlException(ex); } catch (DocumentException ex) { LOG.error("", ex); throw new XmlException(ex); } } private void convertModes(final Document doc) { XPath xpathSelector = DocumentHelper.createXPath("/settings/filters/filter/row"); List results = xpathSelector.selectNodes(doc); for (Iterator iter = results.iterator(); iter.hasNext();) { Element elem = (Element) iter.next(); Attribute attr = elem.attribute("mode"); String currentValue = attr.getText(); attr.setText(convertMode(currentValue)); } } private void convertDefaultPriceModes(final Document doc) { XPath xpathSelector = DocumentHelper.createXPath("/settings/marketstat"); List results = xpathSelector.selectNodes(doc); for (Iterator iter = results.iterator(); iter.hasNext();) { Element elem = (Element) iter.next(); Attribute attr = elem.attribute("defaultprice"); if (attr != null) { //May not exist (in early versions) String currentValue = attr.getText(); attr.setText(convertDefaultPriceMode(currentValue)); } } } private void convertTableSettings(final Document doc) { XPath xpathSelector = DocumentHelper.createXPath("/settings/columns/column"); List results = xpathSelector.selectNodes(doc); List tableColumnNames = new ArrayList<>(); List tableColumnVisible = new ArrayList<>(); for (Iterator iter = results.iterator(); iter.hasNext();) { Element element = (Element) iter.next(); Attribute name = element.attribute("name"); Attribute visible = element.attribute("visible"); tableColumnNames.add(name.getText()); if (visible.getText().equals("true")) { tableColumnVisible.add(name.getText()); } } String mode = convertFlag(doc); writeTableSettings(doc, mode, tableColumnNames, tableColumnVisible); } private String convertDefaultPriceMode(final String oldVal) { if (oldVal.startsWith("PRICE_")) { return oldVal; } String convert = oldVal.toLowerCase(); if (convert.contains("midpoint")) { return PriceMode.PRICE_MIDPOINT.name(); } if (convert.contains("sell average")) { return PriceMode.PRICE_SELL_AVG.name(); } if (convert.contains("sell median")) { return PriceMode.PRICE_SELL_MEDIAN.name(); } if (convert.contains("sell minimum")) { return PriceMode.PRICE_SELL_MIN.name(); } if (convert.contains("sell maximum")) { return PriceMode.PRICE_SELL_MAX.name(); } if (convert.contains("buy maximum")) { return PriceMode.PRICE_BUY_MAX.name(); } if (convert.contains("buy average")) { return PriceMode.PRICE_BUY_AVG.name(); } if (convert.contains("buy median")) { return PriceMode.PRICE_BUY_MEDIAN.name(); } if (convert.contains("buy minimum")) { return PriceMode.PRICE_BUY_MIN.name(); } throw new IllegalArgumentException("Failed to convert the price type " + oldVal); } private String convertMode(final String oldVal) { if (oldVal.startsWith("MODE_")) { return oldVal; } String convert = oldVal.toLowerCase(); convert = convert.toLowerCase(); if (convert.contains("equals")) { return "MODE_EQUALS"; } if (convert.contains("contains")) { return "MODE_CONTAIN"; } if (convert.contains("does not contain")) { return "MODE_CONTAIN_NOT"; } if (convert.contains("does not equal")) { return "MODE_EQUALS_NOT"; } if (convert.contains("greater than")) { return "MODE_GREATER_THAN"; } if (convert.contains("less than")) { return "MODE_LESS_THAN"; } if (convert.contains("greater than column")) { return "MODE_GREATER_THAN_COLUMN"; } if (convert.contains("less than column")) { return "MODE_LESS_THAN_COLUMN"; } throw new IllegalArgumentException("Failed to convert the mode type " + oldVal); } private String convertFlag(final Document doc) { XPath flagSelector = DocumentHelper.createXPath("/settings/flags/flag"); List flagResults = flagSelector.selectNodes(doc); boolean text = false; boolean window = false; for (Iterator iter = flagResults.iterator(); iter.hasNext();) { Element element = (Element) iter.next(); Attribute key = element.attribute("key"); Attribute visible = element.attribute("enabled"); if (key.getText().equals("FLAG_AUTO_RESIZE_COLUMNS_TEXT")) { text = visible.getText().equals("true"); element.detach(); } if (key.getText().equals("FLAG_AUTO_RESIZE_COLUMNS_WINDOW")) { window = visible.getText().equals("true"); element.detach(); } } if (text) { return "TEXT"; } if (window) { return "WINDOW"; } return "NONE"; } private void writeTableSettings(final Document doc, final String mode, final List tableColumnNames, final List tableColumnVisible) { Element tables = doc.getRootElement().addElement("tables"); Element table = tables.addElement("table"); table.addAttribute("name", "COLUMN_SETTINGS_ASSETS"); table.addAttribute("resize", mode); for (String columnName : tableColumnNames) { Element column = table.addElement("column"); column.addAttribute("name", columnName); column.addAttribute("visible", String.valueOf(tableColumnVisible.contains(columnName))); } } @Override public int getStart() { return 1; } @Override public int getEnd() { return 2; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/online/CitadelGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.online; import java.util.Collection; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.settings.Citadel; import net.nikr.eve.jeveasset.data.settings.CitadelSettings; import net.nikr.eve.jeveasset.io.local.CitadelReader; import net.nikr.eve.jeveasset.io.local.CitadelWriter; public class CitadelGetter { private static CitadelGetter citadelGetter; private CitadelSettings citadelSettings = new CitadelSettings(); protected CitadelGetter() { } public synchronized static Citadel get(long locationID) { return getCitadelGetter().getCitadel(locationID); } public synchronized static Iterable> getAll() { return getCitadelGetter().getCitadelAll(); } public synchronized static void remove(long locationID) { getCitadelGetter().removeCitadel(locationID); } public synchronized static void remove(Set locationIDs) { getCitadelGetter().removeCitadels(locationIDs); } public synchronized static void set(Citadel citadel) { getCitadelGetter().setCitadel(citadel); } public synchronized static void set(Collection citadels) { getCitadelGetter().setCitadels(citadels); } private static CitadelGetter getCitadelGetter() { if (citadelGetter == null) { citadelGetter = new CitadelGetter(); citadelGetter.loadXml(); } return citadelGetter; } private void saveXml() { CitadelWriter.save(citadelSettings); } private void loadXml() { citadelSettings = CitadelReader.load(); } private void removeCitadel(long locationID) { citadelSettings.remove(locationID); saveXml(); } private void removeCitadels(Set locationIDs) { for (long locationID : locationIDs) { citadelSettings.remove(locationID); } if (!locationIDs.isEmpty()) { saveXml(); } } private void setCitadel(Citadel citadel) { citadelSettings.put(citadel.getLocationID(), citadel); saveXml(); } private void setCitadels(Collection citadels) { for (Citadel citadel : citadels) { citadelSettings.put(citadel.getLocationID(), citadel); } if (!citadels.isEmpty()) { saveXml(); } } private Citadel getCitadel(long locationID) { Citadel citadel = citadelSettings.get(locationID); if (citadel == null) { //Location not found in cache -> add placeholder for future updates citadel = new Citadel(locationID); } return citadel; } private Iterable> getCitadelAll() { return citadelSettings.getCache(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/online/DataGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.online; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.net.URLConnection; import java.nio.charset.MalformedInputException; import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.logging.Level; import java.util.logging.Logger; public class DataGetter { private static final Logger LOG = Logger.getLogger(DataGetter.class.getName()); public boolean get(String link, File out, String checksum) { return get(link, out, checksum, 0); } private boolean get(String link, File out, String checksum, int tries) { LOG.info("Downloading: " + link + " to: " + out.getAbsolutePath()); DigestInputStream input = null; FileOutputStream output = null; int n; try { MessageDigest md = MessageDigest.getInstance("MD5"); URL url = new URL(link); URLConnection con = url.openConnection(); byte[] buffer = new byte[4096]; input = new DigestInputStream(con.getInputStream(), md); output = new FileOutputStream(out); while ((n = input.read(buffer)) != -1) { output.write(buffer, 0, n); } output.flush(); String sum = getToHex(md.digest()); if (sum.equals(checksum)) { return true; //OK } } catch (MalformedInputException ex) { LOG.log(Level.SEVERE, ex.getMessage(), ex); } catch (IOException ex) { LOG.log(Level.SEVERE, ex.getMessage(), ex); } catch (NoSuchAlgorithmException ex) { LOG.log(Level.SEVERE, ex.getMessage(), ex); } finally { if (input != null) { try { input.close(); } catch (IOException ex) { LOG.log(Level.SEVERE, ex.getMessage(), ex); } } if (output != null) { try { output.close(); } catch (IOException ex) { LOG.log(Level.SEVERE, ex.getMessage(), ex); } } } if (tries < 10) { //Retry 10 times out.delete(); tries++; return get(link, out, checksum, tries); } else { //Failed 10 times, I give up... return false; } } private String getToHex(byte[] b) { String result = ""; for (int i = 0; i < b.length; i++) { result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1); } return result; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/online/EveImageGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.online; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import javax.imageio.ImageIO; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.api.raw.RawNpcStanding.FromType; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class EveImageGetter implements Runnable { private static final Logger LOG = LoggerFactory.getLogger(EveImageGetter.class); public static enum ImageSize { SIZE_32(32), SIZE_64(64), SIZE_128(128), SIZE_256(256), SIZE_512(512), SIZE_1024(1024); private final int size; private ImageSize(int size) { this.size = size; } public int getSize() { return size; } } public static enum ImageTypeVariation { BPO("bpo"), BPC("bpc"), RELIC("relic"), ICON("icon"), RENDER("render"); private final String variation; private ImageTypeVariation(String variation) { this.variation = variation; } public String getVariation() { return variation; } } public static enum ImageCategory { ALLIANCES("alliances", "logo"), CORPORATIONS("corporations", "logo"), CHARACTERS("characters", "portrait"), TYPE("type", "icon"); private final String category; private final String variation; private ImageCategory(String category, String variation) { this.category = category; this.variation = variation; } public String getURL(int id, ImageSize imageSize) { return getURL(id, imageSize, null); } public String getURL(int id, ImageSize size, ImageTypeVariation typeVariation) { if (typeVariation != null) { return "https://images.evetech.net/" + category + "/" + id + "/" + typeVariation.getVariation() + "?size=" + size.getSize(); } else { return "https://images.evetech.net/" + category + "/" + id + "/" + variation + "?size=" + size.getSize(); } } } private final UpdateTask updateTask; private final List ownerTypes; public EveImageGetter(UpdateTask updateTask, List ownerTypes) { this.updateTask = updateTask; this.ownerTypes = ownerTypes; } public static BufferedImage getBufferedImage(int corporationID, ImageCategory imageCategory) { ImageDownload imageDownload = new ImageDownload(corporationID, imageCategory); try { return imageDownload.get(); } catch (Exception ex) { return null; } } public static BufferedImage getBufferedImage(MyNpcStanding npcStanding) { ImageDownload imageDownload = new ImageDownload(npcStanding); try { return imageDownload.get(); } catch (Exception ex) { return null; } } public static BufferedImage getBufferedImage(MyLoyaltyPoints loyaltyPoints) { ImageDownload imageDownload = new ImageDownload(loyaltyPoints); try { return imageDownload.get(); } catch (Exception ex) { return null; } } @Override public void run() { try { ExecutorService threadPool = Executors.newFixedThreadPool(10); List> futures = new ArrayList<>(); for (Runnable runnable : getImageDownloads(ownerTypes)) { futures.add(threadPool.submit(runnable)); } threadPool.shutdown(); while (!threadPool.awaitTermination(500, TimeUnit.MICROSECONDS)) { if (updateTask != null) { if (updateTask.isCancelled()) { threadPool.shutdownNow(); } } } //Get errors (if any) for (Future future : futures) { future.get(); } } catch (InterruptedException ex) { LOG.error(ex.getMessage(), ex); } catch (ExecutionException ex) { LOG.error(ex.getMessage(), ex); } } private Set getImageDownloads(List ownerTypes) { Set set = new HashSet<>(); for (OwnerType ownerType : ownerTypes) { if (ownerType.isCharacter()) { set.add(new ImageDownload((int) ownerType.getOwnerID(), ImageCategory.CHARACTERS)); } else { set.add(new ImageDownload((int) ownerType.getOwnerID(), ImageCategory.CORPORATIONS)); } for (MyNpcStanding npcStanding : ownerType.getNpcStanding()) { set.add(new ImageDownload(npcStanding)); set.add(new ImageDownload(npcStanding.getCorporationID(), ImageCategory.CORPORATIONS)); } for (MyNpcStanding npcStanding : ownerType.getNpcStanding()) { set.add(new ImageDownload(npcStanding)); set.add(new ImageDownload(npcStanding.getCorporationID(), ImageCategory.CORPORATIONS)); } for (MyLoyaltyPoints loyaltyPoints : ownerType.getLoyaltyPoints()) { set.add(new ImageDownload(loyaltyPoints)); } } return set; } private static class ImageDownload implements Runnable { private final int id; private final ImageCategory category; private final ImageSize size; private final ImageTypeVariation typeVariation; private ImageDownload(MyNpcStanding npcStanding) { this.id = npcStanding.getFromID(); category = getImageCategory(npcStanding.getFromType()); size = MyNpcStanding.IMAGE_SIZE; typeVariation = null; } private ImageDownload(int corporationID, ImageCategory imageCategory) { this.id = corporationID; this.category = imageCategory; size = MyNpcStanding.IMAGE_SIZE; typeVariation = null; } private ImageDownload(MyLoyaltyPoints loyaltyPoints) { id = loyaltyPoints.getCorporationID(); category = ImageCategory.CORPORATIONS; size = MyLoyaltyPoints.IMAGE_SIZE; typeVariation = null; } private ImageCategory getImageCategory(FromType fromType) { if (fromType == FromType.FACTION) { return ImageCategory.CORPORATIONS; } else if (fromType == FromType.NPC_CORP) { return ImageCategory.CORPORATIONS; } else if (fromType == FromType.AGENT) { return ImageCategory.CHARACTERS; } else { throw new IllegalArgumentException(); } } @Override public void run() { try { download(id, category, size, typeVariation); } catch (IOException ex) { LOG.error(ex.getMessage(), ex); } } public BufferedImage get() throws Exception { String filename = download(id, category, size, typeVariation); return getBufferedImage(filename); } private String download(int id, ImageCategory category, ImageSize size, ImageTypeVariation typeVariation) throws IOException { String url = category.getURL(id, size, typeVariation); String filename = FileUtil.getPathImages(getFilename(id, category, size, typeVariation)); Path path = Paths.get(filename); if (Files.exists(path)) { return filename; } try (InputStream in = new URL(url).openStream()) { Files.copy(in, path); } return filename; } private String getFilename(int id, ImageCategory category, ImageSize size, ImageTypeVariation typeVariation) { if (typeVariation != null) { return category.name().toLowerCase() + "_" + typeVariation.name().toLowerCase() + "_" + id + "_" + size.getSize() + ".png"; } else { return category.name().toLowerCase() + "_" + id + "_" + size.getSize() + ".png"; } } private static BufferedImage getBufferedImage(final String filename) { try { if (filename != null) { return ImageIO.read(new File(filename)); } else { LOG.warn("image: " + filename + " not found (URL == null)"); } } catch (IOException ex) { LOG.warn("image: " + filename + " not found (IOException)"); } return null; } @Override public int hashCode() { int hash = 7; hash = 97 * hash + this.id; hash = 97 * hash + Objects.hashCode(this.category); hash = 97 * hash + Objects.hashCode(this.typeVariation); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ImageDownload other = (ImageDownload) obj; if (this.id != other.id) { return false; } if (this.category != other.category) { return false; } return this.typeVariation == other.typeVariation; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/online/EveRefGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.online; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; import com.google.gson.annotations.SerializedName; import com.google.gson.reflect.TypeToken; import java.io.IOException; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.sde.IndustryMaterial; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.ReprocessedMaterial; import net.nikr.eve.jeveasset.io.esi.EsiItemsGetter; import net.nikr.eve.jeveasset.io.shared.ThreadWoker; import okhttp3.Call; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.logging.HttpLoggingInterceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class EveRefGetter { private static final Logger LOG = LoggerFactory.getLogger(EveRefGetter.class); private static final Gson GSON = new GsonBuilder().create(); /** * HttpLoggingInterceptor */ private static final HttpLoggingInterceptor HTTP_LOGGING_INTERCEPTOR = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { @Override public void log(String string) { LOG.debug(string); } }); /** * HTTP Client */ private final OkHttpClient client; private static EveRefGetter getter; private EveRefGetter() { if (LOG.isDebugEnabled()) { client = new OkHttpClient().newBuilder() .addNetworkInterceptor(HTTP_LOGGING_INTERCEPTOR) .build(); HTTP_LOGGING_INTERCEPTOR.setLevel(HttpLoggingInterceptor.Level.BASIC); } else { client = new OkHttpClient().newBuilder().build(); } } public static Item getItem(Item item) { EveRefType type = getType(item.getTypeID()); if (type == null) { return item; } EveRefBlueprint blueprint = null; if (get(type.isBlueprint(), false)) { //Get Blueprint Data blueprint = getBlueprint(item.getTypeID()); } return getItem(item, type, blueprint); } protected static Item getItem(Item item, EveRefType type, EveRefBlueprint blueprint) { if (type == null) { return item; } //Tech Level String tech = item.getTech(); Integer metaGroupID = type.getMetaGroupID(); if (metaGroupID != null) { tech = EsiItemsGetter.getTechLevel(metaGroupID); } //BlueprintIDs Set blueprintTypeIDs = new HashSet<>(); Map producedByBlueprints = type.getProducedByBlueprints(); if (producedByBlueprints != null) { for (EveRefProducedByBlueprints blueprints : producedByBlueprints.values()) { if ("manufacturing".equalsIgnoreCase(blueprints.getBlueprintActivity())) { Integer blueprintTypeID = blueprints.getBlueprintTypeID(); if (blueprintTypeID != null) { blueprintTypeIDs.add(blueprintTypeID); } } } } //Reproccesed List reprocessedMaterials = new ArrayList<>(); if (type.getTypeMaterials() != null && item.isMarketGroup()) { for (EveRefTypeMaterial material : type.getTypeMaterials().values()) { Integer typeID = material.getMaterialTypeID(); Integer quantity = material.getQuantity(); if (typeID != null && quantity != null) { reprocessedMaterials.add(new ReprocessedMaterial(typeID, quantity, type.getPortionSize())); } } } int productTypeID = EsiItemsGetter.PRODUCT_TYPE_ID_DEFAULT; int productQuantity = EsiItemsGetter.PRODUCT_QUANTITY_DEFAULT; List manufacturingMaterials = new ArrayList<>(); List reactionMaterials = new ArrayList<>(); if (blueprint != null) { //Blueprints safeAdd(blueprint.getManufacturing(), manufacturingMaterials); EveRefMaterial manufacturingMaterial = safeGet(blueprint.getManufacturing()); if (manufacturingMaterial != null) { productTypeID = manufacturingMaterial.getTypeID(); productQuantity = manufacturingMaterial.getQuantity(); } //Reactions safeAdd(blueprint.getReaction(), reactionMaterials); EveRefMaterial reactionMaterial = safeGet(blueprint.getReaction()); if (reactionMaterial != null) { productTypeID = reactionMaterial.getTypeID(); productQuantity = reactionMaterial.getQuantity(); } } //Base Price Long basePrice = get(type.getBasePrice(), EsiItemsGetter.BASE_PRICE_DEFAULT).longValue(); return new Item(item, basePrice, tech, productTypeID, productQuantity, blueprintTypeIDs, reprocessedMaterials, manufacturingMaterials, reactionMaterials); } private static void safeAdd(EveRefActivity activity, List materials) { if (activity != null && activity.getMaterials() != null) { for (EveRefMaterial eveRefMaterial : activity.getMaterials().values()) { Integer typeID = eveRefMaterial.getTypeID(); Integer quantity = eveRefMaterial.getQuantity(); if (typeID != null && quantity != null) { materials.add(new IndustryMaterial(typeID, quantity)); } } } } private static EveRefMaterial safeGet(EveRefActivity activity) { if (activity != null && activity.getProducts() != null) { Map reactionProducts = activity.getProducts(); if (!reactionProducts.isEmpty()) { return reactionProducts.values().iterator().next(); } } return null; } private static V get(V value, V defaultValue) { if (value != null) { return value; } return defaultValue; } public static EveRefBlueprint getBlueprint(int TypeID) { if (getter == null) { getter = new EveRefGetter(); } return getter.blueprint(TypeID); } public static EveRefType getType(int TypeID) { if (getter == null) { getter = new EveRefGetter(); } return getter.type(TypeID); } private EveRefBlueprint blueprint(final int typeID) { Update update = new Update(new Updater() { @Override public Call getCall() { Request.Builder request = new Request.Builder() .url("https://ref-data.everef.net/blueprints/" + typeID) .addHeader("User-Agent", Program.PROGRAM_USER_AGENT); return client.newCall(request.build()); } @Override public Type getType() { return new TypeToken() {}.getType(); } }) { }; return ThreadWoker.startReturn(null, update); //Return null on failure } private EveRefType type(final int typeID) { Update update = new Update(new Updater() { @Override public Call getCall() { Request.Builder request = new Request.Builder() .url("https://ref-data.everef.net/types/" + typeID) .addHeader("User-Agent", Program.PROGRAM_USER_AGENT); return client.newCall(request.build()); } @Override public Type getType() { return new TypeToken() {}.getType(); } }) { }; return ThreadWoker.startReturn(null, update); //Return null on failure } private abstract class Update implements Callable { private final Updater updater; public Update(Updater updater) { this.updater = updater; } @Override public T call() throws Exception { long start = System.currentTimeMillis(); T results = null; try { results = GSON.fromJson(updater.getCall().execute().body().string(), updater.getType()); if (results == null) { LOG.error("Error fetching price", new Exception("results is null")); } } catch (IllegalArgumentException | IOException | JsonParseException ex) { LOG.error("Error fetching price", ex); } long duration = System.currentTimeMillis() - start; LOG.info("Completed in " + duration + "ms"); return results; } } private static interface Updater { public Call getCall(); public Type getType(); } public static class EveRefBlueprint { private Map activities; @SerializedName(value = "blueprint_type_id") private Long blueprintTypeID; @SerializedName(value = "max_production_limit") private Long maxProductionLimit; public Map getActivities() { if (activities == null) { activities = new HashMap<>(); } return activities; } public EveRefActivity getCopying() { return getActivities().get("copying"); } public EveRefActivity getInvention() { return getActivities().get("invention"); } public EveRefActivity getManufacturing() { return getActivities().get("manufacturing"); } public EveRefActivity getReaction() { return getActivities().get("reaction"); } public EveRefActivity getResearchMaterial() { return getActivities().get("research_material"); } public EveRefActivity getResearchTime() { return getActivities().get("research_time"); } public Long getBlueprintTypeID() { return blueprintTypeID; } public Long getMaxProductionLimit() { return maxProductionLimit; } } public static class EveRefActivity { private Map materials; private Map products; private Long time; @SerializedName(value = "required_skills") private Map requiredSkills; public Map getMaterials() { return materials; } public Map getProducts() { return products; } public Long getTime() { return time; } public Map getRequiredSkills() { return requiredSkills; } } public static class EveRefMaterial { private Double probability; private Integer quantity; @SerializedName(value = "type_id") private Integer typeID; public Double getProbability() { return probability; } public Integer getQuantity() { return quantity; } public Integer getTypeID() { return typeID; } } public static class EveRefType { @SerializedName(value = "type_id") private Long typeID; @SerializedName(value = "base_price") private Double basePrice; private Double capacity; private Map description; @SerializedName(value = "dogma_attributes") private Map dogmaAttributes; @SerializedName(value = "dogma_effects") private Map dogmaEffects; @SerializedName(value = "faction_id") private Long factionID; @SerializedName(value = "graphic_id") private Long graphicID; @SerializedName(value = "group_id") private Long groupID; @SerializedName(value = "icon_id") private Long iconID; @SerializedName(value = "market_group_id") private Long marketGroupID; private Double mass; private Map> masteries; @SerializedName(value = "meta_group_id") private Integer metaGroupID; private Map name; @SerializedName(value = "packaged_volume") private Double packagedVolume; @SerializedName(value = "portion_size") private Integer portionSize; private Boolean published; @SerializedName(value = "race_id") private Long raceID; private Double radius; @SerializedName(value = "sof_faction_name") private String sofFactionName; @SerializedName(value = "sof_material_set_id") private Long sofMaterialSetID; @SerializedName(value = "sound_id") private Long soundID; private EveRefTraits traits; @SerializedName(value = "variation_parent_type_id") private Long variationParentTypeID; private Double volume; @SerializedName(value = "required_skills") private Map requiredSkills; @SerializedName(value = "applicable_mutaplasmid_type_ids") private List applicableMutaplasmidTypeIDS; @SerializedName(value = "creating_mutaplasmid_type_ids") private List creatingMutaplasmidTypeIDS; @SerializedName(value = "type_variations") private Map> typeVariations; @SerializedName(value = "ore_variations") private Map> oreVariations; @SerializedName(value = "is_ore") private Boolean ore; @SerializedName(value = "produced_by_blueprints") private Map producedByBlueprints; @SerializedName(value = "type_materials") private Map typeMaterials; @SerializedName(value = "can_fit_types") private List canFitTypes; @SerializedName(value = "can_be_fitted_with_types") private List canBeFittedWithTypes; @SerializedName(value = "is_skill") private Boolean skill; @SerializedName(value = "is_mutaplasmid") private Boolean mutaplasmid; @SerializedName(value = "is_dynamic_item") private Boolean dynamicItem; @SerializedName(value = "is_blueprint") private Boolean blueprint; public Long getTypeID() { return typeID; } public Double getBasePrice() { return basePrice; } public Double getCapacity() { return capacity; } public Map getDescription() { return description; } public Map getDogmaAttributes() { return dogmaAttributes; } public Map getDogmaEffects() { return dogmaEffects; } public Long getFactionID() { return factionID; } public Long getGraphicID() { return graphicID; } public Long getGroupID() { return groupID; } public Long getIconID() { return iconID; } public Long getMarketGroupID() { return marketGroupID; } public Double getMass() { return mass; } public Map> getMasteries() { return masteries; } public Integer getMetaGroupID() { return metaGroupID; } public Map getName() { return name; } public Double getPackagedVolume() { return packagedVolume; } public Integer getPortionSize() { return portionSize; } public Boolean isPublished() { return published; } public Long getRaceID() { return raceID; } public Double getRadius() { return radius; } public String getSofFactionName() { return sofFactionName; } public Long getSofMaterialSetID() { return sofMaterialSetID; } public Long getSoundID() { return soundID; } public EveRefTraits getTraits() { return traits; } public Long getVariationParentTypeID() { return variationParentTypeID; } public Double getVolume() { return volume; } public Map getRequiredSkills() { return requiredSkills; } public List getApplicableMutaplasmidTypeIDS() { return applicableMutaplasmidTypeIDS; } public List getCreatingMutaplasmidTypeIDS() { return creatingMutaplasmidTypeIDS; } public Map> getTypeVariations() { return typeVariations; } public Map> getOreVariations() { return oreVariations; } public Boolean isOre() { return ore; } public Map getProducedByBlueprints() { return producedByBlueprints; } public Map getTypeMaterials() { return typeMaterials; } public List getCanFitTypes() { return canFitTypes; } public List getCanBeFittedWithTypes() { return canBeFittedWithTypes; } public Boolean isSkill() { return skill; } public Boolean isMutaplasmid() { return mutaplasmid; } public Boolean isDynamicItem() { return dynamicItem; } public Boolean isBlueprint() { return blueprint; } } public static class EveRefDogmaAttribute { @SerializedName(value = "attribute_id") private Long attributeID; private Double value; public Long getAttributeID() { return attributeID; } public Double getValue() { return value; } } public static class EveRefDogmaEffect { @SerializedName(value = "effect_id") private Long effectID; @SerializedName(value = "is_default") private Boolean isDefault; public Long getEffectID() { return effectID; } public Boolean isDefault() { return isDefault; } } public static class EveRefProducedByBlueprints { @SerializedName(value = "blueprint_type_id") private Integer blueprintTypeID; @SerializedName(value = "blueprint_activity") private String blueprintActivity; public Integer getBlueprintTypeID() { return blueprintTypeID; } public String getBlueprintActivity() { return blueprintActivity; } } public static class EveRefTraits { @SerializedName(value = "misc_bonuses") private Map miscBonuses; @SerializedName(value = "role_bonuses") private Map roleBonuses; private Map> types; public Map getMiscBonuses() { return miscBonuses; } public Map getRoleBonuses() { return roleBonuses; } public Map> getTypes() { return types; } } public static class EveRefRoleBonus { private Double bonus; @SerializedName(value = "bonus_text") private Map bonusText; private Long importance; @SerializedName(value = "is_positive") private Boolean positive; @SerializedName(value = "unit_id") private Long unitID; public Double getBonus() { return bonus; } public Map getBonusText() { return bonusText; } public Long getImportance() { return importance; } public Boolean isPositive() { return positive; } public Long getUnitID() { return unitID; } } public static class EveRefTypeMaterial { @SerializedName(value = "material_type_id") private Integer materialTypeID; private Integer quantity; public Integer getMaterialTypeID() { return materialTypeID; } public Integer getQuantity() { return quantity; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/online/PriceDataGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.online; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Proxy; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.SplashUpdater; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.PriceData; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings.PriceMode; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings.PriceSource; import net.nikr.eve.jeveasset.data.settings.PriceHistoryDatabase; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import uk.me.candle.eve.pricing.Pricing; import uk.me.candle.eve.pricing.PricingFactory; import uk.me.candle.eve.pricing.PricingListener; import uk.me.candle.eve.pricing.options.LocationType; import uk.me.candle.eve.pricing.options.PriceLocation; import uk.me.candle.eve.pricing.options.PriceType; import uk.me.candle.eve.pricing.options.PricingFetch; import uk.me.candle.eve.pricing.options.PricingOptions; public class PriceDataGetter implements PricingListener { private static final Logger LOG = LoggerFactory.getLogger(PriceDataGetter.class); private static final String JANICE = ""; private static final long PRICE_CACHE_TIMER = 1 * 60 * 60 * 1000L; // 1 hour (hours*min*sec*ms) private static final int ATTEMPT_COUNT = 2; private static final int ZERO_PRICES_WARNING_LIMIT = 10; private static final double FAILED_PERCENT_CANCEL_LIMIT = 5.0; private static final int PLEX_TYPE_ID = 44992; private UpdateTask updateTask; private boolean update; private Set typeIDs; private Set failed; private Set okay; private Set zero; private Set queue; private final Map updatedList = Collections.synchronizedMap(new HashMap<>()); private final Map priceDataList = Collections.synchronizedMap(new HashMap<>()); private long nextUpdate = 0; public void load() { Map priceData = processLoad(); if (priceData != null) { Settings.get().setPriceData(priceData); } } /** * Load price data from cache and only update missing price data. * @param profileData * @param task UpdateTask to track progress * @return */ public boolean updateNew(final ProfileData profileData, final UpdateTask task) { return processUpdate(profileData, task, false); } /** * Update of all price data. * @param profileData * @param task UpdateTask to track progress * @return */ public boolean updateAll(final ProfileData profileData, final UpdateTask task) { return processUpdate(profileData, task, true); } /** * Load data from price cache * @return available price data */ private Map processLoad() { Pricing pricing = PricingFactory.getPricing(PricingFetch.FUZZWORK, new DefaultPricingOptions()); LOG.info("Price data loading"); for (Item item : StaticData.get().getItems().values()) { //For each typeID if (!item.isMarketGroup()) { continue; } int typeID = item.getTypeID(); PriceData priceData = priceDataList.get(typeID); if (priceData == null) { priceData = new PriceData(); priceDataList.put(typeID, priceData); } boolean ok = false; for (PriceMode priceMode : PriceMode.values()) { //For each PriceMode (all combinations of PricingNumber & PricingType) PriceType priceType = priceMode.getPricingType(); if (priceType == null) { continue; //Ignore calculated prices - f.ex. PriceMode.PRICE_MIDPOINT } Double price = pricing.getPriceCache(typeID, priceType); if (price != null) { ok = true; //Something is set PriceMode.setDefaultPrice(priceData, priceMode, price); } } if (!ok) { priceDataList.remove(typeID); //Remove failed typeID } long nextUpdateTemp = pricing.getNextUpdateTime(typeID); if (nextUpdateTemp >= 0 && nextUpdateTemp > getNextUpdateTime()) { setUpdateNext(nextUpdateTemp); } } if (!priceDataList.isEmpty()) { LOG.info(" Price data loaded"); Map hashMap = new HashMap<>(); hashMap.putAll(priceDataList); return hashMap; //Return copy of Map } else { LOG.info(" Price data not loaded"); return null; } } /** * Update settings with new price data * @param task UpdateTask to update progress on * @param updateAll if true update all prices, if false only update new/missing prices * @return true if OK or false if FAILED */ private boolean processUpdate(final ProfileData profileData, final UpdateTask task, final boolean updateAll) { Set priceTypeIDs = profileData.getPriceTypeIDs(); //Remove plex boolean plex; if (Settings.get().getPriceDataSettings().getSource() == PriceSource.FUZZWORK) { plex = priceTypeIDs.remove(PLEX_TYPE_ID); } else { plex = false; } //Update normal Map priceData = processUpdate(task, updateAll, new DefaultPricingOptions(), priceTypeIDs, Settings.get().getPriceDataSettings().getSource()); //Update plex Map plexPriceData = null; if (plex) { plexPriceData = processUpdate(task, updateAll, new PlexPricingOptions(0), Collections.singleton(PLEX_TYPE_ID), Settings.get().getPriceDataSettings().getSource()); } if (priceData != null) { if (plexPriceData != null) { priceData.putAll(plexPriceData); } Settings.get().setPriceData(priceData); return true; } else { return false; } } /** * * @param task UpdateTask to update progress on * @param updateAll true to update all prices. false to only update new/missing prices * @param pricingOptions Options used doing update * @param typeIDs TypeIDs to get price data for * @param priceSource Price data source to update from (only used in log) * @return */ protected Map processUpdate(final UpdateTask task, final boolean updateAll, final PricingOptions pricingOptions, final Set typeIDs, final PriceSource priceSource) { this.updateTask = task; this.update = updateAll; this.typeIDs = Collections.synchronizedSet(new HashSet<>(typeIDs)); this.failed = Collections.synchronizedSet(new HashSet<>()); this.zero = Collections.synchronizedSet(new HashSet<>()); this.okay = Collections.synchronizedSet(new HashSet<>()); this.queue = Collections.synchronizedSet(new HashSet<>(typeIDs)); this.updatedList.clear(); if (priceSource == PriceSource.JANICE) { String janiceKey = Settings.get().getPriceDataSettings().getJaniceKey(); if (janiceKey != null && !janiceKey.isEmpty()) { pricingOptions.addHeader("X-ApiKey", janiceKey); } else if (JANICE != null && !JANICE.isEmpty()) { pricingOptions.addHeader("X-ApiKey", JANICE); } else if (updateTask != null) { updateTask.addError("Price data", "No Janice API Key"); return null; } } if (updateAll) { LOG.info("Price data update all (" + priceSource + "):"); } else { LOG.info("Price data update new (" + priceSource + "):"); } Pricing pricing = PricingFactory.getPricing(priceSource.getPricingFetch(), pricingOptions); pricing.addPricingListener(this); if (updateAll) { //Update all pricing.updatePrices(typeIDs); } else { //Update new for (int id : typeIDs) { createPriceData(id, pricing); } } while (!queue.isEmpty()) { try { synchronized (this) { wait(1000); } } catch (InterruptedException ex) { LOG.info("Failed to update price"); pricing.cancelAll(); if (updateTask != null) { updateTask.addWarning("Price data", "Cancelled"); updateTask.setTaskProgress(100, 100, 0, 100); updateTask = null; } clear(pricing); return null; } } boolean updated = !okay.isEmpty() && typeIDs.size() * FAILED_PERCENT_CANCEL_LIMIT / 100 > failed.size(); if (!failed.isEmpty()) { StringBuilder errorString = new StringBuilder(); boolean first = true; synchronized (failed) { for (int typeID : failed) { if (first) { first = false; } else { errorString.append(", "); } errorString.append(typeID); } } LOG.error("Failed to update price data for the following typeIDs: " + errorString.toString()); if (updated && updateTask != null) { updateTask.addError("Price data", "Failed to update price data for " + failed.size() + " of " + typeIDs.size() + " item types"); } } if (!zero.isEmpty()) { StringBuilder errorString = new StringBuilder(); synchronized (zero) { boolean first = true; for (int typeID : zero) { if (first) { first = false; } else { errorString.append(", "); } errorString.append(typeID); } } LOG.warn("Price data is zero for the following typeIDs: " + errorString.toString()); if (updated && updateTask != null && typeIDs.size() * ZERO_PRICES_WARNING_LIMIT / 100 < zero.size()) { updateTask.addWarning("Price data", "Price data is zero for " + zero.size() + " of " + typeIDs.size() + " item types"); } } if (updated) { //All Updated if (updateAll) { LOG.info(" Price data updated"); } else { LOG.info(" Price data loaded"); } try { pricing.writeCache(); LOG.info(" Price data cached saved"); } catch (IOException ex) { LOG.error("Failed to write price data cache", ex); } //We only set the price data if everthing worked (AKA all updated) try { //return new HashMap(priceDataList); // XXX - Workaround for ConcurrentModificationException in HashMap constructor Map hashMap = new HashMap<>(); priceDataList.keySet().removeAll(failed); //Remove failed hashMap.putAll(priceDataList); PriceHistoryDatabase.setPriceData(updatedList); return hashMap; } finally { clear(pricing); } } else { //None or some updated LOG.info(" Failed to update price data"); if (updateTask != null) { updateTask.addError("Price data", "Failed to update price data"); updateTask.setTaskProgress(100, 100, 0, 100); } clear(pricing); return null; } } public synchronized Date getNextUpdate() { return new Date(nextUpdate + PRICE_CACHE_TIMER); } private synchronized long getNextUpdateTime() { return nextUpdate; } private synchronized void setUpdateNext(long nextUpdate) { this.nextUpdate = nextUpdate; } private void clear(Pricing pricing) { //Memory SplashUpdater.setSubProgress(100); this.updateTask = null; this.typeIDs.clear(); this.failed.clear(); pricing.removePricingListener(this); } @Override public void priceUpdated(final int typeID, final Pricing pricing) { createPriceData(typeID, pricing); queue.remove(typeID); synchronized (this) { notify(); } } @Override public void priceUpdateFailed(final int typeID, final Pricing pricing) { failed.add(typeID); queue.remove(typeID); synchronized (this) { notify(); } } private void createPriceData(final int typeID, final Pricing pricing) { PriceData priceData = priceDataList.get(typeID); if (priceData == null) { priceData = new PriceData(); priceDataList.put(typeID, priceData); } boolean ok = false; boolean isZero = true; for (PriceMode priceMode : PriceMode.values()) { PriceType priceType = priceMode.getPricingType(); if (priceType == null) { continue; //Ignore calculated prices - f.ex. PriceMode.PRICE_MIDPOINT } Double price = pricing.getPrice(typeID, priceType); if (price != null) { ok = true; //Something is set PriceMode.setDefaultPrice(priceData, priceMode, price); if (price != 0) { isZero = false; } } } if (ok) { if (isZero) { zero.add(typeID); } updatedList.put(typeID, priceData); okay.add(typeID); failed.remove(typeID); queue.remove(typeID); //Load price... } else { failed.add(typeID); } long nextUpdateTemp = pricing.getNextUpdateTime(typeID); if (nextUpdateTemp >= 0 && nextUpdateTemp > getNextUpdateTime()) { setUpdateNext(nextUpdateTemp); } if (updateTask != null) { updateTask.setTaskProgress(typeIDs.size(), okay.size(), 0, 100); } if (!okay.isEmpty() && !typeIDs.isEmpty()) { SplashUpdater.setSubProgress((int) (okay.size() * 100.0 / typeIDs.size())); } } private class PlexPricingOptions extends DefaultPricingOptions { private final int globalPlexMarketRegionID; public PlexPricingOptions(int globalPlexMarketRegionID) { this.globalPlexMarketRegionID = globalPlexMarketRegionID; } @Override public PriceLocation getLocation() { return new PriceLocation() { @Override public long getRegionID() { return globalPlexMarketRegionID; } @Override public long getLocationID() { return globalPlexMarketRegionID; } }; } @Override public LocationType getLocationType() { return LocationType.REGION; } } private class DefaultPricingOptions implements PricingOptions { @Override public long getPriceCacheTimer() { return PRICE_CACHE_TIMER; } @Override public LocationType getLocationType() { return Settings.get().getPriceDataSettings().getLocationType(); } @Override public PriceLocation getLocation() { return ApiIdConverter.getLocation(Settings.get().getPriceDataSettings().getLocationID()); } @Override public InputStream getCacheInputStream() throws IOException { File file = new File(FileUtil.getPathPriceData()); if (file.exists()) { return new FileInputStream(file); } return null; } @Override public OutputStream getCacheOutputStream() throws IOException { return new FileOutputStream(FileUtil.getPathPriceData()); } @Override public boolean getCacheTimersEnabled() { return update; } @Override public Proxy getProxy() { return null; } @Override public int getAttemptCount() { return ATTEMPT_COUNT; } @Override public boolean getUseBinaryErrorSearch() { return false; } @Override public int getTimeout() { return 20000; } @Override public String getUserAgent() { return Program.PROGRAM_USER_AGENT; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/online/UpdateTaskInputStream.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.online; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; public class UpdateTaskInputStream extends FilterInputStream { private final long maxNumBytes; private final UpdateTask updateTask; private final int start; private final int end; private volatile long totalNumBytesRead; public UpdateTaskInputStream(final InputStream in, final long maxNumBytes, final UpdateTask updateTask) { this(in, maxNumBytes, updateTask, 0, 100); } public UpdateTaskInputStream(final InputStream in, final long maxNumBytes, final UpdateTask updateTask, int start, int end) { super(in); this.maxNumBytes = maxNumBytes; this.updateTask = updateTask; this.start = start; this.end = end; } public long getMaxNumBytes() { return maxNumBytes; } public long getTotalNumBytesRead() { return totalNumBytesRead; } @Override public int read() throws IOException { return updateProgressInteger(super.read()); } @Override public int read(byte[] b) throws IOException { return updateProgressInteger(super.read(b)); } @Override public int read(byte[] b, int off, int len) throws IOException { return updateProgressInteger(super.read(b, off, len)); } @Override public long skip(long n) throws IOException { return updateProgressLong(super.skip(n)); } @Override public synchronized void mark(int readlimit) { throw new UnsupportedOperationException(); } @Override public synchronized void reset() throws IOException { throw new UnsupportedOperationException(); } @Override public boolean markSupported() { return false; } private int updateProgressInteger(final int numBytesRead) { updateProgressLong(numBytesRead); return numBytesRead; } private long updateProgressLong(final long numBytesRead) { if (numBytesRead > 0) { this.totalNumBytesRead += numBytesRead; if (updateTask != null) { updateTask.setTaskProgress(maxNumBytes, totalNumBytesRead, start, end); } } return numBytesRead; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/online/Updater.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * Original code from jWarframe (https://github.com/GoldenGnu/jwarframe) * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.online; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.CliOptions; import net.nikr.eve.jeveasset.Main; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.ProxyData; import net.nikr.eve.jeveasset.io.shared.FileUtil; public class Updater { private static final Logger LOG = Logger.getLogger(Updater.class.getName()); private static final String UPDATE_URL = "https://eve.nikr.net/jeveassets/update/"; private static final String PROGRAM = UPDATE_URL + "program/"; private static final String DATA = UPDATE_URL + "data/"; private static final String UPDATE = UPDATE_URL + "jupdate.jar"; public void update(final String localProgram, String localData, ProxyData proxyData) { if (isPackageManager() && !getPackageNotifyUpdates()) { LOG.info("Not checking for updates (package manager enabled)"); return; } LOG.info("Checking online version"); Getter getter = new Getter(); final String onlineProgram = getter.get(PROGRAM+"update_version.dat"); update("Program", onlineProgram, localProgram, PROGRAM, proxyData); final String onlineData = getter.get(DATA+"update_version.dat"); if (localData == null) { fixData(); } else { update("Static data", onlineData, localData, DATA, proxyData); } } public boolean checkProgramUpdate(final String localProgram) { if (isPackageManager()) { LOG.info("Not checking for updates (package manager enabled)"); return false; } LOG.info("Checking online version"); Getter getter = new Getter(); final String onlineProgram = getter.get(PROGRAM+"update_version.dat"); return onlineProgram != null && !onlineProgram.equals(localProgram); } public boolean checkDataUpdate(String localData) { if (isPackageManager()) { LOG.info("Not checking for updates (package manager enabled)"); return false; } LOG.info("Checking online version"); Getter getter = new Getter(); final String onlineData = getter.get(DATA+"update_version.dat"); return onlineData != null && !onlineData.equals(localData); } public void fixData() { if (isPackageManager()) { JOptionPane.showMessageDialog(Main.getTop(), "One of the data files in the data folder is corrupted or missing\r\n" + "jEveAssets will not work without it\r\n" + "Please use your package manager to correct the problem\r\n" , Program.PROGRAM_NAME + " - Critical Error", JOptionPane.ERROR_MESSAGE); System.exit(-1); } int value = JOptionPane.showConfirmDialog(Main.getTop(), "One of the data files in the data folder is corrupted or missing\r\n" + "jEveAssets will not work without it\r\n" + "Download the latest version with auto update?\r\n" , Program.PROGRAM_NAME + " - Critical Error", JOptionPane.OK_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE); if (value == JOptionPane.OK_OPTION) { LOG.info("Updating data"); boolean download = downloadUpdater(); if (download) { runUpdate(DATA, null); } else { JOptionPane.showMessageDialog(Main.getTop(), "Auto update failed\r\n" + "Please, re-download jEveAssets and leave the unzipped directory intact\r\n" + "Press OK to close jEveAssets", Program.PROGRAM_NAME + " - Critical Error", JOptionPane.ERROR_MESSAGE); System.exit(-1); } } else { JOptionPane.showMessageDialog(Main.getTop(), "Please, re-download jEveAssets and leave the unzipped directory intact\r\n" + "Restart jEveAssets to use auto update to fix the problem\r\n" + "Press OK to close jEveAssets", Program.PROGRAM_NAME + " - Critical Error", JOptionPane.ERROR_MESSAGE); System.exit(-1); } } public void fixLibs() { if (isPackageManager()) { JOptionPane.showMessageDialog(Main.getTop(), "One of the libraies in the lib folder is corrupted or missing\r\n" + "jEveAssets will not work without it\r\n" + "Please use your package manager to correct the problem\r\n" , Program.PROGRAM_NAME + " - Critical Error", JOptionPane.ERROR_MESSAGE); System.exit(-1); } int value = JOptionPane.showConfirmDialog(Main.getTop(), "One of the libraies in the lib folder is corrupted or missing\r\n" + "jEveAssets will not work without it\r\n" + "Download the latest version with auto update?\r\n" , Program.PROGRAM_NAME + " - Critical Error", JOptionPane.OK_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE); if (value == JOptionPane.OK_OPTION) { LOG.info("Updating program"); boolean download = downloadUpdater(); if (download) { runUpdate(PROGRAM, null); } else { JOptionPane.showMessageDialog(Main.getTop(), "Auto update failed\r\n" + "Please, re-download jEveAssets and leave the unzipped directory intact\r\n" + "Press OK to close jEveAssets", Program.PROGRAM_NAME + " - Critical Error", JOptionPane.ERROR_MESSAGE); System.exit(-1); } } else { JOptionPane.showMessageDialog(Main.getTop(), "Please, re-download jEveAssets and leave the unzipped directory intact\r\n" + "Restart jEveAssets to use auto update to fix the problem\r\n" + "Press OK to close jEveAssets", Program.PROGRAM_NAME + " - Critical Error", JOptionPane.ERROR_MESSAGE); System.exit(-1); } } public void fixMissingClasses() { if (isPackageManager()) { JOptionPane.showMessageDialog(Main.getTop(), "jEveAssets have been corrupted\r\n" + "Please use your package manager to correct the problem\r\n" , Program.PROGRAM_NAME + " - Critical Error", JOptionPane.ERROR_MESSAGE); System.exit(-1); } int value = JOptionPane.showConfirmDialog(Main.getTop(), "jEveAssets have been corrupted\r\n" + "You may be able to use auto update to fix the problem\r\n" + "Download the latest version with auto update?\r\n" , Program.PROGRAM_NAME + " - Critical Error", JOptionPane.OK_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE); if (value == JOptionPane.OK_OPTION) { LOG.info("Updating program"); boolean download = downloadUpdater(); if (download) { runUpdate(PROGRAM, null); } else { JOptionPane.showMessageDialog(Main.getTop(), "Auto update failed\r\n" + "Please, re-download jEveAssets and leave the unzipped directory intact\r\n" + "Press OK to close jEveAssets" , Program.PROGRAM_NAME + " - Critical Error", JOptionPane.ERROR_MESSAGE); System.exit(-1); } } else { JOptionPane.showMessageDialog(Main.getTop(), "Please, re-download jEveAssets and leave the unzipped directory intact\r\n" + "Restart jEveAssets to use auto update to fix the problem\r\n" + "Press OK to close jEveAssets" , Program.PROGRAM_NAME + " - Critical Error", JOptionPane.ERROR_MESSAGE); System.exit(-1); } } public String getLocalData() { Getter getter = new Getter(); return getter.get(new File(FileUtil.getPathDataVersion())); } private void update(String title, String online, String local, String link, ProxyData proxyData) { LOG.log(Level.INFO, "{0} Online: {1} Local: {2}", new Object[]{title.toUpperCase(), online, local}); if (online != null && !online.equals(local)) { if (isPackageManager()) { JOptionPane.showMessageDialog(Main.getTop(), title + " update available\r\n" + "\r\n" + "Your version: " + local + "\r\n" + "Latest version: " + online + "\r\n" + "\r\n" + "Please use your package manager to update\r\n" + "\r\n" , Program.PROGRAM_NAME + " - Auto Update", JOptionPane.PLAIN_MESSAGE); return; } int value = JOptionPane.showConfirmDialog(Main.getTop(), title + " update available\r\n" + "\r\n" + "Your version: " + local + "\r\n" + "Latest version: " + online + "\r\n" + "\r\n" + "Update " + title.toLowerCase() + " now?\r\n" + "\r\n" , Program.PROGRAM_NAME + " - Auto Update", JOptionPane.OK_CANCEL_OPTION); if (value == JOptionPane.OK_OPTION) { LOG.log(Level.INFO, "Updating {0}", title); boolean download = downloadUpdater(); if (download) { runUpdate(link, proxyData); } else { JOptionPane.showMessageDialog(Main.getTop(), "Auto update failed\r\n" + "Restart jEveAssets to try again...", "jEveAssets - Auto Update", JOptionPane.ERROR_MESSAGE); } } } } private void runUpdate(String link, ProxyData proxyData) { ProcessBuilder processBuilder = new ProcessBuilder(); processBuilder.directory(getJavaHome()); processBuilder.command(getArgsString(link, proxyData)); try { processBuilder.start(); System.exit(0); } catch (IOException ex) { LOG.log(Level.SEVERE, "Failed to start jupdate.jar", ex); } } private File getJavaHome() { return new File(System.getProperty("java.home") + File.separator + "bin"); } private List getArgsString(String link, ProxyData proxyData) { List list = new ArrayList<>(); list.add("java"); if (proxyData != null) { list.addAll(proxyData.getArgs()); } else { list.add("-Djava.net.useSystemProxies=true"); } list.add("-jar"); list.add(FileUtil.getPathRunUpdate()); list.add(link); if (CliOptions.get().isJmemory()) { list.add(FileUtil.getPathRunMemory()); } else { list.add(FileUtil.getPathRunJar()); } return list; } public static boolean isPackageManager() { return new File(FileUtil.getPathPackageManager()).exists(); } public static String getPackageMaintainers() { return readProperties(FileUtil.getPathPackageManager()).getProperty("maintainers", null); } public static boolean getPackageNotifyUpdates() { return "true".equals(readProperties(FileUtil.getPathPackageManager()).getProperty("notifyUpdates", "").toLowerCase()); } private static Properties readProperties(String filename) { Properties properties = new Properties(); FileInputStream inputStream = null; try { inputStream = new FileInputStream(new File(filename)); properties.load(inputStream); } catch (IOException ex) { //No problem } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException ex) { //No problem } } } return properties; //Never null } private boolean downloadUpdater() { DataGetter dataGetter = new DataGetter(); Getter getter = new Getter(); String checksum = getter.get(UPDATE+".md5"); return dataGetter.get(UPDATE, new File(FileUtil.getPathRunUpdate()), checksum); } private static class Getter { protected String get(File file) { try { return get(new FileReader(file)); } catch (FileNotFoundException ex) { return null; } } protected String get(String link) { try { URL url = new URL(link); return get(new InputStreamReader(url.openStream())); } catch (MalformedURLException e) { return null; } catch (IOException ex) { return null; } } protected String get(Reader reader) { StringBuilder builder = new StringBuilder(); try { BufferedReader in = new BufferedReader(reader); String str; while ((str = in.readLine()) != null) { builder.append(str); } return builder.toString(); } catch (MalformedURLException e) { return null; } catch (IOException e) { return null; } finally { if (reader != null) { try { reader.close(); } catch (IOException ex) { //I give up... } } } } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/online/ZkillboardPricesHistoryGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.online; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; import com.google.gson.reflect.TypeToken; import java.io.IOException; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import net.nikr.eve.jeveasset.Program; import okhttp3.Call; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.logging.HttpLoggingInterceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ZkillboardPricesHistoryGetter { private static final Logger LOG = LoggerFactory.getLogger(ZkillboardPricesHistoryGetter.class); private static final long RATE_LIMIT_MS = 1010; private static final ExecutorService THREAD_POOL = Executors.newSingleThreadExecutor(); private static final Gson GSON = new GsonBuilder().create(); private static Long wait = null; private static Long ended = null; /** * HttpLoggingInterceptor */ private static final HttpLoggingInterceptor HTTP_LOGGING_INTERCEPTOR = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { @Override public void log(String string) { LOG.debug(string); } }); /** * HTTP Client */ private final OkHttpClient client; private static ZkillboardPricesHistoryGetter getter; private ZkillboardPricesHistoryGetter() { if (LOG.isDebugEnabled()) { client = new OkHttpClient().newBuilder() .addNetworkInterceptor(HTTP_LOGGING_INTERCEPTOR) .build(); HTTP_LOGGING_INTERCEPTOR.setLevel(HttpLoggingInterceptor.Level.BASIC); } else { client = new OkHttpClient().newBuilder().build(); } } public static Map getPriceHistory(int TypeID) { if (getter == null) { getter = new ZkillboardPricesHistoryGetter(); } return getter.update(TypeID); } private Map update(int TypeID) { Future> future = THREAD_POOL.submit(new PriceHistoryUpdate(TypeID)); try { return future.get(); } catch (InterruptedException ex) { LOG.error(ex.getMessage(), ex); } catch (ExecutionException ex) { LOG.error(ex.getMessage(), ex); } return null; //Failed } private class PriceHistoryUpdate implements Callable> { private final int typeID; public PriceHistoryUpdate(int typeID) { this.typeID = typeID; } @Override public Map call() throws Exception { if (wait != null && ended != null && System.currentTimeMillis() < (ended + wait)) { LOG.info("Waiting: " + (wait) + "ms"); Thread.sleep(wait); } long start = System.currentTimeMillis(); Map results = null; try { results = GSON.fromJson(getCall(typeID).execute().body().string(), new TypeToken>() {}.getType()); if (results == null) { LOG.error("Error fetching price", new Exception("results is null")); } } catch (IllegalArgumentException | IOException | JsonParseException ex) { LOG.error("Error fetching price", ex); } long duration = System.currentTimeMillis() - start; LOG.info("Completed in " + duration + "ms"); if (duration < RATE_LIMIT_MS) { wait = (RATE_LIMIT_MS - duration); ended = System.currentTimeMillis(); } else { wait = null; ended = null; } if (results != null) { results.remove("typeID"); results.remove("currentPrice"); } return results; } public Call getCall(Integer typeID) { Request.Builder request = new Request.Builder() .url("https://zkillboard.com/api/prices/" + typeID+ "/") .addHeader("User-Agent", Program.PROGRAM_USER_AGENT); return client.newCall(request.build()); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/shared/AbstractGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.Callable; import java.util.concurrent.Future; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.Updatable; import net.nikr.eve.jeveasset.io.shared.ThreadWoker.TaskCancelledException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AbstractGetter implements Runnable { private static final Logger LOG = LoggerFactory.getLogger(AbstractGetter.class); private static final long NEXT_UPDATE_ADDED_TIME = 30L * 1000L; //30 seconds protected static final int NO_RETRIES = 0; protected enum TaskType { ACCOUNT_BALANCE("Account Balance"), ASSETS("Assets"), BLUEPRINTS("Blueprints"), CONTRACTS("Contracts"), CLONES("Clones"), CONTRACT_ITEMS("Contract Items"), CONTRACT_PRICES("Contract Prices"), DIVISIONS("Division Names"), INDUSTRY_JOBS("Industry Jobs"), ITEM_TYPES("Item Types"), JOURNAL("Journal"), LOCATIONS("Locations"), MARKET_ORDERS("Market Orders"), MINING("Mining"), PUBLIC_MARKET_ORDERS("Public Market Orders"), OWNER("Account"), OWNER_ID_TO_NAME("IDs to Names"), FACTION_WARFARE("Faction Warfare"), PLANETARY_INTERACTION("Planetary Assets"), SHIP("Active Ship"), STRUCTURES("Structures"), TRANSACTIONS("Transactions"), SKILLS("Skills"), MANUFACTURING_PRICES("Manufacturing Prices"), LOYALTY_POINTS("Loyalty Points"), NPC_STANDING("NPC Standing"), ; private final String taskName; private TaskType(String taskName) { this.taskName = taskName; } public String getTaskName() { return taskName; } } private final UpdateTask updateTask; private final boolean forceUpdate; private final boolean disabled; private final boolean wait; private final String taskName; private final String apiName; protected final O owner; private String error = null; public AbstractGetter(UpdateTask updateTask, O owner, boolean forceUpdate, Date nextUpdate, TaskType taskType, String apiName) { this.updateTask = updateTask; this.owner = owner; this.forceUpdate = forceUpdate; this.disabled = !forceUpdate && owner != null && !owner.isShowOwner(); this.wait = !forceUpdate && !Updatable.isUpdatable(nextUpdate); if (taskType == null) { taskName = "Unknown"; } else { taskName = taskType.getTaskName(); } //this.taskName = taskType; this.apiName = apiName; } public void start() { ThreadWoker.start(updateTask, Collections.singletonList(this)); } public final synchronized boolean hasError() { return error != null; } public final synchronized String getError() { return error; } public final synchronized void setError(String error) { this.error = error; } /** * NOT THREAD SAFE! * use setNextUpdateSafe(Date date) * @param date */ protected abstract void setNextUpdate(Date date); protected abstract boolean haveAccess(); protected synchronized void setExpires(Map> headers) { Date expires = getHeaderDate(headers, "expires"); setNextUpdateInner(expires); } protected synchronized void setNextUpdateInner(Date date) { if (date != null) { date = new Date(date.getTime() + NEXT_UPDATE_ADDED_TIME); setNextUpdate(date); } } protected final boolean canUpdate() { //Silently ignore disabled owners if (disabled) { logInfo(null, "Owner disabled"); return false; } //Check API cache time if (wait) { addInfo("NOT ALLOWED YET", "Update skipped: Waiting for cache to expire.\r\n(Updatable again after cache expires)"); return false; } //Check if the owner have access to the endpoint if (owner != null && !haveAccess()) { //Silent return false; } return true; } protected final boolean isForceUpdate() { return forceUpdate; } protected interface Updater { public R update() throws E; public String getStatus(); public int getMaxRetries(); } protected final void pause() { if (updateTask != null) { updateTask.pause(); //Pause } } protected final void setProgress(final float progressEnd, final float progressNow, final int minimum, final int maximum) { if (updateTask != null) { updateTask.setTaskProgress(progressEnd, progressNow, minimum, maximum); } } protected final List> startSubThreads(Collection> updaters) throws InterruptedException { return ThreadWoker.startReturn(updateTask, updaters); } protected final List> startSubThreads(Collection> updaters, boolean updateProgress) throws InterruptedException { return ThreadWoker.startReturn(updateTask, updaters, updateProgress); } protected final void checkCancelled() { if (updateTask != null && updateTask.isCancelled()) { throw new TaskCancelledException(); } } protected final void addError(String logMsg, String taskMsg) { addError(logMsg, taskMsg, null); } protected final void addError(Object logMsg, Object taskMsg, Throwable ex) { logError(logMsg, taskMsg, ex); if (updateTask != null && taskMsg != null) { updateTask.addError(buildLogID(), taskMsg.toString()); } } protected final void addWarning(String logMsg, String taskMsg) { addWarning(logMsg, taskMsg, null); } protected final void addWarning(Object logMsg, Object taskMsg, Throwable ex) { logWarn(logMsg, taskMsg, ex); if (updateTask != null && taskMsg != null) { updateTask.addWarning(buildLogID(), taskMsg.toString()); } } protected final void addInfo(String logMsg, String taskMsg) { addInfo(logMsg, taskMsg, null); } protected final void addInfo(Object logMsg, Object taskMsg, Throwable ex) { logInfo(logMsg, taskMsg, ex); if (updateTask != null && taskMsg != null) { updateTask.addInfo(buildLogID(), taskMsg.toString()); } } private String buildLogID() { StringBuilder ownerBuilder = new StringBuilder(); ownerBuilder.append(apiName); ownerBuilder.append(" > "); ownerBuilder.append(taskName); if (owner != null) { ownerBuilder.append(" > "); ownerBuilder.append(owner.getOwnerName()); } return ownerBuilder.toString(); } protected final void logError(Object logMsg, Object taskMsg) { logError(logMsg, taskMsg, null); } protected final void logError(Object logMsg, Object taskMsg, Throwable ex) { String e = getLog(logMsg); setError(e); if (ex != null) { LOG.error(e, ex); } else { LOG.error(e); } } protected final void logWarn(Object logMsg, Object taskMsg) { logWarn(logMsg, taskMsg, null); } protected final void logWarn(Object logMsg, Object taskMsg, Throwable ex) { String e = getLog(logMsg); if (ex != null) { LOG.warn(e, ex); } else { LOG.warn(e); } } protected final void logInfo(Object logMsg, Object taskMsg) { logInfo(logMsg, taskMsg, null); } protected final void logInfo(Object logMsg, Object taskMsg, Throwable ex) { String e = getLog(logMsg); if (ex != null) { LOG.info(e, ex); } else { LOG.info(e); } } protected final String getLog(Object logMsg) { StringBuilder builder = new StringBuilder(); builder.append(apiName); builder.append(" "); builder.append(taskName); builder.append(" failed to update for: "); if (owner != null) { builder.append(" > "); builder.append(owner.getOwnerName()); } if (logMsg != null) { builder.append(" ERROR: "); builder.append(logMsg); } return builder.toString(); } protected final void logInfo(String update, String msg) { StringBuilder builder = new StringBuilder(); if (msg != null) { builder.append(msg); builder.append(":"); } builder.append(" "); builder.append(apiName); builder.append(" > "); builder.append(taskName); if (owner != null) { builder.append(" > "); builder.append(owner.getOwnerName()); } if (update != null) { builder.append(" ("); builder.append(update); builder.append(")"); } LOG.info(builder.toString()); } protected final List> splitList(Collection list, final int L) { return splitList(new ArrayList<>(list), L); } private List> splitList(List list, final int L) { List> parts = new ArrayList<>(); final int N = list.size(); for (int i = 0; i < N; i += L) { parts.add(new ArrayList<>(list.subList(i, Math.min(N, i + L)))); } return parts; } protected final List> splitSet(Collection list, final int L) { return splitSet(new ArrayList<>(list), L); } private List> splitSet(List list, final int L) { List> parts = new ArrayList<>(); final int N = list.size(); for (int i = 0; i < N; i += L) { parts.add(new HashSet<>(list.subList(i, Math.min(N, i + L)))); } return parts; } protected final Map getIDs(OwnerType owner) { Map itemMap = new HashMap<>(); ArrayList assets; synchronized(owner) { assets = new ArrayList<>(owner.getAssets()); } addItemIDs(itemMap, assets); return itemMap; } private void addItemIDs(Map itemIDs, List assets) { for (MyAsset asset : assets) { if ((asset.getItem().isContainer() || asset.getItem().getGroup().equals(Item.GROUP_BIOMASS) || asset.getItem().getCategory().equals(Item.CATEGORY_DEPLOYABLE) || asset.getItem().isShip() || asset.getItem().getCategory().equals(Item.CATEGORY_STRUCTURE)) && asset.isSingleton()) { itemIDs.put(asset.getItemID(), asset); } addItemIDs(itemIDs, asset.getAssets()); } } protected static final Integer getHeaderInteger(Map> responseHeaders, String headerName) { String errorResetHeader = getHeader(responseHeaders, headerName); if (errorResetHeader != null) { try { return Integer.valueOf(errorResetHeader); } catch (NumberFormatException ex) { //No problem } } return null; } protected static final Date getHeaderDate(Map> responseHeaders, String headerName) { String header = getHeader(responseHeaders, headerName); if (header != null) { return Formatter.parseExpireDate(header); } return null; } protected static final Date getHeaderExpires(Map> responseHeaders) { String header = getHeader(responseHeaders, "expires"); if (header != null) { return Formatter.parseExpireDate(header); } return null; } protected static final String getHeader(Map> responseHeaders, String headerName) { if (responseHeaders != null) { Map> caseInsensitiveHeaders = new TreeMap<>(StringComparators.CASE_INSENSITIVE); caseInsensitiveHeaders.putAll(responseHeaders); List headers = caseInsensitiveHeaders.get(headerName.toLowerCase()); if (headers != null && !headers.isEmpty()) { String header = headers.get(0); if (header != null && !header.isEmpty()) { return header; } } } return null; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/shared/AccountAdder.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; public interface AccountAdder { public boolean hasError(); public boolean isPrivilegesLimited(); public boolean isPrivilegesInvalid(); public boolean isWrongEntry(); public String getError(); public boolean isInvalid(); } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/shared/AccountAdderAdapter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; public class AccountAdderAdapter implements AccountAdder { @Override public boolean hasError() { return false; } @Override public boolean isPrivilegesLimited() { return false; } @Override public boolean isPrivilegesInvalid() { return false; } @Override public boolean isWrongEntry() { return false; } @Override public String getError() { return null; } @Override public boolean isInvalid() { return false; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/shared/ApiIdConverter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import net.nikr.eve.jeveasset.data.api.accounts.SimpleOwner; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType; import static net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType.ALLIANCE_ID; import static net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType.CHARACTER_ID; import static net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType.CONTRACT_ID; import static net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType.CORPORATION_ID; import static net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType.EVE_SYSTEM; import static net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType.INDUSTRY_JOB_ID; import static net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType.MARKET_TRANSACTION_ID; import static net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType.PLANET_ID; import static net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType.STATION_ID; import static net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType.STRUCTURE_ID; import static net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType.SYSTEM_ID; import static net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType.TYPE_ID; import net.nikr.eve.jeveasset.data.sde.Agent; import net.nikr.eve.jeveasset.data.sde.IndustryMaterial; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.ItemFlag; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.NpcCorporation; import net.nikr.eve.jeveasset.data.sde.ReprocessedMaterial; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.Citadel; import net.nikr.eve.jeveasset.data.settings.Citadel.CitadelSource; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingFacility; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingRigs; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ReactionRigs; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingSecurity; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ReactionSecurity; import net.nikr.eve.jeveasset.data.settings.PriceData; import net.nikr.eve.jeveasset.data.settings.ReprocessSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.io.esi.EsiItemsGetter; import net.nikr.eve.jeveasset.io.local.ItemsWriter; import net.nikr.eve.jeveasset.io.online.CitadelGetter; import net.troja.eve.esi.model.MoonResponse; import net.troja.eve.esi.model.PlanetResponse; import net.troja.eve.esi.model.StructureResponse; public final class ApiIdConverter { private ApiIdConverter() { } private static final String EMPTY_STRING = ""; private static final String UNKNOWN_FLAG = "Unknown"; private static final ConcurrentMap ITEM_DOWNLOAD_LOCKS = new ConcurrentHashMap<>(); private static final ExecutorService ITEM_DOWNLOAD_THREAD_POOL = Executors.newFixedThreadPool(ThreadWoker.MAIN_THREADS); private static boolean update = false; private enum PriceType { ITEM, REPROCESSED, MANUFACTURING } /* public static String flag(final int flag, final MyAsset parentAsset) { ItemFlag itemFlag = StaticData.get().getItemFlags().get(flag); if (itemFlag != null) { if (parentAsset != null && !parentAsset.getFlag().isEmpty()) { return parentAsset.getFlag() + " > " + itemFlag.getFlagName(); } else { return itemFlag.getFlagName(); } } return "!" + flag; } */ public static ItemFlag getFlag(final int flag) { ItemFlag itemFlag = StaticData.get().getItemFlags().get(flag); if (itemFlag != null) { return itemFlag; } else { return new ItemFlag(flag, UNKNOWN_FLAG, UNKNOWN_FLAG); } } public static String getFlagName(String flagName) { switch (flagName) { case "CorpSAG1": return "1st Division"; case "CorpSAG2": return "2nd Division"; case "CorpSAG3": return "3rd Division"; case "CorpSAG4": return "4th Division"; case "CorpSAG5": return "5th Division"; case "CorpSAG6": return "6th Division"; case "CorpSAG7": return "7th Division"; default: return flagName; } } public static String getFlagName(ItemFlag itemFlag) { return getFlagName(itemFlag, null); } public static String getFlagName(ItemFlag itemFlag, SimpleOwner ownerType) { switch (itemFlag.getFlagID()) { case 62: return "Corporation Deliveries"; case 63: return itemFlag.getFlagName(); case 64: return itemFlag.getFlagName(); case 115: return getDivisionName(ownerType, 1); case 116: return getDivisionName(ownerType, 2); case 117: return getDivisionName(ownerType, 3); case 118: return getDivisionName(ownerType, 4); case 119: return getDivisionName(ownerType, 5); case 120: return getDivisionName(ownerType, 6); case 121: return getDivisionName(ownerType, 7); case 146: return "Junkyard Reprocessed"; case 147: return "Junkyard Trashed"; } if (itemFlag.getFlagText().toLowerCase().contains("slot")) { return getSlotName(itemFlag); } return itemFlag.getFlagText(); } private static String getDivisionName(SimpleOwner ownerType, int i) { final String division; switch (i) { case 1: division = "1st Division"; break; case 2: division = "2nd Division"; break; case 3: division = "3rd Division"; break; case 4: division = "4th Division"; break; case 5: division = "5th Division"; break; case 6: division = "6th Division"; break; case 7: division = "7th Division"; break; default: division = "Division " + 1; break; } String divisionName = null; if (ownerType != null) { divisionName = ownerType.getAssetDivisions().get(i); } if (divisionName == null || divisionName.isEmpty()) { return division; } else { return divisionName + " (" + division + ")"; } } private static String getSlotName(ItemFlag itemFlag) { String name = itemFlag.getFlagText(); name = name.replace(" power", ""); name = name.replace(" s", " S"); return name; } public static String getContext(MyJournal journal) { return getContext(journal.getContextType(), journal.getContextID()); } public static String getContext(final ContextType contextType, final Long contextID) { if (contextType == null || contextID == null) { return null; } switch (contextType) { case ALLIANCE_ID: case CHARACTER_ID: case CORPORATION_ID: return getOwnerName(contextID); case CONTRACT_ID: return General.get().journalContract(); case INDUSTRY_JOB_ID: return General.get().journalIndustryJob(); case MARKET_TRANSACTION_ID: if (contextID != 1) { return General.get().journalMarketTransaction(); } else { return General.get().journalSystemTransaction(); } case EVE_SYSTEM: case TYPE_ID: Item item = ApiIdConverter.getItem(contextID.intValue()); if (!item.isEmpty()) { return item.getTypeName(); } return null; case PLANET_ID: case STATION_ID: case SYSTEM_ID: case STRUCTURE_ID: MyLocation location = ApiIdConverter.getLocation(contextID); if (!location.isEmpty()) { return location.getLocation(); } return null; default: return null; } } /** * * @param typeID * @param isBlueprintCopy * @return PriceData for the type or PriceData.EMPTY (all zeros) */ public static PriceData getPriceData(final Integer typeID, final boolean isBlueprintCopy) { if (typeID == null) { return PriceData.EMPTY; } if (isBlueprintCopy) { return PriceData.EMPTY; } PriceData priceData = Settings.get().getPriceData().get(typeID); if (priceData == null) { return PriceData.EMPTY; } if (priceData.isEmpty()) { //No Price :( return PriceData.EMPTY; } return priceData; } public static double getPrice(final Integer typeID, final boolean isBlueprintCopy) { return getPriceType(typeID, isBlueprintCopy, PriceType.ITEM); } private static double getPriceReprocessed(final Integer typeID) { return getPriceType(typeID, false, PriceType.REPROCESSED); } private static double getPriceManufacturing(final Integer typeID) { return getPriceType(typeID, false, PriceType.MANUFACTURING); } private static double getPriceType(final Integer typeID, final boolean isBlueprintCopy, PriceType type) { if (typeID == null) { return 0; } UserItem userPrice; if (isBlueprintCopy) { //Blueprint Copy userPrice = Settings.get().getUserPrices().get(-typeID); } else { //All other userPrice = Settings.get().getUserPrices().get(typeID); } if (userPrice != null) { return userPrice.getValue(); } //Blueprint Copy (Default Zero) if (isBlueprintCopy) { return 0; } //Blueprints Base Price Item item = getItem(typeID); //Tech 1 if (item.isBlueprint()) { if (Settings.get().isBlueprintBasePriceTech1() && !item.getTypeName().toLowerCase().contains("ii")) { return item.getPriceBase(); } //Tech 2 if (Settings.get().isBlueprintBasePriceTech2() && item.getTypeName().toLowerCase().contains("ii")) { return item.getPriceBase(); } } //Manufacturing Price for non-market items if (!item.isMarketGroup() && Settings.get().isManufacturingDefault()) { return item.getPriceManufacturing(); } //Price data PriceData priceData = Settings.get().getPriceData().get(typeID); if (priceData != null && priceData.isEmpty()) { priceData = null; } if (type == PriceType.REPROCESSED) { return Settings.get().getPriceDataSettings().getDefaultPriceReprocessed(priceData); } else if (type == PriceType.MANUFACTURING) { return Settings.get().getPriceDataSettings().getDefaultPriceManufacturing(priceData); } else { return Settings.get().getPriceDataSettings().getDefaultPrice(priceData); } } /** * Calculate Manufacturing Price - This is expensive! * Use Item.getPriceManufacturing() to get the manufacturing price * @param item * @return */ public static double getPriceManufacturing(Item item) { return getPriceManufacturing(Settings.get().getManufacturingSettings(), item); } protected static double getPriceManufacturing(ManufacturingSettings manufacturingSettings, Item item) { //Installation Fee Double baseCost = manufacturingSettings.getPrices().get(item.getTypeID()); if (baseCost == null) { return 0; } int systemID = manufacturingSettings.getSystemID(); Float systemIndex = manufacturingSettings.getSystems().get(systemID); if (systemIndex == null) { return 0.1; } double installationFee = getManufacturingInstallationFee(manufacturingSettings, systemIndex, baseCost, item); //Materials Cost double materialCost = 0; Item blueprint = getItem(item.getBlueprintTypeID()); for (IndustryMaterial material : blueprint.getManufacturingMaterials()) { double quantity = getManufacturingQuantity(manufacturingSettings, material.getQuantity()); double price = getPriceManufacturing(material.getTypeID()); materialCost = materialCost + (price * quantity); } return installationFee + materialCost; } protected static double getManufacturingInstallationFee(ManufacturingSettings manufacturingSettings, Float systemIndex, Double baseCost, Item item) { //Installation Fee ManufacturingFacility facility = manufacturingSettings.getFacility(); double bonuses = percentToBonus(facility.getFeeBonus()); double tax = manufacturingSettings.getTax() / 100; double scc = 0.25 / 100; //TIF = EIV * ((SCI * bonuses) + FacilityTax + SCC + AlphaClone) //EIV: ME 0 quantity of inputs * adjusted price of inputs => baseCost //SCI: System Cost Index //Facility Tax: Fixed tax for NPC stations set to 0.25% or tax rate set by facility owner. //SCC: SCC surcharge, this is a fixed value and cannot be affected by anything //Bonuses: Any bonuses that are applicable //AlphaClone: Tax applicable to alpha clones, set at 0.25% (Just add to tax) return baseCost * ((systemIndex * bonuses) + tax + scc); } private static double getManufacturingQuantity(ManufacturingSettings manufacturingSettings, int quantity) { int me = manufacturingSettings.getMaterialEfficiency(); ManufacturingFacility facility = manufacturingSettings.getFacility(); ManufacturingRigs rigs = manufacturingSettings.getRigs(); ManufacturingSecurity security = manufacturingSettings.getSecurity(); return getManufacturingQuantity(quantity, me, facility, rigs, security, 1, true); } /** * * @param quantity * @param me * @param facility * @param rigs * @param security * @param runs * @param round * @return Can return less than 1 (one) */ public static double getManufacturingQuantity(int quantity, int me, ManufacturingFacility facility, ManufacturingRigs rigs, ManufacturingSecurity security, double runs, boolean round) { //base * ((100-ME)/100) * (EC modifier) * (EC Rig modifier)) return roundManufacturingQuantity(quantity * percentToBonus(me) * percentToBonus(facility.getMaterialBonus()) * rigToBonus(rigs, security), runs, round); } public static double getReactionQuantity(int quantity, ManufacturingSettings.ReactionRigs rigs, ManufacturingSettings.ReactionSecurity security, double runs, boolean round) { return roundManufacturingQuantity(quantity * rigToBonus(rigs, security), runs, round); } private static double roundManufacturingQuantity(double manufacturingQuantity, double runs, boolean round) { double quantity = Math.max(runs, manufacturingQuantity * runs); if (round) { return Math.ceil(quantity); } else { return quantity; } } private static double percentToBonus(double value) { return ((100.0 - value) / 100.0); } private static double rigToBonus(ManufacturingRigs rigs, ManufacturingSecurity security) { if (rigs == ManufacturingRigs.NONE) { return 1; } else { return percentToBonus(rigs.getMaterialBonus() * security.getRigBonus()); } } private static double rigToBonus(ReactionRigs rigs, ReactionSecurity security) { if (rigs == ReactionRigs.NONE) { return 1; } else { return percentToBonus(rigs.getMaterialBonus() * security.getRigBonus()); } } public static double getPriceReprocessed(Item item) { return getPriceReprocessed(item, false); } public static double getPriceReprocessedMax(Item item) { return getPriceReprocessed(item, true); } private static double getPriceReprocessed(Item item, boolean max) { double priceReprocessed = 0; int portionSize = 0; for (ReprocessedMaterial material : item.getReprocessedMaterial()) { //Calculate reprocessed price portionSize = material.getPortionSize(); double price = ApiIdConverter.getPriceReprocessed(material.getTypeID()); int count; if (max) { count = ReprocessSettings.getMax(material.getQuantity(), item.isOre()); } else { count = Settings.get().getReprocessSettings().getLeft(material.getQuantity(), item.isOre()); } priceReprocessed = priceReprocessed + (price * count); } if (priceReprocessed > 0 && portionSize > 0) { priceReprocessed = priceReprocessed / portionSize; } return priceReprocessed; } public static float getVolume(final Item item, final boolean packaged) { if (item != null) { if (packaged) { return item.getVolumePackaged(); } else { return item.getVolume(); } } return 0; } public static Item getItem(final Integer typeID) { if (typeID == null) { return new Item(0); } Item item = StaticData.get().getItems().get(typeID); if (item == null) { item = new Item(typeID); } return item; } public static void setUpdateItem(boolean update) { ApiIdConverter.update = update; } public static Item getItemUpdate(final Integer typeID) { return getItemUpdate(typeID, update); } public static Item getItemUpdate(final Integer typeID, boolean update) { if (!update) { return getItem(typeID); } if (typeID == null) { return new Item(0); } Item item = getUpdateItem(typeID); if (item != null) { return item; } else { return synchronizedDownloadItem(typeID); } } public static void updateItem(Integer typeID) { if (!update || typeID == null) { return; } Item item = getUpdateItem(typeID); if (item == null) { Thread thread = new Thread(new Runnable() { @Override public void run() { downloadItem(typeID); } }); thread.start(); } } private static Item getUpdateItem(final Integer typeID) { Item item = StaticData.get().getItems().get(typeID); if (item == null || (item.getVersion() != null && !item.getVersion().equals(EsiItemsGetter.ESI_ITEM_VERSION))) { //New ESI item version if (item != null && item.getVersion().startsWith(EsiItemsGetter.ESI_ITEM_EMPTY)) { String lastUpdated = item.getVersion().replace(EsiItemsGetter.ESI_ITEM_EMPTY, ""); String today = Formatter.dateOnly(Settings.getNow()); if (lastUpdated.equals(today)) { return item; } } return null; } return item; } protected static Item synchronizedDownloadItem(final Integer typeID) { ITEM_DOWNLOAD_LOCKS.putIfAbsent(typeID, new Object()); //Only download one item type at the time (Locks on typeID) synchronized(ITEM_DOWNLOAD_LOCKS.get(typeID)) { Item item = getUpdateItem(typeID); if (item != null) { //May have been downloaded while waiting for sync return item; } else { return downloadItem(typeID); } } } private static Item downloadItem(final Integer typeID) { //Only download one item at the time Item item = ThreadWoker.startReturn(ITEM_DOWNLOAD_THREAD_POOL, null, new DownloadItem(typeID)); if (item == null) { //Empty Item item = new Item(typeID, EsiItemsGetter.ESI_ITEM_EMPTY + Formatter.dateOnly(Settings.getNow())); } synchronized(StaticData.get().getItems()) { StaticData.get().getItems().put(typeID, item); //Add Item } ITEM_DOWNLOAD_LOCKS.remove(typeID); //Remove lock after download is completed if (ITEM_DOWNLOAD_LOCKS.isEmpty()) { //Save when the download queue is empty synchronized(StaticData.get().getItems()) { ItemsWriter.save(); //Save XML } } return item; } private static class DownloadItem implements Callable { private final Integer typeID; public DownloadItem(Integer typeID) { this.typeID = typeID; } @Override public Item call() throws Exception { EsiItemsGetter esiItemsGetter = new EsiItemsGetter(typeID); esiItemsGetter.run(); return esiItemsGetter.getItem(); } } public static String getOwnerName(final Integer ownerID) { if (ownerID == null) { return EMPTY_STRING; } else { return getOwnerName(Long.valueOf(ownerID)); } } public static Agent getAgent(final Integer agentID) { Agent agent = StaticData.get().getAgents().get(agentID); if (agent == null) { agent = new Agent(agentID); } return agent; } public static NpcCorporation getNpcCorporation(final Integer corporationID) { NpcCorporation npcCorporation = StaticData.get().getNpcCorporations().get(corporationID); if (npcCorporation == null) { npcCorporation = new NpcCorporation(corporationID); } return npcCorporation; } public static String getOwnerName(final Long ownerID) { if (ownerID == null || ownerID == 0) { //0 (zero) is valid, but, should return empty string return EMPTY_STRING; } String owner = Settings.get().getOwners().get(ownerID); if (owner != null) { return owner; } else { // OwnerIDs from the journal can be a system ID MyLocation location = getLocation(ownerID); if (!location.isEmpty()) { return location.getLocation(); } } return "!" + String.valueOf(ownerID); } public static boolean isLocationOK(final Long locationID) { return !getLocation(locationID, null).isEmpty(); } public static MyLocation getLocation(Integer locationID) { if (locationID == null) { return MyLocation.create(0); } else { return getLocation(Long.valueOf(locationID), null); } } public static MyLocation getLocation(Long locationID) { return getLocation(locationID, null); } public static MyLocation getLocation(final Long locationID, final MyAsset parentAsset) { if (locationID == null) { return MyLocation.create(0); } MyLocation location = StaticData.get().getLocation(locationID); if (location != null) { return location; } if (parentAsset != null) { location = parentAsset.getLocation(); if (location != null) { return location; } } location = CitadelGetter.get(locationID).toLocation(); if (location != null) { return location; } return MyLocation.create(locationID); } public static void addLocation(final Citadel citadel) { MyLocation location = citadel.toLocation(); if (location != null) { StaticData.get().addLocation(location); } } public static Citadel getCitadel(final StructureResponse response, final long locationID) { return new Citadel(locationID, response.getName(), response.getSolarSystemId(), false, true, CitadelSource.ESI_STRUCTURES); } public static Citadel getCitadel(PlanetResponse planet) { return new Citadel(planet.getPlanetId(), planet.getName(), planet.getSystemId(), false, false, CitadelSource.ESI_PLANET); } public static Citadel getCitadel(MoonResponse planet) { return new Citadel(planet.getMoonId(), planet.getName(), planet.getSystemId(), false, false, CitadelSource.ESI_MOON); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/shared/DataConverter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.accounts.SimpleOwner; import net.nikr.eve.jeveasset.data.api.my.MyAccountBalance; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyExtraction; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.api.my.MySkill; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.api.raw.RawAccountBalance; import net.nikr.eve.jeveasset.data.api.raw.RawAsset; import net.nikr.eve.jeveasset.data.api.raw.RawClone; import net.nikr.eve.jeveasset.data.api.raw.RawContract; import net.nikr.eve.jeveasset.data.api.raw.RawContractItem; import net.nikr.eve.jeveasset.data.api.raw.RawExtraction; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob; import net.nikr.eve.jeveasset.data.api.raw.RawJournal; import net.nikr.eve.jeveasset.data.api.raw.RawLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.Change; import net.nikr.eve.jeveasset.data.api.raw.RawMining; import net.nikr.eve.jeveasset.data.api.raw.RawNpcStanding; import net.nikr.eve.jeveasset.data.api.raw.RawSkill; import net.nikr.eve.jeveasset.data.api.raw.RawTransaction; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.io.local.profile.ProfileContracts; import net.nikr.eve.jeveasset.io.local.profile.ProfileDatabase; import net.nikr.eve.jeveasset.io.local.profile.ProfileIndustryJobs; import net.nikr.eve.jeveasset.io.local.profile.ProfileJournals; import net.nikr.eve.jeveasset.io.local.profile.ProfileMarketOrders; import net.nikr.eve.jeveasset.io.local.profile.ProfileMining; import net.nikr.eve.jeveasset.io.local.profile.ProfileTransactions; import net.nikr.eve.jeveasset.io.local.profile.ProfileConnectionData; public abstract class DataConverter { public static List assetIndustryJob(final Collection industryJobs, boolean includeManufacturing, boolean includeCopying) { List assets = new ArrayList<>(); for (MyIndustryJob industryJob : industryJobs) { if (industryJob.isNotDeliveredToAssets()) { //Blueprint if (industryJob.isRemovedFromAssets()) { MyAsset asset = new MyAsset(industryJob, false); assets.add(asset); } //Manufacturing Output if (includeManufacturing && industryJob.isManufacturing() && industryJob.getProductTypeID() != null) { MyAsset product = new MyAsset(industryJob, true); assets.add(product); } //Copy Output if (includeCopying && industryJob.isCopying()) { for (int i = 0; i < industryJob.getRuns(); i++) { MyAsset product = new MyAsset(industryJob, true); assets.add(product); } } } } return assets; } public static List assetMarketOrder(final Collection marketOrders, boolean includeSellOrders, boolean includeBuyOrders) { List assets = new ArrayList<>(); for (MyMarketOrder marketOrder : marketOrders) { if (marketOrder.isActive() && marketOrder.getVolumeRemain() > 0 && ((!marketOrder.isBuyOrder() && includeSellOrders) || (marketOrder.isBuyOrder() && includeBuyOrders))) { MyAsset asset = new MyAsset(marketOrder); assets.add(asset); } } return assets; } public static List assetContracts(final Collection contractItems, final Map owners, boolean includeSellContracts, boolean includeBuyContracts) { List list = new ArrayList<>(); //Only includes issuer buying and selling items //TODO Could add issuer bought/sold and acceptor bought/sold items to the assets list for (MyContractItem contractItem : contractItems) { SimpleOwner issuer; if (contractItem.getContract().isForCorp()) { issuer = new SimpleOwner() { @Override public long getOwnerID() { if (Settings.get().isAssetsContractsOwnerCorporation() ||Settings.get().isAssetsContractsOwnerBoth()) { return contractItem.getContract().getIssuerCorpID(); } else { return contractItem.getContract().getIssuerID(); } } @Override public String getOwnerName() { if (Settings.get().isAssetsContractsOwnerCorporation()) { return ApiIdConverter.getOwnerName(contractItem.getContract().getIssuerCorpID()); } else if (Settings.get().isAssetsContractsOwnerBoth()) { String characterName = ApiIdConverter.getOwnerName(contractItem.getContract().getIssuerID()); String corporationName = ApiIdConverter.getOwnerName(contractItem.getContract().getIssuerCorpID()); return GuiShared.get().contractCorporationOwner(corporationName, characterName); } else { //Character return ApiIdConverter.getOwnerName(contractItem.getContract().getIssuerID()); } } @Override public boolean isCorporation() { return Settings.get().isAssetsContractsOwnerCorporation() || Settings.get().isAssetsContractsOwnerBoth(); } }; } else { issuer = owners.get(contractItem.getContract().getIssuerID()); } if (contractItem.getContract().isOpen() //Not completed && issuer != null //Owned && contractItem.getContract().isItemContract() //Not courier && ((contractItem.isIncluded() && includeSellContracts) //Sell || (!contractItem.isIncluded() && includeBuyContracts))) { //Buy MyAsset asset = new MyAsset(contractItem, issuer); list.add(asset); } } return list; } public static List assetCloneImplants(final Map> clones, boolean includeJumpClones, boolean includePluggedInImplants) { List assets = new ArrayList<>(); for (Map.Entry> entry : clones.entrySet()) { OwnerType owner = entry.getKey(); for (RawClone clone : entry.getValue()) { List parents = new ArrayList<>(); MyAsset jumpClone = new MyAsset(clone, owner); parents.add(jumpClone); if (includeJumpClones) { assets.add(jumpClone); } if (includePluggedInImplants) { for (Integer implantTypeID : clone.getImplants()) { MyAsset implant = new MyAsset(clone, implantTypeID, owner, parents); jumpClone.addAsset(implant); if (!includeJumpClones) { assets.add(implant); } } } } } return assets; } protected static List convertRawAccountBalance(List rawAccountBalances, OwnerType owner) { List accountBalances = new ArrayList<>(); for (RawAccountBalance rawAccountBalance : rawAccountBalances) { //Lookup by ItemID accountBalances.add(toMyAccountBalance(rawAccountBalance, owner)); } return accountBalances; } public static MyAccountBalance toMyAccountBalance(RawAccountBalance rawAccountBalance, OwnerType owner) { return new MyAccountBalance(rawAccountBalance, owner); } public static List toRawAssets(List rawAssets, OwnerType owner) { return convertRawAssets(rawAssets, owner); } protected static List convertRawAssets(List rawAssets, OwnerType owner) { List assets = new ArrayList<>(); Map lookup = new HashMap<>(); Map> childMap = new HashMap<>(); List root = new ArrayList<>(); for (RawAsset rawAsset : rawAssets) { //Lookup by ItemID lookup.put(rawAsset.getItemID(), rawAsset); childMap.put(rawAsset.getItemID(), new ArrayList<>()); } for (RawAsset rawAsset : rawAssets) { //Create child map RawAsset parent = lookup.get(rawAsset.getLocationID()); if (parent != null) { //Is Child Asset childMap.get(parent.getItemID()).add(rawAsset); } else { //Is Root Asset root.add(rawAsset); } } for (RawAsset rawAsset : root) { MyAsset asset = deepAsset(rawAsset, owner, childMap, null); if (asset != null) { assets.add(asset); } } return assets; } private static MyAsset deepAsset(RawAsset rawAsset, OwnerType owner, Map> childMap, MyAsset parent) { List parents = new ArrayList<>(); if (parent != null) { parents.addAll(parent.getParents()); parents.add(parent); } MyAsset asset = toMyAsset(rawAsset, owner, parents); if (asset != null) { for (RawAsset child : childMap.get(rawAsset.getItemID())) { MyAsset childAsset = deepAsset(child, owner, childMap, asset); if (childAsset != null) { asset.addAsset(childAsset); } } } return asset; } public static MyAsset toMyAsset(RawAsset rawAsset, OwnerType owner, List parents) { Item item = ApiIdConverter.getItemUpdate(rawAsset.getTypeID()); if (!parents.isEmpty()) { //Update locationID from ItemID to locationID MyAsset rootAsset = parents.get(0); rawAsset.setLocationID(rootAsset.getLocationID()); } return new MyAsset(rawAsset, item, owner, parents); } protected static Map> convertRawContracts(List rawContracts, OwnerType owner, boolean saveHistory) { Map> contracts = new HashMap<>(); for (RawContract rawContract : rawContracts) { MyContract contract = toMyContract(rawContract); List contractItems = owner.getContracts().get(contract); //Load ContractItems if (contractItems == null) { //New contractItems = new ArrayList<>(); } else { //Old, update contract items for (MyContractItem contractItem : contractItems) { contractItem.setContract(contract); } } contracts.put(contract, contractItems); } if (saveHistory) { Set update = new HashSet<>(contracts.keySet()); //Contracts in esi needs to be update for (Map.Entry> entry : owner.getContracts().entrySet()) { MyContract contract = entry.getKey(); if (!contracts.containsKey(contract)) { if(contract.archive()) { update.add(contract); //Archived contracts needs to be update } contracts.put(contract, entry.getValue()); } } ProfileDatabase.update(new ProfileConnectionData(new HashSet<>(update)) { @Override public void update(Connection connection, Collection data) throws SQLException { ProfileContracts.updateContracts(connection, owner.getAccountID(), data); } }); } return contracts; } protected static Map> convertRawContractItems(Map> rawContractItems, OwnerType owner, boolean saveHistory) { Map> contracts = new HashMap<>(); for (Map.Entry> entry : rawContractItems.entrySet()) { List contractItems = new ArrayList<>(); for (RawContractItem response : entry.getValue()) { contractItems.add(toMyContractItem(response, entry.getKey())); } contracts.put(entry.getKey(), contractItems); } if (saveHistory) { ProfileDatabase.update(new ProfileConnectionData>(contracts.values()) { @Override public void update(Connection connection, Collection> data) throws SQLException { ProfileContracts.updateContractItems(connection, data); } }); for (Map.Entry> entry : owner.getContracts().entrySet()) { contracts.putIfAbsent(entry.getKey(), entry.getValue()); } } return contracts; } public static MyContract toMyContract(RawContract rawContract) { return new MyContract(rawContract); } public static MyContractItem toMyContractItem(RawContractItem rawContractItem, MyContract contract) { Item item = ApiIdConverter.getItemUpdate(rawContractItem.getTypeID()); return new MyContractItem(rawContractItem, contract, item); } protected static Set convertRawIndustryJobs(List rawIndustryJobs, OwnerType owner, boolean saveHistory) { Set industryJobs = new HashSet<>(); for (RawIndustryJob rawIndustryJob : rawIndustryJobs) { industryJobs.add(toMyIndustryJob(rawIndustryJob, owner)); } if (saveHistory) { Set update = new HashSet<>(industryJobs); //Industry jobs in esi needs to be update for (MyIndustryJob industryJob : owner.getIndustryJobs()) { if (industryJob.archive()) { update.add(industryJob); //Archived industry jobs needs to be update } industryJobs.add(industryJob); } ProfileDatabase.update(new ProfileConnectionData(update) { @Override public void update(Connection connection, Collection data) throws SQLException { ProfileIndustryJobs.updateIndustryJobs(connection, owner.getAccountID(), data); } }); } return industryJobs; } public static MyIndustryJob toMyIndustryJob(RawIndustryJob rawIndustryJob, OwnerType owner) { Item item = ApiIdConverter.getItemUpdate(rawIndustryJob.getBlueprintTypeID()); Item output = ApiIdConverter.getItemUpdate(rawIndustryJob.getProductTypeID()); return new MyIndustryJob(rawIndustryJob, item, output, owner); } protected static Set convertRawJournals(List rawJournals, OwnerType owner, boolean saveHistory) { Set journals = new HashSet<>(); for (RawJournal rawJournal : rawJournals) { journals.add(toMyJournal(rawJournal, owner)); } if (saveHistory) { ProfileDatabase.update(new ProfileConnectionData(journals) { @Override public void update(Connection connection, Collection data) throws SQLException { ProfileJournals.updateJournals(connection, owner.getAccountID(), data); } }); journals.addAll(owner.getJournal()); } return journals; } public static MyJournal toMyJournal(RawJournal rawJournal, OwnerType owner) { return new MyJournal(rawJournal, owner); } protected static Set convertRawMarketOrders(List rawMarketOrders, OwnerType owner, boolean saveHistory) { Set marketOrders = new HashSet<>(); Map> changed = new HashMap<>(); for (MyMarketOrder marketOrder : owner.getMarketOrders()) { changed.put(marketOrder.getOrderID(), marketOrder.getChanges()); } for (RawMarketOrder rawMarketOrder : rawMarketOrders) { MyMarketOrder marketOrder = toMyMarketOrder(rawMarketOrder, owner); marketOrders.add(marketOrder); marketOrder.addChanges(changed.get(marketOrder.getOrderID())); } if (saveHistory) { Set update = new HashSet<>(marketOrders); //Market orders in esi needs to be update for (MyMarketOrder marketOrder : owner.getMarketOrders()) { if (marketOrder.archive()) { update.add(marketOrder); //Archived market orders needs to be update } marketOrders.add(marketOrder); } ProfileDatabase.update(new ProfileConnectionData(update) { @Override public void update(Connection connection, Collection data) throws SQLException { ProfileMarketOrders.updateMarketOrders(connection, owner.getAccountID(), data); } }); } return marketOrders; } public static MyMarketOrder toMyMarketOrder(RawMarketOrder rawMarketOrder, OwnerType owner) { Item item = ApiIdConverter.getItemUpdate(rawMarketOrder.getTypeID()); return new MyMarketOrder(rawMarketOrder, item, owner); } protected static Set convertRawTransactions(List rawTransactions, OwnerType owner, boolean saveHistory) { Set transactions = new HashSet<>(); for (RawTransaction rawTransaction : rawTransactions) { transactions.add(toMyTransaction(rawTransaction, owner)); } if (saveHistory) { ProfileDatabase.update(new ProfileConnectionData(transactions) { @Override public void update(Connection connection, Collection data) throws SQLException { ProfileTransactions.updateTransactions(connection, owner.getAccountID(), data); } }); transactions.addAll(owner.getTransactions()); } return transactions; } public static MyTransaction toMyTransaction(RawTransaction rawTransaction, OwnerType owner) { Item item = ApiIdConverter.getItemUpdate(rawTransaction.getTypeID()); return new MyTransaction(rawTransaction, item, owner); } protected static List convertRawSkills(List rawSkills, OwnerType owner) { List skills = new ArrayList<>(); for (RawSkill rawSkill : rawSkills) { skills.add(toMySkill(rawSkill, owner)); } return skills; } public static MySkill toMySkill(RawSkill rawSkill, OwnerType owner) { Item item = ApiIdConverter.getItemUpdate(rawSkill.getTypeID()); return new MySkill(rawSkill, item, owner.getOwnerName()); } protected static Set convertRawMining(List rawMinings, OwnerType owner, boolean saveHistory) { Set minings = new HashSet<>(); for (RawMining rawMining : rawMinings) { minings.add(toMyMining(rawMining)); } if (saveHistory) { ProfileDatabase.update(new ProfileConnectionData(minings) { @Override public void update(Connection connection, Collection data) throws SQLException { ProfileMining.updateMinings(connection, owner.getAccountID(), data); } }); minings.addAll(owner.getMining()); } return minings; } public static MyMining toMyMining(RawMining rawMining) { Item item = ApiIdConverter.getItemUpdate(rawMining.getTypeID()); MyLocation location = ApiIdConverter.getLocation(rawMining.getLocationID()); return new MyMining(rawMining, item, location); } protected static Set convertRawExtraction(List rawExtractions, OwnerType owner, boolean saveHistory) { Set extractions = new HashSet<>(); for (RawExtraction rawMining : rawExtractions) { extractions.add(toMyExtraction(rawMining)); } if (saveHistory) { ProfileDatabase.update(new ProfileConnectionData(new ArrayList<>(extractions)) { @Override public void update(Connection connection, Collection data) throws SQLException { ProfileMining.updateExtractions(connection, owner.getAccountID(), data); } }); extractions.addAll(owner.getExtractions()); } return extractions; } public static MyExtraction toMyExtraction(RawExtraction rawExtraction) { MyLocation moon = ApiIdConverter.getLocation(rawExtraction.getMoonID()); return new MyExtraction(rawExtraction, moon); } protected static Set convertMyLoyaltyPoints(Set rawLoyaltyPointses, OwnerType owner) { Set loyaltyPointses = new HashSet<>(); for (RawLoyaltyPoints rawLoyaltyPoints : rawLoyaltyPointses) { loyaltyPointses.add(toMyLoyaltyPoints(rawLoyaltyPoints, owner)); } return loyaltyPointses; } public static MyLoyaltyPoints toMyLoyaltyPoints(RawLoyaltyPoints rawLoyaltyPoints, OwnerType owner) { return new MyLoyaltyPoints(rawLoyaltyPoints, owner); } protected static Set convertMyNpcStanding(Set rawNpcStandings, OwnerType owner) { Set npcStandings = new HashSet<>(); for (RawNpcStanding rawNpcStanding : rawNpcStandings) { npcStandings.add(toMyNpcStanding(rawNpcStanding, owner)); } return npcStandings; } public static MyNpcStanding toMyNpcStanding(RawNpcStanding rawNpcStanding, OwnerType owner) { return new MyNpcStanding(rawNpcStanding, owner); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/shared/DesktopUtil.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.awt.Desktop; import java.awt.Window; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.Set; import javax.swing.JEditorPane; import javax.swing.JOptionPane; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.shared.CopyHandler; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog; import net.nikr.eve.jeveasset.i18n.GuiShared; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class DesktopUtil { private static final Logger LOG = LoggerFactory.getLogger(DesktopUtil.class); private DesktopUtil() { } public static HyperlinkListener getHyperlinkListener(Window window) { return new LinkListener(window); } private static boolean isSupported(final Desktop.Action action) { if (Desktop.isDesktopSupported()) { Desktop desktop = Desktop.getDesktop(); if (desktop.isSupported(action)) { return true; } } return false; } public static void open(final String filename, final Program program) { File file = new File(filename); LOG.info("Opening: {}", file.getName()); if (isSupported(Desktop.Action.OPEN)) { Desktop desktop = Desktop.getDesktop(); try { desktop.open(file); return; } catch (IOException ex) { LOG.warn(" Opening Failed: {}", ex.getMessage()); } } else { LOG.warn(" Opening failed"); } JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), "Could not open " + file.getName(), "Open File", JOptionPane.PLAIN_MESSAGE); } /** * Open link to jEveAssets manual * @param helpLink * @param window */ public static void browse(HelpLink helpLink, final Window window) { if (helpLink == null) { return; } int returnValue = JOptionPane.showConfirmDialog(window, GuiShared.get().helpOpenManual(helpLink.getTitle()), GuiShared.get().helpOpenManualTitle(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if (returnValue != JOptionPane.OK_OPTION) { return; } browse(helpLink.getLink(), window); } /** * Open a single link * @param url * @param program */ public static void browse(final String url, Program program) { browse(url, getWindow(program)); } /** * Open a single link * @param url * @param window * @return */ public static boolean browse(final String url, final Window window) { if (url == null) { return false; } if (isSupported(Desktop.Action.BROWSE)) { if (browse(url)) { return true; } else { JOptionPane.showMessageDialog(window, "Could not browse to:\r\n" + url, "Browse", JOptionPane.PLAIN_MESSAGE); return false; } } else { int value = JOptionPane.showConfirmDialog(window, "Automatic browsing is not support on this platform.\r\n" + "1) Press OK to copy the URL into your clipboard.\r\n" + "2) Open your browser and paste the url into the address line.", "Browse", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if (value == JOptionPane.OK_OPTION) { CopyHandler.toClipboard(url); return true; } else { return false; } } } /** * Open multiple links * @param urls * @param program */ public static void browse(final Set urls, Program program) { browse(urls, getWindow(program)); } /** * Open multiple links * @param urls * @param window */ private static void browse(final Set urls, Window window) { if (urls == null || urls.isEmpty()) { return; } if (isSupported(Desktop.Action.BROWSE)) { if (urls.size() > 1) { int value = JOptionPane.showConfirmDialog(window, GuiShared.get().openLinks(urls.size()), GuiShared.get().openLinksTitle(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if(value != JOptionPane.OK_OPTION) { return; } } for (String url : urls) { if (!browse(url)) { JOptionPane.showMessageDialog(window, "Could not browse to:\r\n" + url, "Browse", JOptionPane.PLAIN_MESSAGE); break; } } } else { StringBuilder builder = new StringBuilder(); for (String url : urls) { builder.append(url); builder.append("\r\n"); } JOptionPane.showMessageDialog(window, "Automatic browsing is not support on this platform.\r\n" + "You need to copy and paste the URLs the into your browser.\r\n" + "Press OK to show the URLs.", "Browse", JOptionPane.PLAIN_MESSAGE); JTextDialog jTextDialog = new JTextDialog(window); jTextDialog.exportText(builder.toString()); } } private static Window getWindow(Program program) { if (program != null) { return program.getMainWindow().getFrame(); } else { return null; } } private static boolean browse(final String url) { if (url == null) { return false; } LOG.info("Browsing: " + url); URI uri; try { uri = new URI(url); } catch (URISyntaxException ex) { LOG.warn(" Browsing Failed: " + ex.getMessage()); return false; } Desktop desktop = Desktop.getDesktop(); try { desktop.browse(uri); return true; } catch (IOException ex) { LOG.warn(" Browsing Failed: " + ex.getMessage()); return false; } } private static class LinkListener implements HyperlinkListener { private final Window window; public LinkListener(Window window) { this.window = window; } @Override public void hyperlinkUpdate(final HyperlinkEvent hle) { Object o = hle.getSource(); if (o instanceof JEditorPane) { JEditorPane jEditorPane = (JEditorPane) o; if (HyperlinkEvent.EventType.ACTIVATED.equals(hle.getEventType()) && jEditorPane.isEnabled()) { browse(hle.getURL().toString(), window); } } } } public static class HelpLink { private final String link; private final String title; public HelpLink(String link, String title) { this.link = link; this.title = title; } public String getLink() { return link; } public String getTitle() { return title; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/shared/FileUtil.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.io.File; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import javax.swing.JOptionPane; import net.nikr.eve.jeveasset.CliOptions; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FileUtil extends FileUtilSimple { private static final Logger LOG = LoggerFactory.getLogger(FileUtil.class); private static final Object SYNC_LOCK = new Object(); private static final String PATH_IMAGES = "images"; private static final String PATH_SOUNDS = "sounds"; private static final String PATH_ASSET_ADDED = "data" + File.separator + "added.json"; private static final String PATH_ASSET_ADDED_DATABASE = "data" + File.separator + "addedsql.db"; private static final String PATH_STOCKPILE_IDS_DATABASE = "data" + File.separator + "stockpileids.db"; private static final String PATH_PRICE_HISTORY_DATABASE = "data" + File.separator + "pricehistory.db"; private static final String PATH_TRACKER_DATA = "data" + File.separator + "tracker.json"; private static final String PATH_SETTINGS = "data" + File.separator + "settings.xml"; private static final String PATH_AGENTS = "data" + File.separator + "agents.xml"; private static final String PATH_NPC_CORPORATION = "data" + File.separator + "npccorporation.xml"; private static final String PATH_ITEMS = "data" + File.separator + "items.xml"; private static final String PATH_ITEMS_UPDATES = "data" + File.separator + "items_updates.xml"; private static final String PATH_JUMPS = "data" + File.separator + "jumps.xml"; private static final String PATH_LOCATIONS = "data" + File.separator + "locations.xml"; private static final String PATH_FLAGS = "data" + File.separator + "flags.xml"; private static final String PATH_PRICE_DATA = "data" + File.separator + "pricedata.dat"; private static final String PATH_ASSETS = "data" + File.separator + "assets.xml"; private static final String PATH_CONQUERABLE_STATIONS = "data" + File.separator + "conquerable_stations.xml"; private static final String PATH_CITADEL = "data" + File.separator + "citadel.xml"; private static final String PATH_README = "readme.txt"; private static final String PATH_LICENSE = "license.txt"; private static final String PATH_CREDITS = "credits.txt"; private static final String PATH_CHANGELOG = "changelog.txt"; private static final String PATH_PROFILES = "profiles"; private static final String PATH_DATA = "data"; private static final String PATH_DATA_VERSION = "data" + File.separator + "data.dat"; private static final String PATH_PACKAGE_MANAGER = "packagemanager.properties"; private static final String PATH_MEMORY = "jmemory.jar"; private static final String PATH_EXPORT = "exports"; private static enum FileType { STATIC_DATA, USER_FILES } private static boolean testPath = false; public static void enableTestPath() { testPath = true; } public static boolean onMac() { return System.getProperty("os.name").toLowerCase().startsWith("mac os x"); } public static String getPathDataVersion() { return getStaticFile(PATH_DATA_VERSION); } public static String getPathRunMemory() { return getStaticFile(PATH_MEMORY); } public static String getPathPackageManager() { return getStaticFile(PATH_PACKAGE_MANAGER); } public static String getPathRunUpdate() { File userDir = new File(System.getProperty("user.home", ".")); File file = new File(userDir.getAbsolutePath() + File.separator + ".jupdate" + File.separator + "jupdate.jar"); File parentDir = file.getParentFile(); if (!parentDir.exists() && !parentDir.mkdirs()) { throw new RuntimeException("Failed to create .jUpdate directory"); } return file.getAbsolutePath(); } public static String getPathImages(String filename) { return getUserFile(PATH_IMAGES + File.separator + filename); } public static String getPathSounds(String filename) { return getUserFile(PATH_SOUNDS + File.separator + filename); } public static String getPathSoundsDirectory() { return getUserFile(PATH_SOUNDS); } public static String getUserFile(final String filename) { return getLocalFile(filename, FileType.USER_FILES); } public static String getStaticFile(final String filename) { return getLocalFile(filename, FileType.STATIC_DATA); } /** * * @param filename the name of the data file to obtain * @param fileType * @return */ private static String getLocalFile(final String filename, FileType fileType) { File file; File ret; if (fileType == FileType.USER_FILES && testPath) { ret = new File(FileUtilSimple.getLocalFile("test-output" + File.separator + filename)); } else if (fileType == FileType.USER_FILES && !CliOptions.get().isPortable()) { File userDir = new File(System.getProperty("user.home", ".")); if (onMac()) { // preferences are stored in user.home/Library/Preferences file = new File(userDir, "Library" + File.separator + "Preferences" + File.separator + "JEveAssets"); } else { file = new File(userDir.getAbsolutePath() + File.separator + ".jeveassets"); } ret = new File(file.getAbsolutePath() + File.separator + filename); } else { //jEveAssets program directory ret = new File(FileUtilSimple.getLocalFile(filename)); } File parent = ret.getParentFile(); synchronized (SYNC_LOCK) { if (!parent.exists() && !parent.mkdirs()) { JOptionPane.showMessageDialog(null, "Failed to create directory " + parent.getAbsolutePath(), Program.PROGRAM_NAME + " - Critical Error", JOptionPane.ERROR_MESSAGE); System.exit(-1); } } return ret.getAbsolutePath(); } public static String getExtension(final File file) { String extension = null; if (file == null) { return null; } String filename = file.getName(); int i = filename.lastIndexOf('.'); if (i > 0 && i < filename.length() - 1) { extension = filename.substring(i + 1).toLowerCase(); } return extension; } public static void autoImportFileUtil() { if (Program.isDevBuild() && !Settings.isTestMode()) { //Need import CliOptions.get().setPortable(false); Path settingsFrom = Paths.get(getPathSettings()); Path trackerFrom = Paths.get(getPathTrackerData()); Path assetAddedFrom = Paths.get(getPathAssetAdded()); Path assetAddedDatabaseFrom = Paths.get(getPathAssetAddedDatabase()); Path stockpileIDsDatabaseFrom = Paths.get(getPathStockpileIDsDatabase()); Path priceHistoryDatabasFrom = Paths.get(getPathPriceHistoryDatabase()); Path citadelFrom = Paths.get(getPathCitadel()); Path priceFrom = Paths.get(getPathPriceData()); Path profilesFrom = Paths.get(getPathProfilesDirectory()); Path itemsUpdatesFrom = Paths.get(getPathItemsUpdates()); CliOptions.get().setPortable(true); Path settingsTo = Paths.get(getPathSettings()); Path trackerTo = Paths.get(getPathTrackerData()); Path assetAddedTo = Paths.get(getPathAssetAdded()); Path assetAddedDatabaseTo = Paths.get(getPathAssetAddedDatabase()); Path stockpileIDsDatabaseTo = Paths.get(getPathStockpileIDsDatabase()); Path priceHistoryDatabasTo = Paths.get(getPathPriceHistoryDatabase()); Path citadelTo = Paths.get(getPathCitadel()); Path priceTo = Paths.get(getPathPriceData()); Path profilesTo = Paths.get(getPathProfilesDirectory()); Path itemsUpdatesTo = Paths.get(getPathItemsUpdates()); if (Files.exists(settingsFrom) && !Files.exists(settingsTo)) { LOG.info("Importing settings"); try { Files.copy(settingsFrom, settingsTo); LOG.info(" OK"); } catch (IOException ex) { LOG.info(" FAILED"); } } if (Files.exists(trackerFrom) && !Files.exists(trackerTo)) { LOG.info("Importing tracker data"); try { Files.copy(trackerFrom, trackerTo); LOG.info(" OK"); } catch (IOException ex) { LOG.info(" FAILED"); } } if (Files.exists(assetAddedFrom) && !Files.exists(assetAddedTo)) { LOG.info("Importing asset added"); try { Files.copy(assetAddedFrom, assetAddedTo); LOG.info(" OK"); } catch (IOException ex) { LOG.info(" FAILED"); } } if (Files.exists(assetAddedDatabaseFrom) && !Files.exists(assetAddedDatabaseTo)) { LOG.info("Importing asset added"); try { Files.copy(assetAddedDatabaseFrom, assetAddedDatabaseTo); LOG.info(" OK"); } catch (IOException ex) { LOG.info(" FAILED"); } } if (Files.exists(stockpileIDsDatabaseFrom) && !Files.exists(stockpileIDsDatabaseTo)) { LOG.info("Importing stockpile IDs"); try { Files.copy(stockpileIDsDatabaseFrom, stockpileIDsDatabaseTo); LOG.info(" OK"); } catch (IOException ex) { LOG.info(" FAILED"); } } if (Files.exists(priceHistoryDatabasFrom) && !Files.exists(priceHistoryDatabasTo)) { LOG.info("Importing price history"); try { Files.copy(priceHistoryDatabasFrom, priceHistoryDatabasTo); LOG.info(" OK"); } catch (IOException ex) { LOG.info(" FAILED"); } } if (Files.exists(citadelFrom) && !Files.exists(citadelTo)) { LOG.info("Importing citadels"); try { Files.copy(citadelFrom, citadelTo); LOG.info(" OK"); } catch (IOException ex) { LOG.info(" FAILED"); } } if (Files.exists(priceFrom) && !Files.exists(priceTo)) { LOG.info("Importing prices"); try { Files.copy(priceFrom, priceTo); LOG.info(" OK"); } catch (IOException ex) { LOG.info(" FAILED"); } } if (Files.exists(itemsUpdatesFrom) && !Files.exists(itemsUpdatesTo)) { LOG.info("Importing items updates"); try { Files.copy(itemsUpdatesFrom, itemsUpdatesTo); LOG.info(" OK"); } catch (IOException ex) { LOG.info(" FAILED"); } } if (Files.exists(profilesFrom) && !Files.exists(profilesTo)) { PathMatcher xmlMatcher = FileSystems.getDefault().getPathMatcher("glob:*.xml"); PathMatcher dbMatcher = FileSystems.getDefault().getPathMatcher("glob:*.db"); try { LOG.info("Importing profiles"); Files.walkFileTree(profilesFrom, new SimpleFileVisitor() { @Override public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException { if (dir.equals(profilesFrom)) { Files.createDirectories(profilesTo.resolve(profilesFrom.relativize(dir))); return FileVisitResult.CONTINUE; } else { return FileVisitResult.SKIP_SUBTREE; } } @Override public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { if (xmlMatcher.matches(file.getFileName()) || dbMatcher.matches(file.getFileName())) { Files.copy(file, profilesTo.resolve(profilesFrom.relativize(file))); } return FileVisitResult.CONTINUE; } }); LOG.info(" OK"); } catch (IOException ex) { LOG.info(" FAILED"); } } } } public static String getPathExports() { return getUserFile(PATH_EXPORT); } public static String getPathSettings() { return getUserFile(PATH_SETTINGS); } public static String getPathTrackerData() { return getUserFile(PATH_TRACKER_DATA); } public static String getPathAssetAdded() { return getUserFile(PATH_ASSET_ADDED); } public static String getPathAssetAddedDatabase() { return getUserFile(PATH_ASSET_ADDED_DATABASE); } public static String getPathStockpileIDsDatabase() { return getUserFile(PATH_STOCKPILE_IDS_DATABASE); } public static String getPathPriceHistoryDatabase() { return getUserFile(PATH_PRICE_HISTORY_DATABASE); } public static String getPathConquerableStations() { return getUserFile(PATH_CONQUERABLE_STATIONS); } public static String getPathCitadel() { return getUserFile(PATH_CITADEL); } public static String getPathPriceData() { return getUserFile(PATH_PRICE_DATA); } public static String getPathAssetsOld() { return getUserFile(PATH_ASSETS); } public static String getPathProfilesDirectory() { return getUserFile(PATH_PROFILES); } public static String getPathProfile(String filename) { return getUserFile(PATH_PROFILES + File.separator + filename); } public static String getPathDataDirectory() { return getUserFile(PATH_DATA); } public static String getPathItemsUpdates() { return getUserFile(PATH_ITEMS_UPDATES); } public static String getPathJumps() { return getStaticFile(PATH_JUMPS); } public static String getPathFlags() { return getStaticFile(PATH_FLAGS); } public static String getPathStaticDataDirectory() { return getStaticFile(PATH_DATA); } public static String getPathItems() { return getStaticFile(PATH_ITEMS); } public static String getPathAgents() { return getStaticFile(PATH_AGENTS); } public static String getPathNpcCorporation() { return getStaticFile(PATH_NPC_CORPORATION); } public static String getPathLocations() { return getStaticFile(PATH_LOCATIONS); } public static String getPathReadme() { return getStaticFile(PATH_README); } public static String getPathLicense() { return getStaticFile(PATH_LICENSE); } public static String getPathCredits() { return getStaticFile(PATH_CREDITS); } public static String getPathChangeLog() { return getStaticFile(PATH_CHANGELOG); } public static String getUserDirectory() { File userDir = new File(System.getProperty("user.home", ".")); return userDir.getAbsolutePath() + File.separator; } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/shared/FileUtilSimple.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.io.File; import java.net.URL; public class FileUtilSimple { private static final String PATH_JAR = "jeveassets.jar"; public static String getPathRunJar() { return getLocalFile(PATH_JAR); } public static String getPathLib() { return getPathLib(""); } public static String getPathLib(String filename) { return getLocalFile("lib" + File.separator + filename); } /** * * @param filename the name of the data file to obtain * @return */ public static String getLocalFile(final String filename) { File file; File ret; URL location = net.nikr.eve.jeveasset.Program.class.getProtectionDomain().getCodeSource().getLocation(); try { file = new File(location.toURI()); } catch (Exception ex) { file = new File(location.getPath()); } ret = new File(file.getParentFile().getAbsolutePath() + File.separator + filename); return ret.getAbsolutePath(); } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/shared/RawConverter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Map; import net.nikr.eve.jeveasset.data.api.raw.RawContract; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob; import net.nikr.eve.jeveasset.data.api.raw.RawJournal; import net.nikr.eve.jeveasset.data.api.raw.RawJournalRefType; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawNpcStanding; import net.nikr.eve.jeveasset.data.sde.ItemFlag; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.troja.eve.esi.model.CharacterAssetsResponse; import net.troja.eve.esi.model.CharacterBlueprintsResponse; import net.troja.eve.esi.model.CharacterContractsResponse; import net.troja.eve.esi.model.CharacterIndustryJobsResponse; import net.troja.eve.esi.model.CharacterLocationResponse; import net.troja.eve.esi.model.CharacterOrdersHistoryResponse; import net.troja.eve.esi.model.CharacterOrdersResponse; import net.troja.eve.esi.model.StandingsResponse; import net.troja.eve.esi.model.CharacterWalletJournalResponse; import net.troja.eve.esi.model.CorporationAssetsResponse; import net.troja.eve.esi.model.CorporationBlueprintsResponse; import net.troja.eve.esi.model.CorporationContractsResponse; import net.troja.eve.esi.model.CorporationIndustryJobsResponse; import net.troja.eve.esi.model.CorporationOrdersHistoryResponse; import net.troja.eve.esi.model.CorporationOrdersResponse; import net.troja.eve.esi.model.CorporationWalletJournalResponse; import net.troja.eve.esi.model.JumpClone; import net.troja.eve.esi.model.MarketRegionOrdersResponse; import net.troja.eve.esi.model.MarketStructureResponse; public class RawConverter { private static Map journalRefTypesIDs = null; private static synchronized void createJournalRefTypesIDs() { if (journalRefTypesIDs == null) { journalRefTypesIDs = new HashMap<>(); for (RawJournalRefType journalRefType : RawJournalRefType.values()) { journalRefTypesIDs.put(journalRefType.getID(), journalRefType); } } } public static boolean toBoolean(Boolean value) { if (value == null) { return false; } else { return value; } } public static Long toLong(Number value) { if (value != null) { return value.longValue(); } else { return null; } } public static Long toLong(String value) { if (value != null) { try { return Long.valueOf(value); } catch (NumberFormatException ex) { //No problem just return null } } return null; } public static Integer toInteger(Number value) { if (value != null) { return value.intValue(); } else { return null; } } public static int toInteger(Number value, int nullValue) { if (value != null) { return value.intValue(); } else { return nullValue; } } public static Integer toInteger(String value) { if (value != null) { try { return Integer.valueOf(value); } catch (NumberFormatException ex) { //No problem just return null } } return null; } public static Float toFloat(Number value) { if (value != null) { return value.floatValue(); } else { return null; } } public static double toDouble(Number value, double nullValue) { if (value != null) { return value.doubleValue(); } else { return nullValue; } } public static double toDouble(Double value, double nullValue) { if (value != null) { return value; } else { return nullValue; } } public static Date toDate(OffsetDateTime dateTime) { if (dateTime == null) { return null; } else { return Date.from(dateTime.toInstant()); } } public static Date toDate(LocalDate dateTime) { if (dateTime == null) { return null; } else { Date date = Date.from(dateTime.atStartOfDay().toInstant(ZoneOffset.UTC)); Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.set(Calendar.HOUR_OF_DAY, 12); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); return cal.getTime(); } } public static long toLocationID(CharacterLocationResponse shipLocation) { if (shipLocation.getStationId() != null) { return shipLocation.getStationId(); } else if (shipLocation.getStructureId() != null) { return shipLocation.getStructureId(); } else if (shipLocation.getSolarSystemId() != null) { return shipLocation.getSolarSystemId(); } else { return 0; //Fallback } } public static ItemFlag toFlag(JumpClone.LocationTypeEnum value) { return toFlagEnum(value); } public static ItemFlag toFlag(CharacterAssetsResponse.LocationFlagEnum value) { return toFlagEnum(value); } public static ItemFlag toFlag(CorporationBlueprintsResponse.LocationFlagEnum value) { return toFlagEnum(value); } public static ItemFlag toFlag(CorporationAssetsResponse.LocationFlagEnum value) { return toFlagEnum(value); } public static ItemFlag toFlag(CharacterBlueprintsResponse.LocationFlagEnum value) { return toFlagEnum(value); } private static > ItemFlag toFlagEnum(E value) { if (value == null) { return ApiIdConverter.getFlag(0); } try { LocationFlag locationFlag = LocationFlag.valueOf(value.name()); return ApiIdConverter.getFlag(locationFlag.getID()); } catch (IllegalArgumentException ex) { return ApiIdConverter.getFlag(0); } } public static ItemFlag toFlag(final int flagID, final String valueString) { ItemFlag itemFlag = StaticData.get().getItemFlags().get(flagID); if (itemFlag != null) { return itemFlag; } if (valueString != null) { for (LocationFlag value : LocationFlag.values()) { if (value.getValue().equals(valueString)) { return ApiIdConverter.getFlag(value.getID()); } } } return ApiIdConverter.getFlag(0); } public static RawContract.ContractAvailability toContractAvailability(String valueEnum, String valueString) { if (valueEnum != null) { try { return RawContract.ContractAvailability.valueOf(valueEnum); } catch (IllegalArgumentException ex) { } switch (valueEnum.toLowerCase()) { case "private": return RawContract.ContractAvailability.PERSONAL; case "public": return RawContract.ContractAvailability.PUBLIC; } } if (valueString != null) { for (RawContract.ContractAvailability value : RawContract.ContractAvailability.values()) { if (value.getValue().equals(valueString)) { return value; } } } return null; } public static RawContract.ContractAvailability toContractAvailability(CharacterContractsResponse.AvailabilityEnum value) { return toContractAvailabilityEnum(value); } public static RawContract.ContractAvailability toContractAvailability(CorporationContractsResponse.AvailabilityEnum value) { return toContractAvailabilityEnum(value); } private static > RawContract.ContractAvailability toContractAvailabilityEnum(E value) { if (value == null) { return null; } try { return RawContract.ContractAvailability.valueOf(value.name()); } catch (IllegalArgumentException ex) { return null; } } public static RawContract.ContractStatus toContractStatus(String valueEnum, String valueString) { if (valueEnum != null) { try { return RawContract.ContractStatus.valueOf(valueEnum); } catch (IllegalArgumentException ex) { } switch (valueEnum.toUpperCase()) { case "COMPLETED": return RawContract.ContractStatus.FINISHED; case "COMPLETEDBYCONTRACTOR": return RawContract.ContractStatus.FINISHED_CONTRACTOR; case "COMPLETEDBYISSUER": return RawContract.ContractStatus.FINISHED_ISSUER; case "INPROGRESS": return RawContract.ContractStatus.IN_PROGRESS; } } if (valueString != null) { for (RawContract.ContractStatus value : RawContract.ContractStatus.values()) { if (value.getValue().equals(valueString)) { return value; } } } return null; } public static RawContract.ContractStatus toContractStatus(CharacterContractsResponse.StatusEnum value) { return toContractStatusEnum(value); } public static RawContract.ContractStatus toContractStatus(CorporationContractsResponse.StatusEnum value) { return toContractStatusEnum(value); } private static > RawContract.ContractStatus toContractStatusEnum(E value) { if (value == null) { return null; } try { return RawContract.ContractStatus.valueOf(value.name()); } catch (IllegalArgumentException ex) { return null; } } public static RawContract.ContractType toContractType(String valueEnum, String valueString) { if (valueEnum != null) { try { return RawContract.ContractType.valueOf(valueEnum); } catch (IllegalArgumentException ex) { } switch (valueEnum.toLowerCase()) { case "item_exchange": return RawContract.ContractType.ITEM_EXCHANGE; case "itemexchange": return RawContract.ContractType.ITEM_EXCHANGE; case "courier": return RawContract.ContractType.COURIER; case "loan": return RawContract.ContractType.LOAN; case "auction": return RawContract.ContractType.AUCTION; default: return RawContract.ContractType.UNKNOWN; } } if (valueString != null) { for (RawContract.ContractType value : RawContract.ContractType.values()) { if (value.getValue().equals(valueString)) { return value; } } } return null; } public static RawContract.ContractType toContractType(CharacterContractsResponse.TypeEnum value) { return toContractTypeEnum(value); } public static RawContract.ContractType toContractType(CorporationContractsResponse.TypeEnum value) { return toContractTypeEnum(value); } private static > RawContract.ContractType toContractTypeEnum(E value) { if (value == null) { return null; } try { return RawContract.ContractType.valueOf(value.name()); } catch (IllegalArgumentException ex) { return null; } } public static RawNpcStanding.FromType toNpcStandingFromType(String valueEnum, String valueString) { if (valueEnum != null) { try { return RawNpcStanding.FromType.valueOf(valueEnum); } catch (IllegalArgumentException ex) { } } if (valueString != null) { for (RawNpcStanding.FromType value : RawNpcStanding.FromType.values()) { if (value.getValue().equals(valueString)) { return value; } } } return null; } public static RawNpcStanding.FromType toNpcStandingFromType(StandingsResponse.FromTypeEnum value) { return toNpcStandingFromTypeEnum(value); } public static String toAgentDivision(Integer value) { if (value == null) { return null; } switch (value) { case 18: return GuiShared.get().agentDivisionResearchAndDevelopment(); case 22: return GuiShared.get().agentDivisionDistribution(); case 23: return GuiShared.get().agentDivisionMining(); case 24: return GuiShared.get().agentDivisionSecurity(); case 25: return GuiShared.get().agentDivisionIndustrialistEntrepreneur(); case 26: return GuiShared.get().agentDivisionExplorer(); case 27: return GuiShared.get().agentDivisionIndustrialistProducer(); case 28: return GuiShared.get().agentDivisionEnforcer(); case 29: return GuiShared.get().agentDivisionSoldierOfFortune(); case 37: return GuiShared.get().agentDivisionInterBus(); default: return null; } } public static String toAgentType(Integer value) { if (value == null) { return null; } switch (value) { case 1: return GuiShared.get().agentTypeNonAgent(); case 2: return GuiShared.get().agentTypeBasicAgent(); case 3: return GuiShared.get().agentTypeTutorialAgent(); case 4: return GuiShared.get().agentTypeResearchAgent(); case 5: return GuiShared.get().agentTypeConcordAgent(); case 6: return GuiShared.get().agentTypeGenericStorylineMissionAgent(); case 7: return GuiShared.get().agentTypeStorylineMissionAgent(); case 8: return GuiShared.get().agentTypeEventMissionAgent(); case 9: return GuiShared.get().agentTypeFactionalWarfareAgent(); case 10: return GuiShared.get().agentTypeEpicArcAgent(); case 11: return GuiShared.get().agentTypeAuraAgent(); case 12: return GuiShared.get().agentTypeCareerAgent(); default: return null; } } private static > RawNpcStanding.FromType toNpcStandingFromTypeEnum(E value) { if (value == null) { return null; } try { return RawNpcStanding.FromType.valueOf(value.name()); } catch (IllegalArgumentException ex) { return null; } } public static RawIndustryJob.IndustryJobStatus toIndustryJobStatus(Integer valueInt, String valueEnum, String valueString) { if (valueEnum != null) { try { return RawIndustryJob.IndustryJobStatus.valueOf(valueEnum); } catch (IllegalArgumentException ex) { } } if (valueString != null) { for (RawIndustryJob.IndustryJobStatus value : RawIndustryJob.IndustryJobStatus.values()) { if (value.getValue().equals(valueString)) { return value; } } } if (valueInt != null) { switch (valueInt) { case 1: return RawIndustryJob.IndustryJobStatus.ACTIVE; case 2: return RawIndustryJob.IndustryJobStatus.PAUSED; case 3: return RawIndustryJob.IndustryJobStatus.READY; case 101: return RawIndustryJob.IndustryJobStatus.DELIVERED; case 102: return RawIndustryJob.IndustryJobStatus.CANCELLED; case 103: return RawIndustryJob.IndustryJobStatus.REVERTED; case -100: return RawIndustryJob.IndustryJobStatus.ARCHIVED; } } return null; } public static RawIndustryJob.IndustryJobStatus toIndustryJobStatus(CharacterIndustryJobsResponse.StatusEnum value) { return toIndustryJobStatusEnum(value); } public static RawIndustryJob.IndustryJobStatus toIndustryJobStatus(CorporationIndustryJobsResponse.StatusEnum value) { return toIndustryJobStatusEnum(value); } private static > RawIndustryJob.IndustryJobStatus toIndustryJobStatusEnum(E value) { if (value == null) { return null; } try { return RawIndustryJob.IndustryJobStatus.valueOf(value.name()); } catch (IllegalArgumentException ex) { return null; } } public static RawJournalRefType toJournalRefType(Integer valueInt, String valueString) { CharacterWalletJournalResponse.RefTypeEnum charValue = CharacterWalletJournalResponse.RefTypeEnum.fromValue(valueString); if (charValue != null) { return toJournalRefType(charValue); } CorporationWalletJournalResponse.RefTypeEnum corpValue = CorporationWalletJournalResponse.RefTypeEnum.fromValue(valueString); if (corpValue != null) { return toJournalRefType(corpValue); } if (valueInt != null) { createJournalRefTypesIDs(); return journalRefTypesIDs.get(valueInt); } return null; } public static RawJournalRefType toJournalRefType(CharacterWalletJournalResponse.RefTypeEnum value) { if (value == null) { return null; } try { return RawJournalRefType.valueOf(value.name()); } catch (IllegalArgumentException ex) { switch (value) { case KILL_RIGHT_FEE: return RawJournalRefType.KILL_RIGHT; case RESOURCE_WARS_REWARD: return RawJournalRefType.RESOURCE_WARS_SITE_COMPLETION; case REACTION: return RawJournalRefType.REACTIONS; default: return null; } } } public static RawJournalRefType toJournalRefType(CorporationWalletJournalResponse.RefTypeEnum value) { if (value == null) { return null; } try { return RawJournalRefType.valueOf(value.name()); } catch (IllegalArgumentException ex) { switch (value) { case KILL_RIGHT_FEE: return RawJournalRefType.KILL_RIGHT; case RESOURCE_WARS_REWARD: return RawJournalRefType.RESOURCE_WARS_SITE_COMPLETION; case REACTION: return RawJournalRefType.REACTIONS; default: return null; } } } public static RawJournal.ContextType toJournalContextType(CharacterWalletJournalResponse.ContextIdTypeEnum value) { return toJournalContextTypeEnum(value); } public static RawJournal.ContextType toJournalContextType(CorporationWalletJournalResponse.ContextIdTypeEnum value) { return toJournalContextTypeEnum(value); } private static > RawJournal.ContextType toJournalContextTypeEnum(E value) { if (value == null) { return null; } try { return RawJournal.ContextType.valueOf(value.name()); } catch (IllegalArgumentException ex) { return null; } } public static RawJournal.ContextType toJournalContextType(String valueEnum, String valueString) { if (valueEnum != null) { try { return RawJournal.ContextType.valueOf(valueEnum); } catch (IllegalArgumentException ex) { } } if (valueString != null) { for (RawJournal.ContextType value : RawJournal.ContextType.values()) { if (value.getValue().equals(valueString)) { return value; } } } return null; } public static RawJournal.ContextType toJournalContextType(RawJournalRefType refType) { if (refType.getArgName() != null) { switch (refType.getArgName()) { case CONTRACT_ID: return RawJournal.ContextType.CONTRACT_ID; case DESTROYED_SHIP_TYPE_ID: return RawJournal.ContextType.TYPE_ID; case JOB_ID: return RawJournal.ContextType.INDUSTRY_JOB_ID; case TRANSACTION_ID: return RawJournal.ContextType.MARKET_TRANSACTION_ID; } } if (refType.getArgID() != null) { switch (refType.getArgID()) { case NPC_ID: return RawJournal.ContextType.TYPE_ID; case PLAYER_ID: return RawJournal.ContextType.CHARACTER_ID; case STATION_ID: return RawJournal.ContextType.STATION_ID; case SYSTEM_ID: return RawJournal.ContextType.SYSTEM_ID; case CORPORATION_ID: return RawJournal.ContextType.CORPORATION_ID; case ALLIANCE_ID: return RawJournal.ContextType.ALLIANCE_ID; case PLANET_ID: return RawJournal.ContextType.PLANET_ID; } } return null; } public static Long toJournalContextID(Long argID, String argName, RawJournalRefType refType) { if (refType.getArgName() != null) { switch (refType.getArgName()) { case CONTRACT_ID: return RawConverter.toLong(argName); case DESTROYED_SHIP_TYPE_ID: return RawConverter.toLong(argName); case JOB_ID: return RawConverter.toLong(argName); case TRANSACTION_ID: return RawConverter.toLong(argName); } } return argID; } public static int toMarketOrderRegionID(long locationID, int typeID, Integer regionID) { if (regionID != null) { return regionID; } else if (typeID == 44992) { //PLEX return 19000001; //Global PLEX Market Region } else { return (int) ApiIdConverter.getLocation(locationID).getRegionID(); } } public static RawMarketOrder.MarketOrderRange toMarketOrderRange(Integer valueInt, String valueEnum, String valueString) { if (valueEnum != null) { try { return RawMarketOrder.MarketOrderRange.valueOf(valueEnum); } catch (IllegalArgumentException ex) { } } if (valueString != null) { for (RawMarketOrder.MarketOrderRange value : RawMarketOrder.MarketOrderRange.values()) { if (value.getValue().equals(valueString)) { return value; } } } if (valueInt != null) { switch (valueInt) { case -1: return RawMarketOrder.MarketOrderRange.STATION; case 0: return RawMarketOrder.MarketOrderRange.SOLARSYSTEM; case 1: return RawMarketOrder.MarketOrderRange._1; case 2: return RawMarketOrder.MarketOrderRange._2; case 3: return RawMarketOrder.MarketOrderRange._3; case 4: return RawMarketOrder.MarketOrderRange._4; case 5: return RawMarketOrder.MarketOrderRange._5; case 10: return RawMarketOrder.MarketOrderRange._10; case 20: return RawMarketOrder.MarketOrderRange._20; case 30: return RawMarketOrder.MarketOrderRange._30; case 40: return RawMarketOrder.MarketOrderRange._40; case 32767: return RawMarketOrder.MarketOrderRange.REGION; default: throw new RuntimeException("Can't convert: " + valueInt + " to MarketOrderRange"); } } return null; } public static RawMarketOrder.MarketOrderRange toMarketOrderRange(CharacterOrdersResponse.RangeEnum value) { return toMarketOrderRangeEnum(value); } public static RawMarketOrder.MarketOrderRange toMarketOrderRange(CharacterOrdersHistoryResponse.RangeEnum value) { return toMarketOrderRangeEnum(value); } public static RawMarketOrder.MarketOrderRange toMarketOrderRange(CorporationOrdersResponse.RangeEnum value) { return toMarketOrderRangeEnum(value); } public static RawMarketOrder.MarketOrderRange toMarketOrderRange(CorporationOrdersHistoryResponse.RangeEnum value) { return toMarketOrderRangeEnum(value); } public static RawMarketOrder.MarketOrderRange toMarketOrderRange(MarketRegionOrdersResponse.RangeEnum value) { return toMarketOrderRangeEnum(value); } public static RawMarketOrder.MarketOrderRange toMarketOrderRange(MarketStructureResponse.RangeEnum value) { return toMarketOrderRangeEnum(value); } private static > RawMarketOrder.MarketOrderRange toMarketOrderRangeEnum(E value) { if (value == null) { return null; } try { return RawMarketOrder.MarketOrderRange.valueOf(value.name()); } catch (IllegalArgumentException ex) { return null; } } public static RawMarketOrder.MarketOrderState toMarketOrderState(Integer valueInt, String valueEnum, String valueString) { if (valueEnum != null) { try { return RawMarketOrder.MarketOrderState.valueOf(valueEnum); } catch (IllegalArgumentException ex) { } } if (valueString != null) { for (RawMarketOrder.MarketOrderState value : RawMarketOrder.MarketOrderState.values()) { if (value.getValue().equals(valueString)) { return value; } } } if (valueInt != null) { switch (valueInt) { case 0: return RawMarketOrder.MarketOrderState.OPEN; case 1: return RawMarketOrder.MarketOrderState.CLOSED; case 2: return RawMarketOrder.MarketOrderState.EXPIRED; case 3: return RawMarketOrder.MarketOrderState.CANCELLED; case 4: return RawMarketOrder.MarketOrderState.PENDING; case 5: return RawMarketOrder.MarketOrderState.CHARACTER_DELETED; case -100: return RawMarketOrder.MarketOrderState.UNKNOWN; default: throw new RuntimeException("Can't convert: " + valueInt + " to MarketOrderState"); } } return null; } public static RawMarketOrder.MarketOrderState toMarketOrderState(CharacterOrdersHistoryResponse.StateEnum value) { return toMarketOrderStateEnum(value); } public static RawMarketOrder.MarketOrderState toMarketOrderState(CorporationOrdersHistoryResponse.StateEnum value) { return toMarketOrderStateEnum(value); } private static > RawMarketOrder.MarketOrderState toMarketOrderStateEnum(E value) { if (value == null) { return null; } try { return RawMarketOrder.MarketOrderState.valueOf(value.name()); } catch (IllegalArgumentException ex) { return null; } } public static int fromMarketOrderIsBuyOrder(Boolean value) { return value ? 1 : 0; } public static Boolean toTransactionIsBuy(String value) { return value.toLowerCase().equals("buy"); } public static Boolean toTransactionIsPersonal(String value) { return value.toLowerCase().equals("personal"); } public static String fromTransactionIsBuy(Boolean value) { if (value) { return "buy"; } else { return "sell"; } } public static String fromTransactionIsPersonal(Boolean value) { if (value) { return "personal"; } else { return "corporate"; } } public static int toAssetQuantity(int quantity, Integer rawQuantity) { if (rawQuantity != null && rawQuantity < 0) { return rawQuantity; } else { return quantity; } } public enum LocationFlag { AUTOFIT("AutoFit", 0), HANGARALL("HangarAll", 0), //1000 WALLET("Wallet", 1), OFFICEFOLDER("OfficeFolder", 2), WARDROBE("Wardrobe", 3), HANGAR("Hangar", 4), CARGO("Cargo", 5), IMPOUNDED("OfficeImpound", 6), //Impounded MODULE("Skill", 7), //Module SKILL("Skill", 7), REWARD("Reward", 8), LOSLOT0("LoSlot0", 11), LOSLOT1("LoSlot1", 12), LOSLOT2("LoSlot2", 13), LOSLOT3("LoSlot3", 14), LOSLOT4("LoSlot4", 15), LOSLOT5("LoSlot5", 16), LOSLOT6("LoSlot6", 17), LOSLOT7("LoSlot7", 18), MEDSLOT0("MedSlot0", 19), MEDSLOT1("MedSlot1", 20), MEDSLOT2("MedSlot2", 21), MEDSLOT3("MedSlot3", 22), MEDSLOT4("MedSlot4", 23), MEDSLOT5("MedSlot5", 24), MEDSLOT6("MedSlot6", 25), MEDSLOT7("MedSlot7", 26), HISLOT0("HiSlot0", 27), HISLOT1("HiSlot1", 28), HISLOT2("HiSlot2", 29), HISLOT3("HiSlot3", 30), HISLOT4("HiSlot4", 31), HISLOT5("HiSlot5", 32), HISLOT6("HiSlot6", 33), HISLOT7("HiSlot7", 34), ASSETSAFETY("AssetSafety", 36), CAPSULE("Capsule", 56), PILOT("Pilot", 57), SKILLINTRAINING("SkillInTraining", 61), CORPDELIVERIES("CorpMarket", 62), //CorpDeliveries LOCKED("Locked", 63), UNLOCKED("Unlocked", 64), BONUS("Bonus", 86), DRONEBAY("DroneBay", 87), BOOSTER("Booster", 88), IMPLANT("Implant", 89), SHIPHANGAR("ShipHangar", 90), SHIPOFFLINE("ShipOffline", 91), RIGSLOT0("RigSlot0", 92), RIGSLOT1("RigSlot1", 93), RIGSLOT2("RigSlot2", 94), RIGSLOT3("RigSlot3", 95), RIGSLOT4("RigSlot4", 96), RIGSLOT5("RigSlot5", 97), RIGSLOT6("RigSlot6", 98), RIGSLOT7("RigSlot7", 99), CORPSAG1("CorpSAG1", 115), CORPSAG2("CorpSAG2", 116), CORPSAG3("CorpSAG3", 117), CORPSAG4("CorpSAG4", 118), CORPSAG5("CorpSAG5", 119), CORPSAG6("CorpSAG6", 120), CORPSAG7("CorpSAG7", 121), SECONDARYSTORAGE("SecondaryStorage", 122), SUBSYSTEMSLOT0("SubSystemSlot0", 125), SUBSYSTEMSLOT1("SubSystemSlot1", 126), SUBSYSTEMSLOT2("SubSystemSlot2", 127), SUBSYSTEMSLOT3("SubSystemSlot3", 128), SUBSYSTEMSLOT4("SubSystemSlot4", 129), SUBSYSTEMSLOT5("SubSystemSlot5", 130), SUBSYSTEMSLOT6("SubSystemSlot6", 131), SUBSYSTEMSLOT7("SubSystemSlot7", 132), SPECIALIZEDFUELBAY("SpecializedFuelBay", 133), SPECIALIZEDOREHOLD("SpecializedAsteroidHold", 134), SPECIALIZEDGASHOLD("SpecializedGasHold", 135), SPECIALIZEDMINERALHOLD("SpecializedMineralHold", 136), SPECIALIZEDSALVAGEHOLD("SpecializedSalvageHold", 137), SPECIALIZEDSHIPHOLD("SpecializedShipHold", 138), SPECIALIZEDSMALLSHIPHOLD("SpecializedSmallShipHold", 139), SPECIALIZEDMEDIUMSHIPHOLD("SpecializedMediumShipHold", 140), SPECIALIZEDLARGESHIPHOLD("SpecializedLargeShipHold", 141), SPECIALIZEDINDUSTRIALSHIPHOLD("SpecializedIndustrialShipHold", 142), SPECIALIZEDAMMOHOLD("SpecializedAmmoHold", 143), STRUCTUREACTIVE("StructureActive", 144), STRUCTUREINACTIVE("StructureInactive", 145), JUNKYARDREPROCESSED("JunkyardReprocessed", 146), JUNKYARDTRASHED("JunkyardTrashed", 147), SPECIALIZEDCOMMANDCENTERHOLD("SpecializedCommandCenterHold", 148), SPECIALIZEDPLANETARYCOMMODITIESHOLD("SpecializedPlanetaryCommoditiesHold", 149), PLANETSURFACE("PlanetSurface", 150), SPECIALIZEDMATERIALBAY("SpecializedMaterialBay", 151), DUSTDATABANK("DustCharacterDatabank", 152), //DustDatabank DUSTBATTLE("DustCharacterBattle", 153), //DustBattle QUAFEBAY("QuafeBay", 154), FLEETHANGAR("FleetHangar", 155), HIDDENMODIFIERS("HiddenModifiers", 156), STRUCTUREOFFLINE("StructureOffline", 157), FIGHTERBAY("FighterBay", 158), FIGHTERTUBE0("FighterTube0", 159), FIGHTERTUBE1("FighterTube1", 160), FIGHTERTUBE2("FighterTube2", 161), FIGHTERTUBE3("FighterTube3", 162), FIGHTERTUBE4("FighterTube4", 163), SERVICESLOT0("StructureServiceSlot0", 164), //ServiceSlot0 SERVICESLOT1("StructureServiceSlot1", 165), //ServiceSlot1 SERVICESLOT2("StructureServiceSlot2", 166), //ServiceSlot2 SERVICESLOT3("StructureServiceSlot3", 167), //ServiceSlot3 SERVICESLOT4("StructureServiceSlot4", 168), //ServiceSlot4 SERVICESLOT5("StructureServiceSlot5", 169), //ServiceSlot5 SERVICESLOT6("StructureServiceSlot6", 170), //ServiceSlot6 SERVICESLOT7("StructureServiceSlot7", 171), //ServiceSlot7 STRUCTUREFUEL("StructureFuel", 172), DELIVERIES("Deliveries", 173), CRATELOOT("CrateLoot", 174), CORPSEBAY("CrateLoot", 174), //CorpseBay 175? BOOSTERBAY("BoosterBay", 176), SUBSYSTEMBAY("SubSystemBay", 177), FRIGATEESCAPEBAY("FrigateEscapeBay", 179), QUANTUMCOREROOM("StructureDeedBay", 180), //QuantumCoreRoom STRUCTUREDEEDBAY("StructureDeedBay", 180), //QuantumCoreRoom SPECIALIZEDICEHOLD("SpecializedIceHold", 181), SPECIALIZEDASTEROIDHOLD("SpecializedAsteroidHold", 182), MOBILEDEPOTHOLD("MobileDepot", 183), CORPORATIONGOALDELIVERIES("CorpProjectsHangar", 184), INFRASTRUCTUREHANGAR("ColonyResourcesHold", 185), MOONMATERIALBAY("MoonMaterialBay", 186), CAPSULEERDELIVERIES("CapsuleerDeliveries", 187), ; private final String value; private final int id; LocationFlag(String value, int id) { this.value = value; this.id = id; } public String getValue() { return value; } public int getID() { return id; } @Override public String toString() { return String.valueOf(value); } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/shared/SafeConverter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.util.ArrayList; import java.util.List; public class SafeConverter { public static Long toLong(Integer value) { if (value != null) { return value.longValue(); } else { return null; } } public static Integer toInteger(Long value) { if (value != null) { return Math.toIntExact(value); } return null; } public static List toInteger(List values) { if (values != null) { List output = new ArrayList<>(); for (long value : values) { output.add(toInteger(value)); } return output; } return new ArrayList<>(); } public static Float toFloat(Number value) { if (value != null) { return value.floatValue(); } else { return null; } } } ================================================ FILE: src/main/java/net/nikr/eve/jeveasset/io/shared/ThreadWoker.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import net.nikr.eve.jeveasset.gui.dialogs.update.UpdateTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ThreadWoker { public static final int MAIN_THREADS = 100; private static final int SUB_THREADS = 100; private static final ExecutorService RETURN_THREAD_POOL = Executors.newFixedThreadPool(SUB_THREADS); private static final Logger LOG = LoggerFactory.getLogger(ThreadWoker.class); public static void start(UpdateTask updateTask, Collection updaters) { start(updateTask, updaters, true); } public static void start(UpdateTask updateTask, Collection updaters, int start, int end) { start(updateTask, updaters, true, start, end); } public static void start(UpdateTask updateTask, Collection updaters, boolean updateProgress) { start(updateTask, updaters, updateProgress, 0, 100); } public static void start(UpdateTask updateTask, Collection updaters, boolean updateProgress, int start, int end) { ExecutorService threadPool = Executors.newFixedThreadPool(MAIN_THREADS); try { LOG.info("Starting " + updaters.size() + " main threads"); List> futures = new ArrayList<>(); for (Runnable runnable : updaters) { futures.add(threadPool.submit(runnable)); } threadPool.shutdown(); while (!threadPool.awaitTermination(500, TimeUnit.MICROSECONDS)) { if (updateTask != null) { if (updateTask.isCancelled()) { threadPool.shutdownNow(); } else if (updateProgress) { int progress = 0; for (Future future : futures) { if (future.isDone()) { progress++; } } updateTask.setTaskProgress(updaters.size(), progress, start, end); } } } //Get errors (if any) for (Future future : futures) { future.get(); } } catch (InterruptedException ex) { //No problem } catch (ExecutionException ex) { throwExecutionException(ex); } } public static List> startReturn(UpdateTask updateTask, Collection> updaters) throws InterruptedException { return startReturn(updateTask, updaters, false); } public static List> startReturn(UpdateTask updateTask, Collection> updaters, boolean updateProgress) throws InterruptedException { return startReturn(updateTask, updaters, updateProgress, 0, 100); } public static List> startReturn(UpdateTask updateTask, Collection> updaters, boolean updateProgress, int start, int end) throws InterruptedException { if (updateTask != null && updateTask.isCancelled()) { throw new TaskCancelledException(); } LOG.info("Starting " + updaters.size() + " sub threads"); List> futures = new ArrayList<>(); for (Callable callable : updaters) { futures.add(RETURN_THREAD_POOL.submit(callable)); } int done = 0; while (done < futures.size()) { done = 0; for (Future future : futures) { if (future.isDone()) { done++; } } if (updateTask != null) { if (updateTask.isCancelled()) { //If task is cancelled for (Future future : futures) { //cancel all threads future.cancel(true); } throw new TaskCancelledException(); //Stop parent Task } else if (updateProgress) { updateTask.setTaskProgress(updaters.size(), done, start, end); } } Thread.sleep(500); } return futures; } public static K startReturn(UpdateTask updateTask, Callable updater) { return startReturn(RETURN_THREAD_POOL, updateTask, updater); } public static K startReturn(ExecutorService executorService, UpdateTask updateTask, Callable updater) { if (updateTask != null && updateTask.isCancelled()) { throw new TaskCancelledException(); } LOG.info("Starting sub thread"); Future future = executorService.submit(updater); try { return future.get(); } catch (InterruptedException ex) { LOG.error(ex.getMessage(), ex); } catch (ExecutionException ex) { LOG.error(ex.getMessage(), ex); } return null; } public static class TaskCancelledException extends RuntimeException { } private static void throwExecutionException(ExecutionException ex) throws E { throwExecutionException(null, ex); } public static void throwExecutionException(Class clazz, ExecutionException ex) throws E { Throwable cause = ex.getCause(); if (clazz != null && cause.getClass().equals(clazz) ) { throw clazz.cast(cause); } else if (cause instanceof Error) { throw (Error) cause; } else if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else { throw new RuntimeException(cause); } } } ================================================ FILE: src/main/resources/logback.xml ================================================ ${PATTERN} ${log.home}jeveassets.log ${log.home}jeveassets%i.log 1 1 5MB ${PATTERN} ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/DataColors.properties ================================================ #Assets assetsNew=New assetsReprocessingEqual=Reprocessing Colors: reprocess = sell assetsReprocessingReproces=Reprocessing Colors: reprocess > sell assetsReprocessingSell=Reprocessing Colors: sell > reprocess assetsReprocess=Reprocess > sell #Custom customPrice=Custom Price customAssetName=Custom Asset Name customUserLocation=Custom Location #Contracts contractsCourier=Courier contracts contractsIncluded=Buy (included) contractsExcluded=Sell (excluded) #Extractions extractionsDays=2 Days or decaying extractionsWeek=1 Week extractionsWeeks=More than 1 week #Overview overviewGroupedLocations=Grouped Locations #Stockpile stockpileTableBelowThreshold=Below Threshold: Table stockpileIconBelowThreshold=Below Threshold: Icon stockpileTableBelowThreshold2nd=Below 2nd Threshold: Table stockpileIconBelowThreshold2nd=Below 2nd Threshold: Icon stockpileTableOverThreshold=Over Threshold: Table stockpileIconOverThreshold=Over Threshold: Icon #Market Orders marketOrdersOutbidNotBest=Outbid: Not Best marketOrdersOutbidNotBestOwned=Outbid: Not Best (Best Owned) marketOrdersOutbidBest=Outbid: Best marketOrdersOutbidUnknown=Outbid: Unknown marketOrdersExpired=Expired marketOrdersNearExpired=Nearing Expiration marketOrdersNearFilled=Nearing Filled marketOrdersNew=New #Industry Jobs industryJobsDelivered=Industry Job Delivered industryJobsDone=Industry Job Done industryJobsManufacturing=Manufacturing industryJobsResearchingTechnology=Researching Technology industryJobsResearchingTimeProductivity=Researching Time Productivity industryJobsResearchingMeterialProductivity=Researching Material Productivity industryJobsCopying=Copying industryJobsDuplicating=Duplicating industryJobsReverseEngineering=Reverse Engineering industryJobsReverseInvention=Invention industryJobsReactions=Reactions #Slots slotsFree=Slots Free slotsDone=Slots Done slotsFull=Slots Full #Journal journalNew=New #Transactions transactionsBought=Bought transactionsSold=Sold transactionsNew=New #NPC Standing npcStandingNegative=Negative npcStandingPositive=Positive npcStandingNegativeMiddle=Negative Middle npcStandingPositiveMiddle=Positive Middle #Global globalBPC=Blueprint Copy (BPC) globalBPO=Blueprint Original (BPO) globalValueNegative=Negative Values globalValuePositive=Positive Values globalEntryInvalid=Entry Invalid globalEntryWarning=Entry Warning globalEntryValid=Entry Valid globalGrandTotal=Grand total globalSelectedRowHighlighting=Selected row highlighting #Filters filterOrGroup1=Filter Group 1 filterOrGroup2=Filter Group 2 filterOrGroup3=Filter Group 3 filterOrGroup4=Filter Group 4 filterOrGroup5=Filter Group 5 filterOrGroup6=Filter Group 6 filterOrGroup7=Filter Group 7 #Reprocessed reprocessedSell=sell > processed reprocessedReprocess=processed > sell reprocessedEqual="processed = sell #Groups groupAssets=Assets groupCustom=Custom groupContracts=Contracts groupExtractions=Extractions groupOverview=Overview groupMarketOrders=Market Orders groupIndustryJobs=Industry Jobs groupSlots=Slots groupJournal=Journal groupTransactions=Transactions groupNpcStanding=NPC Standing groupGlobal=Global groupFilters=Filters groupReprocessed=Reprocessed groupStockpile=Stockpile #Color Theme colorThemeDark=Dark colorThemeDefault=jEveAssets Default colorThemeStrong=Strong Colors colorThemeColorblind=Colorblind Friendly ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/DataModelAsset.properties ================================================ unpackaged=Unpackaged packaged=Packaged ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/DataModelIndustryJob.properties ================================================ statusPaused=Paused statusActive=Active statusDone=Done statusReverted=Reverted statusCancelled=Cancelled statusDelivered=Delivered statusArchived=Archived statusUnknown=Unknown activityAll=All activityNone=None activityManufacturing=Manufacturing activityResearchingTechnology=Researching Technology activityResearchingTimeProductivity=Researching Time Productivity activityResearchingMeterialProductivity=Researching Material Productivity activityCopying=Copying activityDuplicating=Duplicating activityReverseEngineering=Reverse Engineering activityReverseInvention=Invention activityReactions=Reactions activityUnknown=Unknown descriptionCopying=Copying: {0} making {1} copies with {2} runs each. ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/DataModelPriceDataSettings.properties ================================================ sourceFuzzwork=fuzzwork.co.uk sourceEveTycoon=EveTycoon.com sourceJanice=Janice priceSellMax=Sell Maximum priceSellAvg=Sell Average priceSellMedian=Sell Median priceSellPercentile=Sell Lowest 5% / Sell Percentile priceSellMin=Sell Minimum priceMidpoint=Midpoint priceBuyMax=Buy Maximum priceBuyAvg=Buy Average priceBuyMedian=Buy Median priceBuyPercentile=Buy Highest 5% / Buy Percentile priceBuyMin=Buy Minimum ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/DialoguesAbout.properties ================================================ about=About close=Close ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/DialoguesAccount.properties ================================================ dialogueNameAccountImport=Account Import dialogueNameAccountExport=Account Export previousArrow=< Previous nextArrow=Next > cancel=Cancel ok=OK failApiError=The API returned the following error failApiErrorText={0}
\ Please see the FAQ for help
failNotEnoughPrivileges=Not enough privileges failNotEnoughPrivilegesText=The account does not grant the needed privileges.
\
\
\
\ Press Previous to retry. failNotValid=Account not valid failNotValidText=The entered credentials was not valid.
\
\
\
\ Press Previous to retry. failWrongEntry=Character/Corporation did not match failWrongEntryText=Did not find character/corporation from the edited account.
\ The entered credentials is for a different character/corporation.
\ Please use a matching account or add a new account instead.
\
\ Press Previous to retry. okUpdate=Account already imported okUpdateLimitedText=Update existing account?
\ The account only grant some of the needed privileges.
\ Warning: The updated account will have limited functionality
\
\ Press Previous to retry. Press OK to update account. okUpdateText=Update existing account?
\
\
\
\ Press OK to update account. okLimited=Valid account (limited) okLimitedText=The account only grant some of the needed privileges.
\ Warning: The account will have limited functionality
\
\
\ Press Previous to retry. Press OK to import. okLimitedExportText=The account only grant some of the needed privileges.
\ Warning: The exported account will have limited functionality
\
\
\ Press Previous to retry. Press Next to complete the export. okValid=Account valid okValidText=Tip: To get the new account data select: Menu > Update > Update
\
\
\
\ Press OK to import. authCode=Authorization Code authorize=Authorize accountType=Account accessKey=Access Key ID esiHelpText=Help:\r\n\ 1. Select character or corporation account\r\n\ 2. Select scopes\r\n\ 3. Press next to continue authCodeHelpText=Help:\r\n\ 1. The Eve SSO web page should open in your browser\r\n\ 2. Select your character by clicking on their portrait\r\n\ 3. Click Authorize on the web page\r\n\ 4. Copy the auth code into the field bellow\r\n\ 5. Press next to continue browseHelpText=Help:\r\n\ 1. The Eve SSO web page should open in your browser\r\n\ 2. Select your character by clicking on their portrait\r\n\ 3. Click Authorize on the web page\r\n\ 4. Return to jEveAssets and wait for the import process to finish validatingMessage=Validating Account scopes=Scopes character=Character corporation=Corporation workaroundLabel=Workaround workaroundCheckbox=Use eve.nikr.net scopeAssets=Assets scopeClones=Clones scopeImplants=Implants scopeWallet=Wallet scopeBlueprints=Blueprints scopeIndustryJobs=Industry Jobs scopeMarketOrders=Market Orders scopeMarketStructures=Market Structures scopeContracts=Contracts scopeRoles=Roles (Required) scopeStructures=Structures scopeShipType=Active Ship Type scopeShipLocation=Active Ship Location scopeOpenWindows=Open In-Game Windows scopePlanetaryInteraction=Planetary Assets scopeAutopilot=Set Autopilot scopeDivisions=Division Names scopeSkills=Skills scopeMining=Mining scopeLoyaltyPoints=Loyalty Points scopeNpcStanding=NPC Standing dialogueNameAccountManagement=Account Management add=Add revalidate=Revalidate revalidateMsgAll={0,choice,1#Account|1Delete Profile: "{0}"?
Warning: Deleted profiles can not be restored clearFilter=Clear asset filter? profileLoadedMsg=Profile Loaded ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/DialoguesSettings.properties ================================================ #Settings Dialog settings={0} Settings root=root ok=OK apply=Apply cancel=Cancel tools=Tools values=Values #General general=General loadToolsBackground=Load tools in the background loadToolsOpen=Load tools on show (slower open) loadToolsStartup=Load tools on startup (slow startup) enterFilter=Only filter when enter is pressed highlightSelectedRow=Highlight selected row(s) focusEveOnline=Focus Eve-Online after opening in-game windows focusEveOnlineLinuxCmd=sudo apt-get install wmctrl focusEveOnlineLinuxHelp=wmctrl need to be installed for this to work. focusEveOnlineLinuxHelp2=Run the following cmd to install: copyDecimalSeparator=Copy Decimal Separator transactionsProfit=Transaction Profit transactionsMargin=Margin transactionsPrice=Default Price: transactionsPriceAverage=Average transactionsPriceLatest=Latest transactionsPriceMaximum=Maximum transactionsPriceMinimum=Minimum includeDays=Transaction Age: days= Days (Zero = Unlimited) #Show show=Show saveTools=Restore tools from previous session selectTools=Select tools: toolsOrderHelp=Drag and drop to rearrange order #Assets assets=Assets includeSellContracts=Include sell contracts includeBuyContracts=Include buy contracts includeSellOrders=Include market sell orders includeBuyOrders=Include market buy orders includeManufacturing=Include manufacturing output includeCopying=Include blueprint copying output includeJumpClones=Include jump clones includePluggedInImplants=Include plugged in implants showContainerItemID=Show Container ItemID (Visual only - filters are compared with ItemID) contractAssetsBoth=Corporation and Character contractAssetsCharacter=Character contractAssetsCorporation=Corporation contractAssetsLabel=Corporation contract owner contractAssetsLabelWarn=Note: Filters will need to match both #Overview overview=Overview ignoreContainers=Ignore Containers (Only include the content of containers) #Stockpile stockpile=Stockpile stockpileSwitchTab=Focus tab automatically stockpileColors=Color Scheme stockpileTwoGroups=2 Groups stockpileThreeGroups=3 Groups percentPlusSymbol=+% #Transactions/Journal/Market Orders/Contracts/Industry Jobs saveHistoryWarning=Warning: if you disable save history, the entire history will be deleted on the next API update. #Market Orders marketOrders=Market Orders marketOrdersSaveHistory=Save Market Orders history expireWarnDays=Days before warning of order expiration remainingWarnPercent=Percent remaining before warning #Transactions transactions=Transactions transactionsSaveHistory=Save Transactions history #Journal journal=Journal journalSaveHistory=Save Journal history #Industry Jobs industryJobs=Industry Jobs industryJobsSaveHistory=Save Industry Jobs history #Contracts contracts=Contracts contractsSaveHistory=Save Contracts history #TrackerToolSettingsPanel tracker=Tracker useAssetPriceForSellOrders=Use asset price for sell orders #PriceHistoryToolSettingsPanel priceHistory=Price History clearBlacklist=Reset Ignored clearBlacklistMsg=jEveAssets keeps a list of incomplete types from the zKillboard API.\r\n\ Types in the list are never downloaded again.\r\n\ Resetting the list makes all types downloadable again.\r\n\ Reset the list now? clearBlacklistTitle=Reset #MiningToolSettingsPanel mining=Mining miningSaveHistory=Save Mining history #JumpsSettingsPanel jumps=Jumps eveGatecampCheck=Eve Gatecamp Check eveGatecampCheckOpenOptions=Open eveGatecampCheckRouteOptions=Route #Colors chartColors=Easy to see chart colors colors=Colors collapse=Collapse expand=Expand columnName=Name #columnBackground text is not displayed, but have to ne unique columnBackground=BG #columnForeground text is not displayed, but have to ne unique columnForeground=FG columnPreview=PW columnSelected=PWS testText=Text testSelectedText=Selected overwriteTitle=Overwrite overwriteMsg=Overwrite customized colors? theme=Colors lookAndFeel=Look & Feel lookAndFeelDefault=Default lookAndFeelDefaultName=Default ({0}) lookAndFeelFlatLight=Flat Light lookAndFeelFlatDark=Flat Dark lookAndFeelFlatIntelliJ=Flat IntelliJ lookAndFeelFlatDarcula=Flat Darcula lookAndFeelNimbusDark=Dark Nimbus lookAndFeelMsg=Changing the Look and Feel will not take effect until jEveAssets is restarted lookAndFeelTitle=Look and Feel #Sounds sounds=Sounds soundsBeep=Beep soundsEveArmor=Eve Armor Warning soundsEveCapacitor=Eve Capacitor Warning soundsEveCargo=Eve Cargo Warning soundsEveCharacterSelection=Eve Character Selection soundsEveLogin=Eve Login soundsEveNotificationPing=Eve Notification Ping soundsEveShield=Eve Shield Warning soundsEveSkill=Eve Skill Completed soundsEveStart=Eve Start soundsEveStructure=Eve Structure Warning soundsIndustryJobCompleted=Industry Job Completed soundsMp3Add=Add Mp3 soundsMp3DeleteMsg=Delete: {0}\r\nNote: Only deletes the copy in the jEveAssets sounds directory soundsMp3DeleteTitle=Delete Mp3 soundsMp3ImportCopy=Failed to copy mp3 file to the sounds directory soundsMp3ImportExist=Mp3 file already exist in the sounds directory soundsMp3ImportTitle=Mp3 Import Failed soundsMp3NoFilesAdded=No files added soundsNone=None soundsOutbidUpdateCompleted=Outbid Update Completed soundsOutbidUpdateAvailable=Outbid Update Available #Price Data changeSourceWarning=Note: When changing the Price Source or Price Location, the changes will not take effect until you update the price data. includeRegions=Price Region: includeStations=Price Station: includeSystems=Price System: notConfigurable=Not Configurable price=Default Price: priceBase=Blueprint base price: priceData=Market Prices priceReprocessed=Reprocessed Price: priceManufacturing=Manufacturing Price: manufacturingDefault=Default price for non-market items priceTech1=Tech 1 priceTech2=Tech 2 source=Price Source: janiceApiKey=Janice API Key: janiceApiKeyMsg=By default jEveAssets doesn't need a Janice API Key\r\n\ If it stops working you can ask for your own API key on the Janice discord\r\n\ Do you want to open the invite link to Janice discord now? janiceApiKeyTitle=Janice API Key #Proxy proxy=Proxy type=Proxy Type address=Proxy Address port=Proxy Port auth=Enable Authenticating username=Username password=Password #Reprocessing reprocessing=Reprocessing reprocessingWarning=Note: Station tax is not calculated (0% tax or 6.67+ standing) stationEquipment=Refining Equipment fiftyPercent=50% percentSymbol=% reprocessingLevel=Reprocessing reprocessingEfficiencyLevel=Reprocessing Efficiency oreProcessingLevel=Ore Processing scrapmetalProcessingLevel=Scrapmetal Processing zero=0 one=1 two=2 three=3 four=4 five=5 #Manufacturing manufacturing=Manufacturing manufacturingFacility=Facility manufacturingFacilityStation=Station manufacturingFacilityMedium=Raitaru (Medium) manufacturingFacilityLarge=Azbel (Large) manufacturingFacilityXLarge=Sotiyo (X-Large) manufacturingME=Material Efficiency manufacturingPercent=% manufacturingRigs=Facility Rigs manufacturingRigsNone=None manufacturingRigsT1=T1 manufacturingRigsT2=T2 manufacturingSecurity=Security manufacturingSecurityHighSec=High Sec manufacturingSecurityLowSec=Low Sec manufacturingSecurityNullSec=Null Sec manufacturingSystems=Systems Index manufacturingSystemsWarning=Systems Indexes are outdated (Fix: Update Market Prices) manufacturingTax=Tax #User set badInput=Bad input deleteItem=Reset deleteTypeTitle=Reset {0} editItem=Edit editTypeTitle=Edit {0} inputNotValid=Input not valid itemEmpty=Empty items={0} items #Names names=Names name=Name namesInstruction=To change the name of an asset:\n\ 1. Go to the Assets tool\n\ 2. Right click on the asset in the table\n\ 3. Select [Name] > [Edit] in the popup menu #Prices pricePrice=Price pricePrices=Prices priceInstructions=To set the price for an asset type:\n\ 1. Go to the Assets or Items tool\n\ 2. Right click on the item in the table\n\ 3. Select [Price] > [Edit] in the popup menu #Locations locationsInstructions=To rename a location:\n\ 1. Go to the Assets tool\n\ 2. Right click a asset with [Unknown Location] in the table\n\ 3. Select [Locations] > [Edit] in the popup menu #Window windowWindow=Window windowSaveOnExit=Save size on exit windowAlwaysOnTop=Always On Top windowFixed=Fixed size windowWidth=Width: windowHeight=Height: windowX=X Position: windowY=Y Position: windowMaximised=Maximized: ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/DialoguesStructure.properties ================================================ eta=ETA: {0} (or less) invalid=No ESI accounts with the structure scope found locationsAll=All Locations locationsItem=Item Locations locationsSelected=Selected Locations locationsTracker=Tracker Locations nextUpdate=Next update in {0} ownersAll=All Owners ownersSingle=Single Owner title=Update Structures updateTitle=Structures ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/DialoguesUpdate.properties ================================================ updating=Updating ok=OK cancel=Cancel cancelQuestion=Do you want to cancel the update? cancelQuestionTitle=Cancel Update minimize=Minimize firstAccount=First Account allAccounts=All Accounts update=Update contracts=Contracts marketOrders=Market Orders industryJobs=Industry Jobs accounts=Accounts accountBalance=Account Balance assets=Assets priceData=Market Prices priceDataNew=New priceDataNone=None nextUpdate=Next Update: cancel=Cancel noAccounts=No Accounts now=Now journal=Journals transactions=Transactions names=ID to Name blueprints=Blueprints skills=Skills loyaltyPoints=Loyalty Points npcStanding=NPC Standing mining=Mining structures=Structures publicMarketOrders=Public Market Orders step1=Accounts step2=Data step3=Dynamic Data step4=Contract Items balance=Balance ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/General.properties ================================================ uncaughtErrorMessage=Please email jeveassets.log to niklaskr@gmail.com (See the readme.txt for details) error=Error contractIncluded=Contract > Sell contractExcluded=Contract > Buy industryJobFlag=Industry Job marketOrderSellFlag=Market Order (Sell) marketOrderBuyFlag=Market Order (Buy) jumpClone=Jump Clone activeClone=Active Clone none=None all=All fileLockTitle=File Lock fileLockMsg=File Lock: {0}
\n\ Please see the Wiki singleInstanceTitle=Run multiple instances? singleInstanceMsg=jEveAssets is already running.\n\ You may lose data if you run more than one instance.\n\ Do you want to run anyway? emptyLocation=[Unknown Location #{0}] assetSafety=Asset Safety journalContract=Contract journalIndustryJob=Industry Job journalMarketTransaction=Market Transaction journalSystemTransaction=System Transaction ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/GuiFrame.properties ================================================ about=About accounts=Accounts... agents=Agents business=Business change=Change Log clickToShow={0} - Click to show clickToApply={0} - Click to apply close=Close Tab contracts=Contracts credits=Credits eve=Eve Server Time exit=Exit exitMsg=Cancel update{0,choice,1#|1 Options... > Jumps\n uiWaypointEveGatecampCheckSecure=Secure uiWaypointEveGatecampCheckShortest=Shortest uiWaypointFail=Waypoint request failed uiWaypointOk=Waypoint request completed uiWaypointTitle=Waypoint uiCharacterInvalidMsg=No valid ESI accounts found uiCharacterMsg=Select in-game character: uiCharacterTitle=Select Character uiContract=Contract uiContractFail=Open contract window request failed uiContractOk=Open contract window request completed uiContractTitle=Contract uiLocationTitle=Select Location uiMarket=Market uiMarketFail=Open market window request failed uiMarketOk=Open market window request completed uiMarketTitle=Market uiOwner=Owner uiOwnerFail=Open info window request failed uiOwnerMsg=Select owner to show info for: uiOwnerOk=Open info window request completed uiOwnerTitle=Owner uiStation=Station uiSystem=System unknownFaction=[No Faction Data] unknownOwner=[Unknown Owner] updateStructures=Update updating=Updating zKillboard=zKillboard #Views deleteView=Delete View deleteViews=Delete {0} views? editViews=Manage... enterViewName=Enter View Name: loadView=Load View manageViews=Manage Views overwriteView=Overwrite View renameView=Rename View saveView=Save View saveViewMsg=Enter view name: #Filters saveFilter=Save saveFilterToolTip=Save Filter enterFilterName=Enter filter name\: save=Save cancel=Cancel noFilterName=You need to enter a name for the filter. overwriteDefaultFilter=You can not overwrite default filters overwriteFilter=Overwrite Filter addField=Add addFieldToolTip=Add Filter clearField=Clear clearFieldToolTip=Clear Filters loadFilter=Load loadFilterToolTip=Load/Manage Filters showFilters=Show showFiltersToolTip=Show/Hide Filters manageFilters=Manage... nothingToSave=Nothing to save... filterManager=Filter Manager managerExport=Export managerImport=Import managerImportFailMsg=Failed to import filters.\r\nRetry? managerImportFailTitle=Import Failed managerLoad=Load managerRename=Rename managerDelete=Delete managerEdit=Edit managerCopy=Copy managerClose=Close renameFilter=Rename Filter deleteFilter=Delete Filter deleteFilters=Delete {0} filters? mergeFilters=Merge Filters managerMerge=Merge filterAll=All filterAnd=And filterOr=Or filterContains=Contains filterContainsNot=Does not contain filterEquals=Equals filterEqualsNot=Does not equals filterRegex=Regular Expression filterGreaterThan=Greater than filterLastDays=Last x days filterNextDays=Next x days filterLastHours=Last x hours filterNextHours=Next x hours filterLessThan=Less than filterBefore=Before filterAfter=After filterEqualsDate=Equals date filterEqualsNotDate=Does not equals date filterEqualsColumn=Equals column filterEqualsNotColumn=Does not equals column filterContainsColumn=Contains column filterContainsNotColumn=Does not contain column filterGreaterThanColumn=Greater than column filterLessThanColumn=Less than column filterBeforeColumn=Before column filterAfterColumn=After column filterUntitled=Untitled filterEmpty=Empty filterShowing=Showing {0} of {1} ({2}) popupMenuAddField=Add Filter popupMenuAddFieldMsg=Add {0} filters? export=Export exportToolTip=Export Data exportTableData=Table Data #Text Dialog textToClipboard=Copy to Clipboard textToFile=Save to file textFromClipboard=Paste from Clipboard textFromFile=Load from file textClose=Close textLoadFailMsg=Failed to load file textLoadFailTitle=Load Failed textSaveFailMsg=Failed to save file textSaveFailTitle=Save Failed textImport=Import textInvalid=Invalid Input textEmpty=Nothing to import textExport=Export #JSimpleColorPicker colorDefault=Default colorNone=None colorCustom=Custom... ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsAgents.properties ================================================ agents=Agents columnName=Agent columnCorporation=Corporation columnFaction=Faction columnLevel=Level columnLocation=Location columnSecurity=Security columnSystem=System columnConstellation=Constellation columnRegion=Region columnDivision=Division columnType=Type columnLocator=Locator columnAgentID=Agent ID columnCorporationID=Corporation ID columnFactionID=Faction ID ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsAssets.properties ================================================ assets=Assets average=Average value of shown assets reprocessColors=Reprocess reprocessColorsToolTip=Reprocess (Red) or Sell (Green) treemap=Treemap treemapToolTip=Treemap view by group totalCount=Total number of shown assets totalReprocessed=Total reprocessed value of shown assets totalValue=Total value of shown assets totalVolume=Total volume of shown assets clearNew=Clear New columnName=Name columnNameType=Type Name columnNameCustom=Item Name columnTags=Tags columnGroup=Group columnCategory=Category columnSlot=Slot Type columnChargeSize=Charge Size columnOwner=Owner columnLocation=Location columnSecurity=Security columnSystem=System columnConstellation=Constellation columnRegion=Region columnFactionWarfareSystemOwner=Faction Warfare columnFactionWarfareSystemOwnerToolTip=System faction warfare occupier columnContainer=Container columnFlag=Flag columnPrice=Price columnPriceToolTip=Default price from the market price API (Options > Options... > Market Prices) columnPriceSellMin=Sell Min columnPriceSellMinToolTip=Minimum sell price from the market price API columnPriceBuyMax=Buy Max columnPriceBuyMaxToolTip=Maximum buy price from the market price API columnPriceReprocessed=Reprocessed columnPriceReprocessedToolTip=Price if asset was reprocessed columnPriceManufacturing=Manufacturing columnPriceManufacturingToolTip=The cost of manufacturing this item type (Options > Options... > Manufacturing) columnTransactionPriceLatest=Last Purchase columnTransactionPriceLatestToolTip=Most recent purchase price columnTransactionPriceAverage=Avg Purchase columnTransactionPriceAverageToolTip=Average purchase price columnTransactionPriceMaximum=Max Purchase columnTransactionPriceMaximumToolTip=Maximum purchase price columnTransactionPriceMinimum=Min Purchase columnTransactionPriceMinimumToolTip=Minimum purchase price columnPriceBase=Base Price columnPriceBaseToolTip=A price set by CCP columnPriceReprocessedDifference=+ Reprocessed columnPriceReprocessedDifferenceToolTip=Reprocessed - Price columnPriceReprocessedPercent=% Reprocessed columnPriceReprocessedPercentToolTip=Reprocessed / Price * 100 columnValueReprocessed=Reprocessed Value columnValueReprocessedToolTip=Reprocessed * Count columnValue=Value columnValueToolTip=Price * Count columnValuePerVolume=isk/m3 columnCount=Count columnTypeCount=Type Count columnTypeCountToolTip=Count of all assets of this type columnMeta=Meta columnTech=Tech columnVolume=Volume columnVolumeTotal=Total Volume columnVolumeTotalToolTip=Volume * Count columnVolumePackaged=Packaged Volume columnVolumePackagedToolTip=Packaged volume of a single asset columnSingleton=Singleton columnAdded=Added columnAddedToolTip=The date this assets was first seen columnMaterialEfficiency=ME columnMaterialEfficiencyToolTip=Blueprint Material Efficiency columnTimeEfficiency=TE columnTimeEfficiencyToolTip=Blueprint Time Efficiency columnRuns=Runs columnRunsToolTip=Blueprint Copy Runs columnStructure=Structure columnStructureToolTip=Asset is in a structure columnItemID=Item ID columnItemIDToolTip=Globally unique ID for this asset (changes when packaged/unpacked/stacked) columnLocationID=Location ID columnLocationIDToolTip=ID for the location of this assets columnTypeID=Type ID columnTypeIDToolTip=All assets of this type have this ID ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsContracts.properties ================================================ auction=Auction availabilityPrivate=Private availabilityPublic=Public bought=Total price of shown completed buy contracts buying=Total price of shown outstanding buy contracts collapse=Collapse collateralAcceptor=Collateral of cargo being transported for shown courier contracts collateralIssuer=Collateral of cargo being shipped for shown courier contracts columnAccepted=Accepted columnAcceptor=Acceptor columnAssignee=Assignee columnAvailability=Availability columnBuyout=Buyout columnCollateral=Collateral columnCompleted=Completed columnContractID=Contract ID columnEndStation=End Station columnExpired=Expired columnIncluded=Included columnIssued=Issued columnForCorp=Corporation columnIssuer=Issuer columnIssuerCorp=Issuer Corp columnItemID=Item ID columnMarketPrice=Market Price columnPriceReprocessed=Reprocessed columnPriceReprocessedToolTip=Price if contract item was reprocessed columnPriceManufacturing=Manufacturing columnPriceManufacturingToolTip=The cost of manufacturing this item type (Options > Options... > Manufacturing) columnMarketValue=Market Value columnMarketValueToolTip=Market Price * Quantity columnValueReprocessed=Reprocessed Value columnValueReprocessedToolTip=Reprocessed * Count columnValueManufacturing=Manufacturing Value columnValueManufacturingToolTip=Manufacturing * Count columnMaterialEfficiency=ME columnMaterialEfficiencyToolTip=Blueprint Material Efficiency columnName=Name columnNumDays=Num Days columnOwned=Owned columnOwnedToolTip=Owned by a shown character account columnPrice=Price columnQuantity=Quantity columnRecordID=Record ID columnReward=Reward columnRuns=Runs columnRunsToolTip=Blueprint Copy Runs columnSingleton=Singleton columnStartStation=Start Station columnStatus=Status columnTimeEfficiency=TE columnTimeEfficiencyToolTip=Blueprint Time Efficiency columnTitle=Title columnType=Type columnTypeID=Type ID columnVolume=Volume courier=Courier excluded=Excluded expand=Expand included=Included itemExchange=Item Exchange loan=Loan missing=[Contract details missing] notAccepted=Not Accepted packaged=Packaged publicContract=Public contractCount=Count of currently filtered contracts sellingPrice=Total price of shown outstanding sell contracts sellingAssets=Total value of assets in shown outstanding sell contracts sold=Total price of shown completed sell contracts status=Status statusArchived=Archived statusCancelled=Cancelled statusCompleted=Completed statusCompletedByContractor=Completed by Contractor statusCompletedByIssuer=Completed by Issuer statusDeleted=Deleted statusFailed=Failed statusInProgress=In Progress statusOutstanding=Outstanding statusRejected=Rejected statusReversed=Reversed statusUnknown=Unknown title=Contracts type=Type unknown=Unknown unpackaged=Unpackaged ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsItems.properties ================================================ items=Items columnName=Name columnGroup=Group columnCategory=Category columnSlot=Slot Type columnChargeSize=Charge Size columnPriceBase=Base Price columnPriceReprocessed=Reprocessed columnPriceManufacturing=Manufacturing columnPriceManufacturingToolTip=The cost of manufacturing this item type (Options > Options... > Manufacturing) columnMeta=Meta columnTech=Tech columnVolume=Volume columnVolumePackaged=Volume Packaged columnTypeID=TypeID ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsJobs.properties ================================================ active=Active all=All bpc=Copy bpo=Original completed=Completed count=Total number of shown industry jobs industry=Industry Jobs install=Install Date inventionSuccess=Percent of shown invention jobs successfully completed manufactureJobsValue=Output value of shown active manufacturing jobs no=No character found status=Status columnState=Status columnActivity=Activity columnName=Name columnGroup=Group columnOwner=Owner columnInstaller=Installer columnOwned=Owned columnOwnedToolTip=Owned by a shown character account columnCompletedCharacter=Completed By columnLocation=Location columnSystem=System columnConstellation=Constellation columnRegion=Region columnStartDate=Start Date columnEndDate=End Date columnCompletedDate=Completed Date columnTimeLeft=Time Left columnPauseDate=Paused Date columnRuns=Runs columnOutputCount=Output Count columnOutputValue=Output Value columnOutputVolume=Output Volume columnOutputVolumeToolTip=Total packaged volume of output items columnOutputType=Output Type columnOutputGroup=Output Group columnOutputCategory=Output Category columnBPO=BPO columnMaterialEfficiency=ME columnTimeEfficiency=TE columnCost=Job Cost columnJobID=Job ID ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsJournal.properties ================================================ clearNew=Clear New contextAllianceID=AllianceID contextCharacterID=CharacterID contextContractID=ContractID contextCorporationID=CorporationID contextEveID=EveID contextIndustryJobID=IndustryJobID contextPlanetID=PlanetID contextStationID=StationID contextSystemID=SystemID contextStructureID=StructureID contextTransactionID=TransactionID contextTypeID=TypeID contracts=Contracts chart=Chart chartTotal=Total chartTitle=Journal Chart close=Close findIn=Find in industryJobs=Industry Jobs noDataFound=No data found rattingIncome=Ratting income title=Journal total=Total for shown entries totalNegative=Expenditure for shown entries totalPositive=Income for shown entries transactions=Transactions columnAccountKey=Wallet Division columnAmount=Amount columnBalance=Balance columnDate=Date columnOwner=Owner columnOwnerName1=From columnOwnerName2=To columnReason=Reason columnRefType=Type columnTaxAmount=TaxAmount columnTags=Tags columnAdded=Added columnAddedToolTip=The date this journal was first seen columnContextName=Context columnContextType=Context Type columnContextID=Context ID ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsLoadout.properties ================================================ # #Sat Nov 27 13:51:18 CET 2010 cancel=Cancel collapse=Collapse columnLocation=Location columnName=Name columnOwner=Owner columnSlot=Slot columnValue=Value columnShip=Ship description=Description\: empty=Empty Name expand=Expand export=Export Fitting exportEft=EFT exportEveXml=Eve Format exportEveXmlAll=All Ships exportEveXmlSelected=Selected Ship exportTableData=Table Data flagCargo=Cargo flagDroneBay=Drone Bay flagHighSlot=High Slot flagLowSlot=Low Slot flagMediumSlot=Medium Slot flagOther=Other flagRigSlot=Rig Slot flagSubSystem=Sub System flagTotalValue=Total Value name=Name\: name1=Name can not be empty... no=No character found no1=No ships found oK=OK owner=Owner ship=Ship Fittings ship1=Ship totalAll=Total totalModules=Modules totalShip=Ship whitespace10=\ {0} ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsLoyaltyPoints.properties ================================================ loyaltyPoints=Loyalty Points columnOwner=Owner columnCorporationName=Corporation columnLoyaltyPoints=Loyalty Points total=Total ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsMaterials.properties ================================================ all=All collapse=Collapse columnCount=Count columnGroup=Group columnLocation=Location columnName=Name columnPrice=Price columnValue=Value columnTypeID=TypeID expand=Expand grandTotal=Grand Total includeCommodity=Commodity includeMaterials=Materials includeOre=Ore includePI=Planetary Materials materials=Materials no=No character found summary=Summary total=Total ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsMining.properties ================================================ average=Average value of shown mining entries character=Character corporation=Corporation count=Count extractions=Extractions extractionsActiveSoon=Soon/Active from=From grandTotal=Grand Total graphToolTip={0}: {1}
Date: {2} groupBasic={0} groupName={0} {1} groupTotal={0} Total includeZero=Always include zero miningGraph=Mining Graph miningLog=Mining Log scaleLinear=Linear scaleLogarithmic=Logarithmic show=Show to=To totalCount=Total number of shown mining entries totalReprocessed=Total reprocessed value of mining entries totalValue=Total value of mining entries totalVolume=Total volume of shown mining entries valueOre=Ore valueReprocessed=Reprocessed valueReprocessedMax=Max Reprocessed volume=Volume columnDate=Date columnName=Name columnGroup=Group columnCategory=Category columnOwner=Owner columnLocation=Location columnCount=Count columnPriceOre=Price Ore columnPriceReprocessed=Price Reprocessed columnPriceReprocessedToolTip=Yield with skills set in: Options > Options... > Reprocessed columnPriceReprocessedMax=Price Reprocessed Max columnPriceReprocessedMaxToolTip=Max possible yield columnValueOre=Value Ore columnValueReprocessed=Value Reprocessed columnValueReprocessedToolTip=Yield with skills set in: Options > Options... > Reprocessed columnValueReprocessedMax=Value Reprocessed Max columnValueReprocessedMaxToolTip=Max possible yield columnVolume=Volume columnValuePerVolumeOre=Isk/m3 Ore columnValuePerVolumeReprocessed=Isk/m3 Reprocessed columnValuePerVolumeReprocessedToolTip=Yield with skills set in: Options > Options... > Reprocessed columnValuePerVolumeReprocessedMax=Isk/m3 Reprocessed Max columnValuePerVolumeReprocessedMaxToolTip=Max possible yield columnCorporation=Corporation columnForCorporation=Type columnExtractionStartTime=Extraction Start columnMoon=Moon columnChunkArrivalTime=Chunk Arrival columnNaturalDecayTime=Natural Decay ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsNpcStanding.properties ================================================ npcStanding=NPC Standing columnOwner=Owner columnAgent=Agent columnCorporation=Corporation columnFaction=Faction columnAgentLevel=Level columnAgentDivision=Division columnAgentType=Agent Type columnType=Type columnRawStanding=Raw Standing columnRawStandingToolTip=Unmodified standing (used by broker's fee calculations) columnStanding=Standing columnStandingToolTip=Standing modified by connections/criminal connections/diplomacy columnStandingMax=Max Standing columnStandingMaxToolTip=Standing with level 5 connections/criminal connections/diplomacy bonus columnLocation=Location columnSecurity=Security columnSystem=System columnConstellation=Constellation columnRegion=Region columnID=ID typeAgent=Agent typeCorporation=Corporation typeFaction=Faction ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsOrders.properties ================================================ # #Sat Nov 27 14:46:33 CET 2010 activeBuyOrders=Buy (active) activeSellOrders=Sell (active) buy=Buy clearNew=Clear New columnOrderType=Type columnName=Name columnGroup=Group columnCategory=Category columnVolumeRemain=Quantity Remaining columnVolumeTotal=Quantity Total columnPrice=Price columnOutbidPrice=Outbid $ columnOutbidPriceToolTip=Best outbid price in order range columnOutbidCount=Outbid # columnOutbidCountToolTip=Total count of remaining items in orders underbidding your order columnOutbidDelta=Outbid \u0394 columnOutbidDeltaToolTip=Outbid price compared to order price columnEveUi=Market Details columnEveUiToolTip=1. Open market details in the eve client (character have to be in-game)
2. Copy the fixed outbid price to the clipboard
3. Focus the characters eve client columnBrokersFee=Broker's Fee columnBrokersFeeToolTip=Broker's Fee payed so far (May not include everything due to ESI limitations) columnEdits=Edits columnEditsToolTip=Times this order was edited (May not include everything due to ESI limitations) columnPriceReprocessed=Reprocessed columnPriceManufacturing=Manufacturing columnPriceManufacturingToolTip=The cost of manufacturing this item type (Options > Options... > Manufacturing) columnIssued=Updated columnIssuedToolTip=Last known issued date columnIssuedFirst=Issued columnIssuedFirstToolTip=First known issued date (may not be the created date due to ESI limitations) columnExpires=Expires columnChanged=Changed columnChangedToolTip=The date this market order was last changed columnRange=Range columnRemainingValue=Remaining Value columnStatus=Status columnMinimumQuantity=Minimum Quantity columnOwner=Owner columnIssuedBy=Issued By columnOwned=Owned columnOwnedToolTip=Owned by a shown character account columnWalletDivision=Wallet Division columnLocation=Location columnSystem=System columnConstellation=Constellation columnRegion=Region columnTransactionPrice=Transaction Price columnTransactionPriceToolTip=Opposite Price (does not include tax) columnTransactionMargin=Transaction Margin columnTransactionMarginToolTip=Transaction Price + Margin set in Options > Options... > General > Margin (does not include tax) columnTransactionProfitDifference=Transaction Profit + columnTransactionProfitDifferenceToolTip=Profit per item compared to transactions (does not include tax) columnTransactionProfitPercent=Transaction Profit % columnTransactionProfitPercentToolTip=Profit percent compared to transactions (does not include tax) columnMarketPrice=Market Price columnMarketPriceToolTip=Default price from the market price API (Options > Options... > Market Prices) columnMarketPriceSellMin=Market Sell Min columnMarketPriceSellMinToolTip=Minimum sell price from the market price API columnMarketPriceBuyMax=Market Buy Max columnMarketPriceBuyMaxToolTip=Maximum buy price from the market price API columnMarketMargin=Market Margin % columnMarketMarginToolTip=Profit percent compared to market price (does not include tax) columnMarketProfit=Market Profit + columnMarketProfitToolTip=Profit per item compared to market price (does not include tax) columnVolume=Volume columnTypeID=TypeID columnOrderID=Order ID eveUiOpen=Open lastEsiUpdateToolTip=Last Esi update lastLogUpdateToolTip=Last MarketLog update lastClipboardToolTip=Last value copied to the clipboard market=Market Orders marketLogTypeToolTip=Order type copied to the clipboard on MarketLog import none=None ownerInvalidScopeMsg=The issuing character of this order is missing the required scope.\r\nOpen the with another character? ownerInvalidScopeTitle=Invalid Owner ownerNotFoundMsg=The issuing character of this order was not found.\r\nOpen the with another character? ownerNotFoundTitle=Owner Not Found rangeStation=Station rangeSolarSystem=System rangeRegion=Region rangeJump=1 Jump rangeJumps={0} Jumps market=Market Orders sell=Sell sellOrderRangeLastToolTip=Sell order outbid range (current data) sellOrderRangeToolTip=Customize sell order range (region is the in-game default) sellOrderRangeSelcted={0} status=Status statusActive=Active statusClosed=Closed statusFulfilled=Fulfilled statusExpired=Expired statusPartiallyFulfilled=Partially Fulfilled statusCancelled=Cancelled statusPending=Pending statusCharacterDeleted=Character Deleted statusUnknown=Unknown totalSellOrders=Total value of shown sell orders totalBuyOrders=Total value of shown buy orders totalEscrow=Total escrow of shown buy orders totalToCover=Total isk to cover of shown buy orders unknownLocationsMsg=Unable to get outbid data for orders in unknown locations\r\n\ Resolve now by updating structures? unknownLocationsMsgLater=Unable to get outbid data for orders in unknown locations\r\n\ Resolve by updating structures: Update > Structures... unknownLocationsTitle=Orders in unknown locations updateNoActiveMsg=No active market orders\r\n\ (orders in unknown locations are ignored) updateNoActiveTitle=Update Cancelled updateOutbidEsi=Update updateOutbidFileBuy=Buy updateOutbidFileSell=Sell updateOutbidWhen={0} updateOutbidUpdating=Updating... updateTitle=Public Market Orders ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsOverview.properties ================================================ # #Sat Nov 27 15:02:59 CET 2010 add=Add to new group... addGroup=Add Group average=Average value of shown items clear=Clear constellations=Constellations deleteGroup=Delete Group deleteTheGroup=Delete Group\: {0}? filterShowing=
Assets {0} of {1} ({2}) groups=Groups groupName=Group Name\: loadFilter=Assets Filter locations=Locations overview=Overview owner=Owner planets=Planets regions=Regions renameGroup=Rename Group stations=Stations systems=Systems totalCount=Total number of shown items totalReprocessed=Total reprocessed value of shown items totalValue=Total value of shown items totalVolume=Total volume of shown items view=View treemap=Treemap treemapToolTip=Treemap view by name columnName=Name columnSystem=System columnConstellation=Constellation columnRegion=Region columnSecurity=Security columnVolume=Volume columnValue=Value columnValuePerVolume=isk/m3 columnCount=Count columnAverageValue=Average Value columnReprocessedValue=Reprocessed Value ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsPriceChanges.properties ================================================ title=Price Changes from=From to=To resetDates=Reset Dates owned=Owned columnName=Name columnGroup=Group columnCategory=Category columnCount=Owned columnCountToolTip=Currently owned items columnPriceFrom=Price From columnPriceTo=Price To columnChangePercent=% Change columnChangePercentToolTip=Price change in percent columnChange=+ Change columnChangeToolTip=Price change columnTotal=\u0394 Change columnTotalToolTip=Approximate value change ((from - to) * currently owned) ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsPriceHistory.properties ================================================ add=Add addTitle=Add Item clear=Clear All deleteHistorySet=Delete price history set? deleteHistorySets=Delete all {0} price history sets? edit=Edit enterName=Enter name\: from=From graphToolTip={0}: {1}
Date: {2} includeZero=Always include zero load=Load manage=Manage... manageTitle=Manage Price History Sets maxItemsMsg=You can not show more than {0} prices at the time merge=Merge price history sets mergeMax=Can not merge sets to be larger than {0} types overwrite=Overwrite price history set? remove=Remove Selected rename=Rename price history sets save=Save saveTitle=Save scaleLinear=Linear scaleLogarithmic=Logarithmic sourcejEveAssets=jEveAssets sourcezKillboard=zKillboard title=Price History to=To updateTitle=zKillboard Price History updatingMsg=You can not add items while updating from the zKillboard Price History API updatingTitle=zKillboard Price History ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsReprocessed.properties ================================================ addItem=Add Item batch=Batch: collapse=Collapse columnName=Name columnPrice=Price columnQuantity100=Quantity 100% columnQuantity100ToolTip=100% yield (not actual possible) columnQuantityMax=Quantity Max columnQuantityMaxToolTip=Max possible yield columnQuantitySkill=Quantity Skill columnQuantitySkillToolTip=Yield with skills set in: Options > Options... > Reprocessed columnTotalBatch=[Batch] columnTotalName=[Name] columnTotalPrice=[Price] columnTotalValue=[Value] columnTypeID=TypeID columnValueDifference=Value Difference columnValueMax=Value Max columnValueSkill=Value Skill expand=Expand grandTotal=Grand Total importButton=Import multiplierSign=\u00d7 price=Price: remove=Remove removeAll=Remove All selectItem=Select Item title=Reprocessed total=Total value=Value: ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsRouting.properties ================================================ # #Sat Nov 27 15:24:52 CET 2010 add=>>> addStation=+ addStationSelect=Select station addStationTitle=Add Station addSystem=+ addSystemSelect=Select system addSystemTitle=Add System algorithm=Algorithm allowed={0} of {1} allowed avoid=Avoid Systems avoidAdd=Add avoidClear=Clear avoidLoad=Load avoidManage=Manage... avoidNone=None avoidRemove=Remove avoidSave=Save calculate=Calculate Route cancel=Cancel checked=\ud83d\uddf9 deleteAvoid=Delete Avoid List deleteAvoids=Delete {0} Avoid Lists? emptyResult=Once a route has been found, it will be displayed here. enterAvoidName=Enter Avoid List Name: error=Error filteredAssets=Filtered Assets filters=Filters manageFiltersTitle=Manage Filters noSystems=There is little point in trying to calculate\nthe optimal route between two or fewer points,\nsince there is only one possible solution. noSystemsTitle=Not calculating ok=OK filtersTab=Filters importOptionsAll=Use this action for all {0,choice,1#|1<({0}) }routes importOptionsOverwriteHelp=Replace the existing route importOptionsRenameHelp=Create new route importOptionsSkipHelp=Keep the existing route mergeAvoids=Merge Avoid Lists overviewGroup=Overview Group: {0} overwriteAvoid=Overwrite Avoid List remove=<<< #\u21e8\u2192\u21d2 renameAvoid=Rename Avoid List resultArrow=\ \u21d2 resultEdit=Edit resultEditAvoid=Avoid: {0} resultEditHelp=Drag and drop to rearrange order resultEditJumps=Jumps: {0} resultEditSecurity=Security: {0} resultEditTitle=Edit Route resultEdited=Edited resultEmpty=Empty resultExport=Export resultImport=Import resultImportIDs=System IDs resultImportNames=System Names resultImportRoute=Import Route resultImportRouteEmpty=Import invalid: No systems found resultImportRouteInvalid=Import invalid: Require minimum two systems resultImportText=Text Route resultImportXml=Routing XML resultImported=Imported resultLoad=Load resultManage=Manage... resultManageTitle=Manage Routes resultOverwrite=Overwrite result? resultSave=Save resultSelectRoutes=Select Routes resultTabFull=Full Result resultTabInfo=Info resultTabShort=Result resultText=Algorithm: {0}\n\ Jumps: {1}\n\ Waypoints: {2}\n\ Security: {3}\n\ Avoid: {4}\n\ Generated in: {5} resultUiFail=Waypoint requests failed resultUiOk=Waypoint requests completed resultUiWaypoints=Add all waypoints to the in-game autopilot resultUnknownValue=Unknown resultUntitled=Untitled routeSaveTitle=Save Route routeSaveMsg=Enter route name: routingTab=Route routingTitle=Routing routeDeleteMsg=Delete {0} routes? routeDeleteTitle=Delete Route routeOverwrite=Overwrite Route routeRenameTitle=Rename Route saveFilterMsg=Enter filter name saveFilterTitle=Save Filter security=Security source=Source startEmpty=Empty startSystem=Start System total={0} of {1} total unchecked=\u2610 ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsSkills.properties ================================================ add=New Skill Plan deleteSkillPlan=Delete skill plan? deleteSkillPlans=Delete all {0} skill plans enterName=Enter name\: manage=Manage... manageTitle=Manage Skill Plans merge=Merge skill plans. noValidSkills=No valid skills found overwrite=Overwrite skill plan? rename=Rename skill plan skillPlans=Skill Plans skills=Skills skillsOverview=Skills Overview tableToolTipSkill={1} \u2192 {2} {0} ({3})
tableToolTipCompleted=All skills complete for this plan. tableToolTipMissing={0} Skills Missing:
tableToolTipTruncated=\u2026 total=Total columnSkill=Skill columnGroup=Group columnCharacter=Character columnActive=Active columnTrained=Trained columnTotal=Total columnUnallocated=Unallocated ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsSlots.properties ================================================ contractCharacter=Character Contracts contractCorporation=Corporation Contracts columnOwner=Owner grandTotal=Grand Total manufacturing=Manufacturing marketOrders=Market Orders reactions=Reactions research=Research tableHeader=View tableHeaderIcon=Compact view using icons tableHeaderText=Default view using text title=Slots columnManufacturingDone=Manufacturing Done columnManufacturingFree=Manufacturing Free columnManufacturingActive=Manufacturing Active columnManufacturingMax=Manufacturing Max columnResearchDone=Research Done columnResearchFree=Research Free columnResearchActive=Research Active columnResearchMax=Research Max columnReactionsDone=Reactions Done columnReactionsFree=Reactions Free columnReactionsActive=Reactions Active columnReactionsMax=Reactions Max columnMarketOrdersFree=Market Orders Free columnMarketOrdersActive=Market Orders Active columnMarketOrdersMax=Market Orders Max columnContractCharacterFree=Character Contracts Free columnContractCharacterActive=Character Contracts Active columnContractCharacterMax=Character Contracts Max columnContractCorporationFree=Corporation Contracts Free columnContractCorporationActive=Corporation Contracts Active columnContractCorporationMax=Corporation Contracts Max columnCurrentStation=Station columnCurrentSystem=System columnCurrentConstellation=Constellation columnCurrentRegion=Region columnCurrentShip=Ship ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsStockpile.properties ================================================ addBlueprintMsg=Add Blueprints as: addBlueprintTitle=Add Blueprint Options addFormulaMsg=Add Formula as: addFormulaTitle=Add Formula Options addFilter=Add addItem=Add Item addLocation=Add Location addStockpileItem=Add Stockpile Item addStockpileTitle=Add Stockpile addToNewStockpile=Add to new stockpile... addToStockpile=Add To blueprintFacility=Facility blueprintMe=Blueprint ME blueprintRigs=Rigs blueprintSecurity=Security blueprintType=Blueprint Type blueprints=Blueprints cancel=Cancel clipboardStockpile=Copy to Clipboard cloneStockpile=Clone cloneStockpileFilter=Clone cloneStockpileTitle=Clone Stockpile close=Close collapse=Collapse constellation=Constellation container=Container containerIncludeSubs=Include Subs containerIncludeSubsToolTip=Include sub containers copy=Blueprint Copy countMinimum=Minimum Count csv=CSV delete=Delete deleteItem=Delete Item deleteItemTitle=Delete Item deleteItems=Delete {0} items? deleteStockpile=Delete deleteStockpileTitle=Delete Stockpile deleteStockpileMsg=Delete {0} Stockpiles duplicate=Duplicate edit=Edit editCell=Double click to edit editGroup=Edit Group editItem=Edit Item editStockpile=Edit editStockpileFilter=Edit editStockpileItem=Edit Stockpile Item editStockpileTitle=Edit Stockpile estimatedMarketValue=Estimated market value: eveMultibuy=Eve Multibuy eveUiOpen=Open expand=Expand exportStockpilesXml=Stockpiles XML exportStockpilesText=Stockpiles Text filters=Add Filter flag=Flag flagIncludeSubs=Include Subs flagIncludeSubsToolTip=Include sub containers getShoppingList=Shopping List groupAddEmpty=Group name can not be empty groupAddExist=Group already exist.\r\nAdd to existing group? groupAddName=Enter Group Name: groupAddNew=Add to new group... groupAddTitle=Add Group groupCollapse=Collapse Groups groupExpand=Expand Groups groupMenu=Group groupRenameExist=Group already exist groupRenameTitle=Rename Group groupShoppingListMsg=Include hidden stockpiles? groupShoppingListTitle=Group Shopping List groups=Groups hideStockpile=Hide importButton=Import importEveXml=Eve Xml Fit importStockpilesText=Stockpiles Text importText=Text Formats importTextFailedMsg=Failed to import stockpile text importXmlFailedMsg=Failed to load stockpile file importStockpilesXml=Stockpiles XML importOptionsAll=Use this action for all {0,choice,1#|1<({0}) }stockpiles importFailedTitle=Import Failed importOptions=Import Options importOptionsAdd=Add importOptionsAddHelp=Add to stockpile(s) importOptionsKeep=Keep importOptionsKeepHelp=Import unchanged importOptionsMerge=Merge importOptionsMergeHelp=Merge the stockpiles together importOptionsNew=New importOptionsNewHelp=Create new stockpile importOptionsOverwrite=Overwrite importOptionsOverwriteHelp=Replace the existing stockpile importOptionsRename=Rename importOptionsRenameHelp=Create new stockpile importOptionsSkip=Skip importOptionsSkipHelp=Do not import importOptionsTemplate=Template importOptionsTemplateHelp=New identical stockpiles include=Include includeCount={0}/4 includeHelp=No include selected includeAssets=Assets includeAssetsTip=Owned assets (Assets) includeJobs=Manufacturing includeJobsTip=Items being manufactured/copied (Industry Jobs) includeBuyOrders=Orders: Buying includeBuyOrdersTip=Unfulfilled buy market orders (Market Orders) includeSellOrders=Orders: Selling includeSellOrdersTip=Unfulfilled sell market orders (Market Orders) includeBuyTransactions=Orders: Bought includeBuyTransactionsTip=Items bought via market orders - After the last asset update (Transactions) includeSellTransactions=Orders: Sold includeSellTransactionsTip=Items sold via market orders - After the last asset update (Transactions) includeBuyingContracts=Contracts: Buying includeBuyingContractsTip=Pending buy contracts (Contracts) includeBoughtContracts=Contracts: Bought includeBoughtContractsTip=Items bought via contracts - After the last asset update (Contracts) includeSellingContracts=Contracts: Selling includeSellingContractsTip=Pending sell contracts (Contracts) includeSoldContracts=Contracts: Sold includeSoldContractsTip=Items sold via contracts - After the last asset update (Contracts) item=Item items=Items itemsMissing=Items Missing itemsOwned=Items Owned itemsRequired=Items Required itemsShoppingList=Items: jobsDays=Manufacturing Duration jobsDaysLess=Days or less jobsDaysMore=Days or more jobsDaysTip=Manufacturing/copying completing in X days or less/more jobsDaysWarning=Manufacturing not included location=Location marketDetailsOwnerToolTip=The character that will be used for opening market details in the eve client (character have to be in-game) match=Matching matchAll=Contains All matchAllTip=Only include asset/contract that contains all the stockpile items matchExclude=Exclude matchInclude=Include materialsManufacturing=Manufacturing Materials materialsReaction=Reaction Materials me=ME multiple=Multiple multiplier=Multiplier multiplierIgnore=Ignore stockpile/subpile multiplier multiplierSign=\u00d7 myLocations=Only show my locations name=Name needed=Surplus: newStockpile=New Stockpile noLocationsFound=No locations found none=None nothingNeeded=Nothing Needed now=Stock: ok=OK original=Blueprint Original owner=Owner percent=% percentFull=Multiplier Percent: percentIgnore=Hide Above: planet=Planet region=Region remove=Remove renameStockpileTitle=Rename Stockpile runs=Blueprint Runs selectFits=Select Fits selectGroup=Select Group: selectStockpiles=Select Stockpiles shoppingList=Shopping List showHidden=Show Hidden showHide=Show/Hide showStockpiles=Stockpiles showSubpileTree=Show Subpile Tree shownValueNeeded=Total surplus value of shown items shownValueNow=Total stock value of shown items shownVolumeNeeded=Total surplus volume of shown items shownVolumeNow=Total stock volume of shown items singleton=Singleton source=Source spreadsheet=Spreadsheet station=Station stockpile=Stockpile stockpileAvailable=Available: stockpileLocation=Location: stockpileOwner=Owner: stockpileShoppingList=Stockpiles subpileShoppingList=Subpiles: subpiles=Subpiles system=System totalStockpile=Total totalToHaul=Total m3 to be hauled: universe=Universe columnName=Name columnGroup=Group columnCategory=Category columnSlot=Slot Type columnChargeSize=Charge Size columnMeta=Meta columnEveUi=Market Details columnEveUiToolTip=1. Open market details in the eve client (character have to be in-game)
2. Focus the characters eve client columnCountNow=Total Stock columnCountNowInventory=Assets columnCountNowBuyOrders=Buy Orders columnCountNowBuyTransactions=Buy Transactions columnCountNowSellOrders=Sell Orders columnCountNowSellTransactions=Sell Transactions columnCountNowJobs=Industry Jobs columnCountNowBuyingContracts=Buying Contracts columnCountNowBoughtContracts=Bought Contracts columnCountNowSellingContracts=Selling Contracts columnCountNowSoldContracts=Sold Contracts columnCountNeeded=Surplus columnCountMinimum=Target columnCountMinimumMultiplied=Target \u00d7 columnPercentNeeded=Surplus % columnPrice=Price columnPriceToolTip=Default price from the market price API (Options > Options... > Market Prices) columnPriceSellMin=Sell Min columnPriceSellMinToolTip=Minimum sell price from the market price API columnPriceBuyMax=Buy Max columnPriceBuyMaxToolTip=Maximum buy price from the market price API columnPriceTransactionAverage=Avg Transaction columnPriceTransactionAverageToolTip=Average transaction price (bought and sold) columnTags=Tags columnValueNow=Stock Value columnValueNeeded=Surplus Value columnVolumeNow=Stock Volume columnVolumeNeeded=Surplus Volume getFilterStockpileName=[Stockpile] Name getFilterStockpileOwner=[Stockpile] Owner getFilterStockpileLocation=[Stockpile] Location getFilterStockpileFlag=[Stockpile] Flag getFilterStockpileContainer=[Stockpile] Container ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsTracker.properties ================================================ all=All allProfiles=All Profiles assets=Assets assetsFilters=Assets Filters cancel=Cancel characterWallet=Character Wallet checkAllLocationsMsg=Due to a bug some tracker locations may have been unchecked\r\n\ \r\n\ Press OK to include all locations\r\n\ Press Cancel to manually check the locations are set correct\r\n\ \r\n checkAllLocationsTitle=Tracker Locations clear=Clear contractCollateral=Contract Collateral contractValue=Contracts characterCorporations=Character Corporations corporationWallet=Corporation Wallet date=Date day1=1 Day delete=Delete deleteSelected=Delete selected tracker data point?\n\ \n\ Warning:\n\ - The data can not be restored once deleted.\n\ - This will delete the entire data point (Total, Asset, Wallet Balance, etc.)\n\ \n division=Division {0} edit=Edit empty=Empty enterNewValue=Enter new value error=Error escrows=Escrows escrowsToCover=Escrows To Cover filterTitle=Tracker Filter from=From grandTotal=Grand Total help=Double click the chart to edit values helpBugData=Bugged helpBugDataToolTip=Assets in containers not assigned to correct corporation hangar division helpLegacyData=Legacy helpLegacyDataToolTip=Legacy data is not filterable helpNewData=OK helpNewDataToolTip=No known bugs implants=Implants importFile=Import file... importFileImport=Importing... importFileInvalidMsg=Not a valid tracker data file importFileOptionsKeep=Merge: On duplicates use existing data importFileOptionsMsg=Warning: This action can not be undone!\n\ \n\ Select how to import: importFileOptionsOverwrite=Merge: On duplicates use imported data importFileOptionsReplace=Delete: Delete all exisitng data and replaced with imported data importFileTitle=Tracker Import includeZero=Always include zero invalid=Invalid input invalidNumberMsg=Not a valid number, try again... invalidNumberTitle=Invalid Input knownLocations=Known Locations manufacturing=Manufacturing month1=1 Month months3=3 Months months6=6 Months newSelected=Add new locations selected noDataFound=No data found note=Note notesAdd=Add Note notesDeleteMsg=Delete note:\r\n{0} notesDeleteTitle=Delete Note notesEditMsg=Enter Note: notesEditTitle=Edit Note ok=OK other=Other quickDate=Quick Date... reset=Reset search=Search scaleLinear=Linear scaleLogarithmic=Logarithmic selectDivision=Select Division selectFlag=Select Flag selectLocation=Select Location selectOwner=Select Owner selectionDate=Date of selected tracker point selectionIsk=Total value of selected tracker point selectionNote=Note selectionShortDate=Date selectionShortIsk=Value selectionShortNote=Note sellOrders=Sell Orders show=Show skillPointFilters=Skill Point Filters skillPointValue=Skill Points skillPoints=Skill Points (SP) statusAssets=Assets value change from start to end date statusBalance=ISK balance change from start to end date statusContractCollateral=Contract collateral change from start to end date statusContractValue=Contract value change from start to end date statusEscrows=Escrows change from start to end date statusEscrowsToCover=Escrows to cover change from start to end date statusImplants=Implants value change from start to end date statusManufacturing=Manufacturing change from start to end date statusSellOrders=Sell orders change from start to end date statusSkillPointValue=Value of skill points change from start to end date statusTotal=Total change from start to end date title=Tracker to=To total=Total unknownLocations=Unknown Locations walletBalance=Wallet Balance walletBalanceFilters=Wallet Filters week1=1 Week week2=2 Weeks year1=1 Year years2=2 Years columnShow=Include columnName=Name columnMinimum=SP Include Threshold [Editable] ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsTransaction.properties ================================================ # #Sat Nov 27 14:46:33 CET 2010 bothAvg=Average buy and sell price bothCount=Total items bought and sold bothTitle=Buy and sell bothTotal=Total bought and sold buy=Buy buyAvg=Average buy price buyCount=Total items bought buyTitle=Buy buyTotal=Total bought clearNew=Clear New corporation=Corporation personal=Personal sell=Sell sellAvg=Average sell price sellCount=Total items sold sellTitle=Sell sellTotal=Total sold title=Transactions columnTransactionType=Type columnName=Name columnGroup=Group columnCategory=Category columnQuantity=Quantity columnPrice=Price columnTax=Tax columnClientName=Client columnStationName=Station columnSystem=System columnConstellation=Constellation columnRegion=Region columnTags=Tags columnTransactionPrice=Transaction Price columnTransactionPriceToolTip=Opposite Price (include tax) columnTransactionMargin=Transaction Margin columnTransactionMarginToolTip=Transaction Price + Margin set in Options > Options... > General > Margin (include tax) columnTransactionProfitDifference=Transaction Profit + columnTransactionProfitDifferenceToolTip=Profit per item (include tax) columnTransactionProfitPercent=Transaction Profit % columnTransactionProfitPercentToolTip=Profit percent (include tax) columnTransactionFor=For columnValue=Value columnTransactionDate=Date columnOwner=Owner columnLocation=Location columnAccountKey=Wallet Division columnAdded=Added columnAddedToolTip=The date this transaction was first seen columnVolume=Volume columnTransactionID=Transaction ID ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsTree.properties ================================================ categories=Categories collapse=Collapse expand=Expand locationAssetSafety=Asset Safety locationClones=Clones locationContracts=Contracts locationDeliveries=Deliveries locationItemHangar=Item Hangar locationMarketOrders=Market Orders locationShipHangar=Ship Hangar locations=Locations title=Tree ================================================ FILE: src/main/resources/net/nikr/eve/jeveasset/i18n/TabsValues.properties ================================================ # #Sat Nov 27 15:48:46 CET 2010 columnAssets=Assets columnBestAsset=Best Asset columnBestModule=Best Module columnBestShip=Best Ship columnBestShipFitted=Best Ship with Fit columnContractCollateral=Contract Collateral columnContractValue=Contracts columnEscrows=Escrows columnEscrowsToCover=Escrows (To Cover) columnManufacturing=Manufacturing columnOwner=Owner columnSellOrders=Sell Orders columnSkillPointValue=Skill Points columnTotal=Total columnWalletBalance=Wallet Balance columnWalletDivision1=Division 1 columnWalletDivision2=Division 2 columnWalletDivision3=Division 3 columnWalletDivision4=Division 4 columnWalletDivision5=Division 5 columnWalletDivision6=Division 6 columnWalletDivision7=Division 7 columnCurrentStation=Station columnCurrentSystem=System columnCurrentConstellation=Constellation columnCurrentRegion=Region columnCurrentShip=Ship grandTotal=Grand Total none=none empty= title=Isk skillPointFilters=Skill Point Filters oldTitle=Values oldNoCharacter=No character found oldNoCorporation=No corporation found ================================================ FILE: src/site/site.xml ================================================ org.apache.maven.skins maven-fluido-skin 1.2.1 ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/ProgramTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset; import org.junit.Test; import static org.junit.Assert.*; public class ProgramTest extends TestUtil { @Test public void isDevBuild() { assertFalse("Program.PROGRAM_DEV_BUILD = true (not allowed to be committed)", Program.isDevBuild()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/TestUtil.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset; import ch.qos.logback.classic.Level; import java.io.File; import net.nikr.eve.jeveasset.data.profile.Profile; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.junit.AfterClass; import org.junit.BeforeClass; public class TestUtil { @BeforeClass public static void initLog() { Main.setLogLocation(true); CliOptions.get().setPortable(true); FileUtil.enableTestPath(); System.setProperty("http.agent", Program.PROGRAM_USER_AGENT); Settings.setTestMode(true); } @AfterClass public static void cleanup() { Profile profile = new Profile(); deleteProfileFilename(profile.getSQLiteFilename()); deleteProfileFilename(profile.getBackupSQLiteFilename()); deleteProfileFilename(FileUtil.getPathAssetAdded()); deleteProfileFilename(FileUtil.getPathStockpileIDsDatabase()); deleteProfileFilename(FileUtil.getPathTrackerData()); } protected static void setLoggingLevel(Level level) { ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) org.slf4j.LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME); root.setLevel(level); } private static void deleteProfileFilename(String filename) { File file = new File(filename); if (file.exists() && !file.delete()) { throw new RuntimeException("Failed to delete:" + filename); } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/profile/StockpileIDsTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.profile; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Set; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.junit.AfterClass; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.BeforeClass; import org.junit.Test; public class StockpileIDsTest extends TestUtil { private static final String TABLE_1 = "test_table_1"; private static final String TABLE_2 = "test_table_2"; private static final long VALUE = 1234L; private static final Set VALUES = Collections.singleton(VALUE); //Database file private static StockpileIDs stockpileIDs; @BeforeClass public static void before() { stockpileIDs = new StockpileIDs(TABLE_1, true); } @AfterClass public static void after() { new File(FileUtil.getPathStockpileIDsDatabase()).delete(); stockpileIDs.removeTable(); } @Test public void testSetConnectionUrl() { } @Test public void testLoad() { } @Test public void testTableExist() { } @Test public void testRemoveTable() { } @Test public void testGetHidden() { assertEquals(0, stockpileIDs.getHidden().size()); assertTrue(stockpileIDs.getHidden().isEmpty()); stockpileIDs.hide(VALUE); assertEquals(1, stockpileIDs.getHidden().size()); //Cleanup stockpileIDs.show(VALUE); assertEquals(0, stockpileIDs.getHidden().size()); } @Test public void testIsHidden() { assertEquals(0, stockpileIDs.getHidden().size()); assertFalse(stockpileIDs.isHidden(VALUE)); stockpileIDs.hide(VALUE); assertTrue(stockpileIDs.isHidden(VALUE)); //Cleanup stockpileIDs.show(VALUE); assertEquals(0, stockpileIDs.getHidden().size()); } @Test public void testIsShown() { assertEquals(0, stockpileIDs.getHidden().size()); assertTrue(stockpileIDs.isShown(VALUE)); stockpileIDs.hide(VALUE); assertFalse(stockpileIDs.isShown(VALUE)); //Cleanup stockpileIDs.show(VALUE); assertEquals(0, stockpileIDs.getHidden().size()); } @Test public void testSetHidden() { assertEquals(0, stockpileIDs.getHidden().size()); stockpileIDs.setHidden(VALUES); assertTrue(stockpileIDs.isHidden(VALUE)); assertEquals(1, stockpileIDs.getHidden().size()); stockpileIDs.setHidden(VALUES); assertTrue(stockpileIDs.isHidden(VALUE)); assertEquals(1, stockpileIDs.getHidden().size()); //Cleanup stockpileIDs.show(VALUE); assertEquals(0, stockpileIDs.getHidden().size()); } @Test public void testHide() { assertEquals(0, stockpileIDs.getHidden().size()); stockpileIDs.hide(VALUE); assertTrue(stockpileIDs.isHidden(VALUE)); assertEquals(1, stockpileIDs.getHidden().size()); stockpileIDs.hide(VALUE); assertTrue(stockpileIDs.isHidden(VALUE)); assertEquals(1, stockpileIDs.getHidden().size()); //Cleanup stockpileIDs.show(VALUE); assertEquals(0, stockpileIDs.getHidden().size()); } @Test public void testSetShown() { assertEquals(0, stockpileIDs.getHidden().size()); stockpileIDs.hide(VALUE); assertTrue(stockpileIDs.isHidden(VALUE)); stockpileIDs.setNewDatabase(true); stockpileIDs.setShown(VALUES, Collections.singletonList(new Stockpile("some name", VALUE, new ArrayList<>(), 1.0, false))); stockpileIDs.setNewDatabase(false); assertFalse(stockpileIDs.isHidden(VALUE)); assertEquals(0, stockpileIDs.getHidden().size()); } @Test public void testShow() { assertEquals(0, stockpileIDs.getHidden().size()); stockpileIDs.hide(VALUE); assertTrue(stockpileIDs.isHidden(VALUE)); assertEquals(1, stockpileIDs.getHidden().size()); stockpileIDs.show(VALUE); assertFalse(stockpileIDs.isHidden(VALUE)); assertEquals(0, stockpileIDs.getHidden().size()); stockpileIDs.show(VALUE); assertFalse(stockpileIDs.isHidden(VALUE)); assertEquals(0, stockpileIDs.getHidden().size()); } @Test public void testRenameTable() { assertEquals(0, stockpileIDs.getHidden().size()); stockpileIDs.hide(VALUE); stockpileIDs.renameTable(TABLE_2); assertTrue(stockpileIDs.isHidden(VALUE)); //Cleanup stockpileIDs.renameTable(TABLE_1); assertTrue(stockpileIDs.isHidden(VALUE)); stockpileIDs.show(VALUE); assertFalse(stockpileIDs.isHidden(VALUE)); assertEquals(0, stockpileIDs.getHidden().size()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/LocationFlagTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.io.shared.RawConverter.LocationFlag; import net.troja.eve.esi.model.CharacterAssetsResponse; import net.troja.eve.esi.model.CharacterBlueprintsResponse; import net.troja.eve.esi.model.CorporationAssetsResponse; import net.troja.eve.esi.model.CorporationBlueprintsResponse; import org.junit.Test; public class LocationFlagTest extends TestUtil { @Test public void locationFlagTest() { RawUtil.compare(LocationFlag.values(), CharacterBlueprintsResponse.LocationFlagEnum.values(), CorporationBlueprintsResponse.LocationFlagEnum.values(), CharacterAssetsResponse.LocationFlagEnum.values(), CorporationAssetsResponse.LocationFlagEnum.values()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/RawAssetTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.raw.RawAsset; import net.troja.eve.esi.model.CharacterAssetsResponse; import net.troja.eve.esi.model.CorporationAssetsResponse; import org.junit.Test; public class RawAssetTest extends TestUtil { @Test public void rawAssetTest() { RawUtil.compare(RawAsset.class, CharacterAssetsResponse.class); RawUtil.compare(RawAsset.class, CorporationAssetsResponse.class); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/RawBlueprintTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.raw.RawBlueprint; import net.troja.eve.esi.model.CharacterBlueprintsResponse; import net.troja.eve.esi.model.CorporationBlueprintsResponse; import org.junit.Test; public class RawBlueprintTest extends TestUtil { @Test public void rawBlueprintTest() { RawUtil.compare(RawBlueprint.class, CharacterBlueprintsResponse.class); RawUtil.compare(RawBlueprint.class, CorporationBlueprintsResponse.class); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/RawCloneTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.raw.RawClone; import net.troja.eve.esi.model.JumpClone; import org.junit.Test; public class RawCloneTest extends TestUtil { @Test public void rawCloneTest() { RawUtil.compare(RawClone.class, JumpClone.class); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/RawContractItemTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.raw.RawContractItem; import net.troja.eve.esi.model.ContractItemsResponse; import net.troja.eve.esi.model.PublicContractsItemsResponse; import org.junit.Test; public class RawContractItemTest extends TestUtil { @Test public void rawContractItemTest() { RawUtil.compare(RawContractItem.class, ContractItemsResponse.class); RawUtil.compare(RawContractItem.class, PublicContractsItemsResponse.class); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/RawContractTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.raw.RawContract; import net.nikr.eve.jeveasset.data.api.raw.RawContract.ContractAvailability; import net.nikr.eve.jeveasset.data.api.raw.RawContract.ContractStatus; import net.nikr.eve.jeveasset.data.api.raw.RawContract.ContractType; import net.troja.eve.esi.model.CharacterContractsResponse; import net.troja.eve.esi.model.CorporationContractsResponse; import org.junit.Test; public class RawContractTest extends TestUtil { @Test public void rawContractTest() { RawUtil.compare(RawContract.class, CharacterContractsResponse.class); RawUtil.compare(ContractAvailability.values(), CharacterContractsResponse.AvailabilityEnum.values()); RawUtil.compare(ContractStatus.values(), CharacterContractsResponse.StatusEnum.values()); RawUtil.compare(ContractType.values(), CharacterContractsResponse.TypeEnum.values()); RawUtil.compare(RawContract.class, CorporationContractsResponse.class); RawUtil.compare(ContractAvailability.values(), CorporationContractsResponse.AvailabilityEnum.values()); RawUtil.compare(ContractStatus.values(), CorporationContractsResponse.StatusEnum.values()); RawUtil.compare(ContractType.values(), CorporationContractsResponse.TypeEnum.values()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/RawIndustryJobTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob.IndustryJobStatus; import net.troja.eve.esi.model.CharacterIndustryJobsResponse; import net.troja.eve.esi.model.CorporationIndustryJobsResponse; import org.junit.Test; public class RawIndustryJobTest extends TestUtil { @Test public void rawIndustryJobTest() { RawUtil.compare(RawIndustryJob.class, CharacterIndustryJobsResponse.class); RawUtil.compare(IndustryJobStatus.values(), CharacterIndustryJobsResponse.StatusEnum.values()); RawUtil.compare(RawIndustryJob.class, CorporationIndustryJobsResponse.class); RawUtil.compare(IndustryJobStatus.values(), CorporationIndustryJobsResponse.StatusEnum.values()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/RawJournalTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.raw.RawJournal; import net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType; import net.troja.eve.esi.model.CharacterWalletJournalResponse; import net.troja.eve.esi.model.CorporationWalletJournalResponse; import org.junit.Test; public class RawJournalTest extends TestUtil { @Test public void rawJournalTest() { RawUtil.compare(RawJournal.class, CharacterWalletJournalResponse.class); RawUtil.compare(RawJournal.class, CorporationWalletJournalResponse.class); RawUtil.compare(ContextType.values(), CharacterWalletJournalResponse.ContextIdTypeEnum.values(), CorporationWalletJournalResponse.ContextIdTypeEnum.values()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/RawLoyaltyPointsTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.raw.RawLoyaltyPoints; import net.troja.eve.esi.model.CharacterLoyaltyPointsResponse; import org.junit.Test; public class RawLoyaltyPointsTest extends TestUtil { @Test public void rawLoyaltyPointsTest() { RawUtil.compare(RawLoyaltyPoints.class, CharacterLoyaltyPointsResponse.class); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/RawMarketOrderTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.MarketOrderRange; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.MarketOrderState; import net.troja.eve.esi.model.CharacterOrdersHistoryResponse; import net.troja.eve.esi.model.CharacterOrdersResponse; import net.troja.eve.esi.model.CorporationOrdersHistoryResponse; import net.troja.eve.esi.model.CorporationOrdersResponse; import org.junit.Test; public class RawMarketOrderTest extends TestUtil { @Test public void rawMarketOrderTest() { RawUtil.compare(RawMarketOrder.class, CharacterOrdersResponse.class); RawUtil.compare(RawMarketOrder.class, CharacterOrdersHistoryResponse.class); RawUtil.compare(RawMarketOrder.class, CorporationOrdersResponse.class); RawUtil.compare(RawMarketOrder.class, CorporationOrdersHistoryResponse.class); RawUtil.compare(MarketOrderRange.values(), CharacterOrdersResponse.RangeEnum.values(), CharacterOrdersHistoryResponse.RangeEnum.values(), CorporationOrdersResponse.RangeEnum.values(), CorporationOrdersHistoryResponse.RangeEnum.values()); RawUtil.compare(MarketOrderState.values(), CharacterOrdersHistoryResponse.StateEnum.values(), CorporationOrdersHistoryResponse.StateEnum.values()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/RawNpcStandingTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.raw.RawNpcStanding; import net.troja.eve.esi.model.StandingsResponse; import org.junit.Test; public class RawNpcStandingTest extends TestUtil { @Test public void rawNpcStandingTest() { RawUtil.compare(RawNpcStanding.class, StandingsResponse.class); RawUtil.compare(RawNpcStanding.FromType.values(), StandingsResponse.FromTypeEnum.values()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/RawPublicMarketOrderTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.MarketOrderRange; import net.nikr.eve.jeveasset.data.api.raw.RawPublicMarketOrder; import net.troja.eve.esi.model.MarketRegionOrdersResponse; import net.troja.eve.esi.model.MarketStructureResponse; import org.junit.Test; public class RawPublicMarketOrderTest extends TestUtil { @Test public void rawPublicMarketOrderTest() { RawUtil.compare(RawPublicMarketOrder.class, MarketRegionOrdersResponse.class); RawUtil.compare(RawPublicMarketOrder.class, MarketStructureResponse.class); RawUtil.compare(MarketOrderRange.values(), MarketRegionOrdersResponse.RangeEnum.values(), MarketStructureResponse.RangeEnum.values()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/RawSkillTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.raw.RawSkill; import net.troja.eve.esi.model.Skill; import org.junit.Test; public class RawSkillTest extends TestUtil { @Test public void rawSkillTest() { RawUtil.compare(RawSkill.class, Skill.class); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/RawTransactionTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.raw.RawTransaction; import net.troja.eve.esi.model.CharacterWalletTransactionsResponse; import net.troja.eve.esi.model.CorporationWalletTransactionsResponse; import org.junit.Test; public class RawTransactionTest extends TestUtil { @Test public void rawTransactionTest() { RawUtil.compare(RawTransaction.class, CharacterWalletTransactionsResponse.class); RawUtil.compare(RawTransaction.class, CorporationWalletTransactionsResponse.class); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/raw/RawUtil.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.raw; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.time.OffsetDateTime; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.raw.RawAsset; import net.nikr.eve.jeveasset.data.api.raw.RawBlueprint; import net.nikr.eve.jeveasset.data.api.raw.RawClone; import net.nikr.eve.jeveasset.data.api.raw.RawContract.ContractStatus; import net.nikr.eve.jeveasset.data.api.raw.RawContractItem; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob.IndustryJobStatus; import net.nikr.eve.jeveasset.data.api.raw.RawJournal; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.MarketOrderState; import net.nikr.eve.jeveasset.data.api.raw.RawPublicMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawTransaction; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class RawUtil { public static void compare(Class raw, Class esi) { compare(getNames(raw, raw.getDeclaredFields()), getNames(raw, esi.getDeclaredFields())); compareTypes(getTypes(raw, raw.getDeclaredFields()), getTypes(raw, esi.getDeclaredFields())); } public static void compare(Enum[] raw, Enum[] esi) { compare(getNames(raw), getNames(esi)); } public static void compare(Enum[] raw, Enum[] ... esi) { compare(getNames(raw), getNames(esi)); } private static Map getTypes(Class raw, Field[] values) { Map names = new HashMap<>(); for (Field value : values) { if (Modifier.isStatic(value.getModifiers())) { //Ignore static fields continue; } Class type = value.getType(); if (ignore(value, raw)) { continue; } if (type.isEnum()) { //Ignore enums continue; } if (type.equals(Date.class)) { //Ignore date formats continue; } if (type.equals(OffsetDateTime.class)) { //Ignore date formats continue; } names.put(value.getName(), type.getName()); } return names; } private static Set getNames(Class raw, Field[] values) { Set names = new HashSet<>(); for (Field value : values) { if (Modifier.isStatic(value.getModifiers())) { //Ignore static fields continue; } if (ignore(value, raw)) { continue; } names.add(value.getName()); } return names; } private static boolean ignore(Field value, Class raw) { if (value.getName().equals("itemFlag") && (raw.equals(RawAsset.class) || raw.equals(RawBlueprint.class) || raw.equals(RawClone.class))) { return true; } if (value.getName().equals("locationFlagEnum") && (raw.equals(RawAsset.class) || raw.equals(RawBlueprint.class))) { return true; } if (value.getName().equals("locationType") && (raw.equals(RawAsset.class))) { //Not used be jEveAssets return true; } if (value.getName().equals("locationTypeEnum") && (raw.equals(RawAsset.class)) || raw.equals(RawClone.class)) { //Not used be jEveAssets return true; } if (value.getName().equals("isBlueprintCopy") && raw.equals(RawAsset.class)) { //Converted to quantity return true; } if (value.getName().equals("itemId") && raw.equals(RawContractItem.class)) { //Only in public endpoint return true; } if (value.getName().equals("runs") && raw.equals(RawContractItem.class)) { //Only in public endpoint return true; } if (value.getName().equals("materialEfficiency") && raw.equals(RawContractItem.class)) { //Only in public endpoint return true; } if (value.getName().equals("timeEfficiency") && raw.equals(RawContractItem.class)) { //Only in public endpoint return true; } if (value.getName().equals("isBlueprintCopy") && raw.equals(RawContractItem.class)) { //Only in public endpoint return true; } if (value.getName().equals("isSingleton") && raw.equals(RawContractItem.class)) { //Only in corp/char endpoints (not working, though) return true; } if (value.getName().equals("rawQuantity") && raw.equals(RawContractItem.class)) { //Only in corp/char endpoints (not working, though) return true; } if (value.getName().equals("accountKey") && (raw.equals(RawTransaction.class) || raw.equals(RawJournal.class))) { return true; } if (value.getName().equals("isPersonal") && raw.equals(RawTransaction.class)) { //Only in character endpoint return true; } if (value.getName().equals("stationId") && raw.equals(RawIndustryJob.class)) { //stationId in character endpoint / locationId in corporation endpoint return true; } if (value.getName().equals("locationId") && raw.equals(RawIndustryJob.class)) { //stationId in character endpoint / locationId in corporation endpoint return true; } if (value.getName().equals("accountId") && raw.equals(RawMarketOrder.class)) { //accountId in character endpoint / walletDivision in corporation endpoint return true; } if (value.getName().equals("walletDivision") && raw.equals(RawMarketOrder.class)) { //accountId in character endpoint / walletDivision in corporation endpoint return true; } if (value.getName().equals("issuedBy") && raw.equals(RawMarketOrder.class)) { //Only in corporation endpoint return true; } if (value.getName().equals("state") && raw.equals(RawMarketOrder.class)) { //Only in history endpoints return true; } if (value.getName().equals("stateEnum") && raw.equals(RawMarketOrder.class)) { //Only in history endpoints return true; } if (value.getName().equals("isCorp") && raw.equals(RawMarketOrder.class)) { //Only in character endpoint return true; } if (value.getName().equals("isCorporation") && raw.equals(RawMarketOrder.class)) { //Only in character endpoint return true; } if (value.getName().equals("changes") && raw.equals(RawMarketOrder.class)) { //jEveAssets value return true; } if (value.getName().equals("changed") && raw.equals(RawMarketOrder.class)) { //jEveAssets value return true; } if (value.getName().equals("updateChanged") && raw.equals(RawMarketOrder.class)) { //jEveAssets value return true; } if (value.getName().equals("systemId") && raw.equals(RawPublicMarketOrder.class)) { //Only in RawPublicMarketOrder return true; } return false; } private static Set getNames(Enum[] ... values) { Set names = new HashSet<>(); for (Enum[] value : values) { for (Enum e : value) { if (e.equals(MarketOrderState.UNKNOWN)) { //jEveAssets value continue; } if (e.equals(MarketOrderState.OPEN)) { //jEveAssets value continue; } if (e.equals(MarketOrderState.CLOSED)) { //Only in XML continue; } if (e.equals(MarketOrderState.CHARACTER_DELETED)) { //Only in XML continue; } if (e.equals(MarketOrderState.PENDING)) { //Only in XML continue; } if (e.equals(IndustryJobStatus.ARCHIVED)) { //jEveAssets value continue; } if (e.equals(ContractStatus.ARCHIVED)) { //jEveAssets value continue; } names.add(e.name()); } } return names; } private static void compare(Set raw, Set esi) { for (String name : raw) { if (!esi.contains(name)) { fail(name+ " removed from esi"); } } for (String name : esi) { if (!raw.contains(name)) { fail(name+ " missing from raw"); } } } private static void compareTypes(Map raw, Map esi) { assertEquals(esi.size(), raw.size()); for (Map.Entry entry : raw.entrySet()) { String rawType = entry.getValue(); String esiType = esi.get(entry.getKey()); if (isUnsafe32bit(entry.getKey(), rawType, esiType)) { continue; } assertEquals(rawType, esiType); } for (Map.Entry entry : esi.entrySet()) { String rawType = raw.get(entry.getKey()); String esiType = entry.getValue(); if (isUnsafe32bit(entry.getKey(), rawType, esiType)) { continue; } assertEquals(rawType, esiType); } } private static boolean isUnsafe32bit(String key, String rawType, String esiType) { if (rawType.equals("java.lang.Integer") && esiType.equals("java.lang.Long")) { System.out.println(key + " is an 'unsafe' Integer"); return true; } if (rawType.equals("java.lang.Float") && esiType.equals("java.lang.Double")) { System.out.println(key + " is an 'unsafe' Float"); return true; } return false; } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/sde/ItemTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.sde; import net.nikr.eve.jeveasset.TestUtil; import org.junit.Test; import static org.junit.Assert.*; public class ItemTest extends TestUtil { @Test public void test() { //PI boolean categoryPlanetaryIndustry = false; boolean categoryPlanetaryCommodities = false; boolean categoryPlanetaryResources = false; boolean groupCommandCenters = false; boolean groupExtractorControlUnits = false; boolean groupProcessors = false; boolean groupSpaceports = false; boolean groupStorageFacilities = false; //Containers boolean groupAuditLogSecureContainer = false; boolean groupFreightContainer = false; boolean groupCargoContainer = false; boolean groupSecureCargoContainer = false; //Blueprint boolean categoryBlueprint = false; long blueprint = 0; long reaction = 0; long total = 0; //Ship boolean categoryShip = false; //Asteroid boolean categoryAsteroid = false; //Module boolean categoryModule = false; //Structure boolean categoryStructure = false; //Material boolean categoryMaterial = false; //Deployable boolean categoryDeployable = false; //Commodity boolean categoryCommodity = false; //Biomass boolean groupBiomass = false; //Station Services boolean groupStationServices = false; //Compressed Gas boolean groupCompressedGas = false; //Harvestable Cloud boolean groupHarvestableCloud = false; for (Item item : StaticData.get().getItems().values()) { //PI if (item.getCategory().equals(Item.CATEGORY_PLANETARY_INDUSTRY)) { categoryPlanetaryIndustry = true; } if (item.getCategory().equals(Item.CATEGORY_PLANETARY_COMMODITIES)) { categoryPlanetaryCommodities = true; } if (item.getCategory().equals(Item.CATEGORY_PLANETARY_RESOURCES)) { categoryPlanetaryResources = true; } if (item.getGroup().equals(Item.GROUP_COMMAND_CENTERS)) { groupCommandCenters = true; } if (item.getGroup().equals(Item.GROUP_EXTRACTOR_CONTROL_UNITS)) { groupExtractorControlUnits = true; } if (item.getGroup().equals(Item.GROUP_PROCESSORS)) { groupProcessors = true; } if (item.getGroup().equals(Item.GROUP_SPACEPORTS)) { groupSpaceports = true; } if (item.getGroup().equals(Item.GROUP_STORAGE_FACILITIES)) { groupStorageFacilities = true; } //Containers if (item.getGroup().equals(Item.GROUP_AUDIT_LOG_SECURE_CONTAINER)) { groupAuditLogSecureContainer = true; } if (item.getGroup().equals(Item.GROUP_FREIGHT_CONTAINER)) { groupFreightContainer = true; } if (item.getGroup().equals(Item.GROUP_CARGO_CONTAINER)) { groupCargoContainer = true; } if (item.getGroup().equals(Item.GROUP_SECURE_CARGO_CONTAINER)) { groupSecureCargoContainer = true; } //Blueprint if (item.getCategory().equals(Item.CATEGORY_BLUEPRINT)) { categoryBlueprint = true; total++; if (item.isBlueprint()) { blueprint++; } if (item.isFormula()) { reaction++; } if (!item.isFormula() && !item.isBlueprint()) { System.out.println(item.getTypeName() + " :: " + item.getGroup()); } } //Ship if (item.isShip()) { //CATEGORY_SHIP categoryShip = true; } //Asteroid if (item.isOre()) { //CATEGORY_ASTEROID categoryAsteroid = true; } //Module if (item.getCategory().equals(Item.CATEGORY_MODULE)) { categoryModule = true; } //Structure if (item.getCategory().equals(Item.CATEGORY_STRUCTURE)) { categoryStructure = true; } //Material if (item.getCategory().equals(Item.CATEGORY_MATERIAL)) { categoryMaterial = true; } //Deployable if (item.getCategory().equals(Item.CATEGORY_DEPLOYABLE)) { categoryDeployable = true; } //Commodity if (item.getCategory().equals(Item.CATEGORY_COMMODITY)) { categoryCommodity = true; } //Biomass if (item.getGroup().equals(Item.GROUP_BIOMASS)) { groupBiomass = true; } //Station Services if (item.getGroup().equals(Item.GROUP_STATION_SERVICES)) { groupStationServices = true; } //Compressed Gas if (item.getGroup().equals(Item.GROUP_COMPRESSED_GAS)) { groupCompressedGas = true; } //Harvestable Cloud if (item.getGroup().equals(Item.GROUP_HARVESTABLE_CLOUD)) { groupHarvestableCloud = true; } } assertEquals(total, blueprint + reaction); //PI assertTrue("no category: Planetary Industry", categoryPlanetaryIndustry); assertTrue("no category: Planetary Commodities", categoryPlanetaryCommodities); assertTrue("no category: Planetary Resources", categoryPlanetaryResources); assertTrue("no group: Command Centers", groupCommandCenters); assertTrue("no group: Extractor Control Units", groupExtractorControlUnits); assertTrue("no group: Processors", groupProcessors); assertTrue("no group: Spaceports", groupSpaceports); assertTrue("no group: Storage Facilities", groupStorageFacilities); //Containers assertTrue("no group: Audit Log Secure Container", groupAuditLogSecureContainer); assertTrue("no group: Freight Container", groupFreightContainer); assertTrue("no group: Cargo Container", groupCargoContainer); assertTrue("no group: Secure Cargo Container", groupSecureCargoContainer); //Blueprint assertTrue("no category: Ship", categoryBlueprint); //Ship assertTrue("no category: Ship", categoryShip); //Asteroid assertTrue("no category: Asteroid", categoryAsteroid); //Module assertTrue("no category: Module", categoryModule); //Structure assertTrue("no category: Structure", categoryStructure); //Material assertTrue("no category: Material", categoryMaterial); //Deployable assertTrue("no category: Deployable", categoryDeployable); //categoryCommodity assertTrue("no category: Commodity", categoryCommodity); //Biomass assertTrue("no group: Biomass", groupBiomass); //Station Services assertTrue("no group: Station Services", groupStationServices); //Gas //Compressed Gas assertTrue("no group: Compressed Gas", groupCompressedGas); //Harvestable Cloud assertTrue("no group: Harvestable Cloud", groupHarvestableCloud); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/sde/StaticDataTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.sde; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import javax.swing.SwingWorker; import net.nikr.eve.jeveasset.TestUtil; import org.junit.Test; public class StaticDataTest extends TestUtil { private static final int RUNS = 1000; @Test public void testLocationsThreadSafty() throws InterruptedException, ExecutionException { StaticData.load(); List> threads = new ArrayList<>(); for (int i = 0; i < RUNS; i++) { threads.add(new ReadThread()); threads.add(new WriteThread()); } for (SwingWorker thread : threads) { thread.execute(); } for (SwingWorker thread : threads) { thread.get(); } } private static class ReadThread extends SwingWorker { @Override protected Void doInBackground() throws Exception { for (MyLocation location : StaticData.get().getLocations()) { StaticData.get().getLocation(location.getLocationID()); } return null; } } private static class WriteThread extends SwingWorker { @Override protected Void doInBackground() throws Exception { for (MyLocation location : StaticData.get().getLocations()) { StaticData.get().removeLocation(location.getLocationID()); StaticData.get().addLocation(location); } return null; } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/settings/ColorThemeTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.settings.ColorTheme.ColorThemeTypes; import org.junit.Test; import static org.junit.Assert.*; public class ColorThemeTest extends TestUtil { @Test public void testDefaultTheme() { test(ColorThemeTypes.DEFAULT.getInstance()); } @Test public void testStrongTheme() { test(ColorThemeTypes.STRONG.getInstance()); } @Test public void testColorblindTheme() { test(ColorThemeTypes.COLORBLIND.getInstance()); } @Test public void testDARKTheme() { test(ColorThemeTypes.DARK.getInstance()); } private void test(ColorTheme colorTheme) { assertTrue(colorTheme.isValid()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/settings/MarketPriceDataTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.Date; import net.nikr.eve.jeveasset.TestUtil; import static org.junit.Assert.*; import org.junit.Test; public class MarketPriceDataTest extends TestUtil { @Test public void testUpdate() { //Set MarketPriceData data = new MarketPriceData(); data.update(75, 1, new Date(1)); data.update(25, 1, new Date(2)); data.update(50, 1, new Date(3)); assertEquals(50, data.getAverage(), 0); assertEquals(75, data.getMaximum(), 0); assertEquals(25, data.getMinimum(), 0); assertEquals(50, data.getLatest(), 0); //Empty data = new MarketPriceData(); assertEquals(0, data.getAverage(), 0); assertEquals(0, data.getMaximum(), 0); assertEquals(0, data.getMinimum(), 0); assertEquals(0, data.getLatest(), 0); //Set data = new MarketPriceData(); data.update(10, 300 , new Date(1)); data.update(20, 100, new Date(2)); assertEquals(12.5, data.getAverage(), 0); assertEquals(20, data.getMaximum(), 0); assertEquals(10, data.getMinimum(), 0); assertEquals(20, data.getLatest(), 0); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/settings/ModuleTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.sde.ItemFlag; import java.util.ArrayList; import java.util.List; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.gui.tabs.loadout.Loadout.FlagType; import org.junit.*; import static org.junit.Assert.assertTrue; public class ModuleTest extends TestUtil { /** * Test of FlagType enum, of class Module. */ @Test public void testFlags() { List flags = new ArrayList(StaticData.get().getItemFlags().values()); for (FlagType type : FlagType.values()) { if (type == FlagType.TOTAL_VALUE) { continue; } if (type == FlagType.OTHER) { continue; } boolean found = false; for (ItemFlag flag : flags) { if (flag.getFlagName().contains(type.getFlag())) { found = true; break; } } assertTrue(type.name() + " flag value (" + type.getFlag() + ") is no longer valid", found); } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/settings/ReprocessSettingsTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import net.nikr.eve.jeveasset.data.sde.ReprocessedMaterial; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.TestUtil; import static org.junit.Assert.assertEquals; import org.junit.Test; public class ReprocessSettingsTest extends TestUtil { @Test public void testSomeMethod() { ReprocessSettings reprocessSettings; //Level 4 Material Skill At 50% Facilities reprocessSettings = new ReprocessSettings(50, 5, 5, 4, 0); assertEquals(68.31, reprocessSettings.getPercent(true), 0); //Level 4 Material Skill 52% Reprocessing Array reprocessSettings = new ReprocessSettings(52, 5, 5, 4, 0); assertEquals(71.0424, reprocessSettings.getPercent(true), 0); //Max Skill At 50% Facilities reprocessSettings = new ReprocessSettings(50, 5, 5, 5, 0); assertEquals(69.575, reprocessSettings.getPercent(true), 0); //Max Skill At 52% Reprocessing Array reprocessSettings = new ReprocessSettings(52, 5, 5, 5, 0); assertEquals(72.358, reprocessSettings.getPercent(true), 0); //Min Reproceesing reprocessSettings = new ReprocessSettings(100, 5, 5, 5, 0); assertEquals(50, reprocessSettings.getPercent(false), 0); //Max Reproceesing reprocessSettings = new ReprocessSettings(0, 0, 0, 0, 5); assertEquals(55, reprocessSettings.getPercent(false), 0.0001); //Level 4 Material Skill At 50% Facilities reprocessSettings = new ReprocessSettings(50, 0, 0, 0, 0); Item item = StaticData.get().getItems().get(238); for (ReprocessedMaterial reprocessedMaterial : item.getReprocessedMaterial()) { if (reprocessedMaterial.getTypeID() == 34) { //Tritanium assertEquals(889, reprocessSettings.getLeft(reprocessedMaterial.getQuantity(), false)); } if (reprocessedMaterial.getTypeID() == 35) { //Pyerite assertEquals(63, reprocessSettings.getLeft(reprocessedMaterial.getQuantity(), false)); } if (reprocessedMaterial.getTypeID() == 36) { //Mexallon assertEquals(44, reprocessSettings.getLeft(reprocessedMaterial.getQuantity(), false)); } if (reprocessedMaterial.getTypeID() == 37) { //Isogen assertEquals(14, reprocessSettings.getLeft(reprocessedMaterial.getQuantity(), false)); } } for (ReprocessedMaterial reprocessedMaterial : item.getReprocessedMaterial()) { if (reprocessedMaterial.getTypeID() == 34) { //Tritanium assertEquals(177800, reprocessSettings.getLeft(reprocessedMaterial.getQuantity() * 200, false)); } if (reprocessedMaterial.getTypeID() == 35) { //Pyerite assertEquals(12700, reprocessSettings.getLeft(reprocessedMaterial.getQuantity() * 200, false)); } if (reprocessedMaterial.getTypeID() == 36) { //Mexallon assertEquals(8900, reprocessSettings.getLeft(reprocessedMaterial.getQuantity() * 200, false)); } if (reprocessedMaterial.getTypeID() == 37) { //Isogen assertEquals(2900, reprocessSettings.getLeft(reprocessedMaterial.getQuantity() * 200, false)); } } } @Test public void test() { ReprocessSettings reprocessSettings; reprocessSettings = new ReprocessSettings(50, 3, 5, 5, 5); assertEquals(reprocessSettings.getReprocessingLevel(), 3); assertEquals(reprocessSettings.getReprocessingEfficiencyLevel(), 0); assertEquals(reprocessSettings.getOreProcessingLevel(), 0); assertEquals(reprocessSettings.getScrapmetalProcessingLevel(), 5); reprocessSettings = new ReprocessSettings(50, 4, 3, 5, 5); assertEquals(reprocessSettings.getReprocessingLevel(), 4); assertEquals(reprocessSettings.getReprocessingEfficiencyLevel(), 3); assertEquals(reprocessSettings.getOreProcessingLevel(), 0); assertEquals(reprocessSettings.getScrapmetalProcessingLevel(), 5); reprocessSettings = new ReprocessSettings(50, 4, 4, 4, 5); assertEquals(reprocessSettings.getReprocessingLevel(), 4); assertEquals(reprocessSettings.getReprocessingEfficiencyLevel(), 4); assertEquals(reprocessSettings.getOreProcessingLevel(), 4); assertEquals(reprocessSettings.getScrapmetalProcessingLevel(), 5); reprocessSettings = new ReprocessSettings(50, 5, 5, 5, 5); assertEquals(reprocessSettings.getReprocessingLevel(), 5); assertEquals(reprocessSettings.getReprocessingEfficiencyLevel(), 5); assertEquals(reprocessSettings.getOreProcessingLevel(), 5); assertEquals(reprocessSettings.getScrapmetalProcessingLevel(), 5); reprocessSettings = new ReprocessSettings(50, 6, 6, 6, 6); assertEquals(reprocessSettings.getReprocessingLevel(), 5); assertEquals(reprocessSettings.getReprocessingEfficiencyLevel(), 5); assertEquals(reprocessSettings.getOreProcessingLevel(), 5); assertEquals(reprocessSettings.getScrapmetalProcessingLevel(), 5); reprocessSettings = new ReprocessSettings(50, 0, 0, 0, 0); assertEquals(reprocessSettings.getReprocessingLevel(), 0); assertEquals(reprocessSettings.getReprocessingEfficiencyLevel(), 0); assertEquals(reprocessSettings.getOreProcessingLevel(), 0); assertEquals(reprocessSettings.getScrapmetalProcessingLevel(), 0); reprocessSettings = new ReprocessSettings(50, -1, -1, -1, -1); assertEquals(reprocessSettings.getReprocessingLevel(), 0); assertEquals(reprocessSettings.getReprocessingEfficiencyLevel(), 0); assertEquals(reprocessSettings.getOreProcessingLevel(), 0); assertEquals(reprocessSettings.getScrapmetalProcessingLevel(), 0); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/settings/SettingsTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.settings.Settings.SettingFlag; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import org.junit.Test; public class SettingsTest extends TestUtil { @Test public void testFlags() { Settings settings = new Settings(); for (SettingFlag flag : SettingFlag.values()) { assertThat(flag.name() + " have no default value", settings.getFlags().get(flag), notNullValue()); } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/data/settings/TrackerDataTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.data.settings; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.gui.tabs.values.Value; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import org.junit.Test; public class TrackerDataTest extends TestUtil { @Test public void addAll() { Map> values; List list; String owner = "owner"; Date date = new Date(); Value oldValue = new Value("Old", date); Value newValue = new Value("New", date); TrackerData.set(Collections.singletonMap(owner, new ArrayList<>(Collections.singletonList(oldValue)))); TrackerData.addAll(Collections.singletonMap(owner, new ArrayList<>(Collections.singletonList(newValue))), true); values = TrackerData.get(); list = values.get(owner); assertNotNull(list); assertEquals(1, list.size()); assertEquals(newValue.getName(), list.get(0).getName()); TrackerData.set(Collections.emptyMap()); TrackerData.set(Collections.singletonMap(owner, new ArrayList<>(Collections.singletonList(oldValue)))); TrackerData.addAll(Collections.singletonMap(owner, new ArrayList<>(Collections.singletonList(newValue))), false); values = TrackerData.get(); list = values.get(owner); assertNotNull(list); assertEquals(1, list.size()); assertEquals(oldValue.getName(), list.get(0).getName()); TrackerData.set(Collections.emptyMap()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/images/ImagesTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.images; import java.awt.image.BufferedImage; import java.io.File; import java.net.URISyntaxException; import net.nikr.eve.jeveasset.TestUtil; import static org.junit.Assert.*; import org.junit.Test; public class ImagesTest extends TestUtil { @Test public void testExists() { for (Images i : Images.values()) { BufferedImage image = Images.getBufferedImage(i.getFilename()); assertNotNull(i.getFilename() + " not found", image); } } @Test public void testPreload() { boolean ok = Images.preload(); assertTrue("Preload failed", ok); } @Test public void testUnused() { try { File dir = new File(Images.class.getResource("Images.class").toURI()).getParentFile(); String[] children = dir.list(); if (children != null) { for (String filename : children) { if (filename.equals("Images.class")) { continue; } boolean ok = false; //Images Class for (Images i : Images.values()) { if (filename.equals(i.getFilename())) { ok = true; break; } } //loading 01-08 for (int a = 0; a < 8; a++) { if (filename.equals("loading0" + (a + 1) + ".png")) { ok = true; break; } } //working 01-24 for (int a = 0; a < 24; a++) { String number; if ((a + 1) < 10) { number = "0" + (a + 1); } else { number = "" + (a + 1); } if (filename.equals("working" + number + ".png")) { ok = true; break; } } assertTrue(filename + " is not used anywhere", ok); } } } catch (URISyntaxException ex) { fail("Directory not found"); } } @Test public void testFilenames() { String[] extensions = {".png", ".gif"}; for (Images i : Images.values()) { String extension = extensions[0]; for (String s : extensions) { if (i.getFilename().endsWith(s)) { extension = s; } } String properFilename = i.toString().toLowerCase() + extension; if (!properFilename.equals(i.getFilename())) { fail(i.toString() + " filename should be " + properFilename + " but is " + i.getFilename()); } } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/shared/FormatterTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.junit.Test; public class FormatterTest { private final Date DATE = Formatter.columnStringToDate("2000-01-01 12:00"); private final int THREADS = 100; @Test public void testThreadSafe() throws InterruptedException, ExecutionException { List> threads = new ArrayList<>(); for (int i = 0; i < THREADS; i++) { threads.add(new ParseDate()); threads.add(new FormatDate()); threads.add(new FormatNumber()); } ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(THREADS * 2); List> futures = newFixedThreadPool.invokeAll(threads); for (Future future : futures) { future.get(); } } @Test public void testAutoFormat() throws InterruptedException, ExecutionException { Formatter.AUTO_FORMAT.format(Long.MAX_VALUE); Formatter.AUTO_FORMAT.format(Long.MIN_VALUE); Formatter.AUTO_FORMAT.format(Double.MIN_VALUE); Formatter.AUTO_FORMAT.format(Double.MAX_VALUE); } private class ParseDate implements Callable { @Override public Void call() throws Exception { Formatter.columnStringToDate("2000-01-01 12:00"); return null; } } private class FormatDate implements Callable { @Override public Void call() throws Exception { Formatter.columnDate(DATE); return null; } } private class FormatNumber implements Callable { @Override public Void call() throws Exception { Formatter.iskFormat(123456789.1234); return null; } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/shared/components/CheckBoxNodeTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.components; import java.util.ArrayList; import java.util.List; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import org.junit.Test; public class CheckBoxNodeTest { private CheckBoxNode root; private CheckBoxNode a; private CheckBoxNode a1; private CheckBoxNode a2; private CheckBoxNode a3; private CheckBoxNode b; private CheckBoxNode b1; private CheckBoxNode b2; private CheckBoxNode b3; private CheckBoxNode c; private CheckBoxNode c1; private CheckBoxNode c2; private CheckBoxNode c3; private final List all = new ArrayList<>(); @Test public void testSetSelected() { makeNodes(true); c3.setSelected(false); assertThat(root.isSelected(), equalTo(false)); assertThat(a.isSelected(), equalTo(true)); assertThat(a1.isSelected(), equalTo(true)); assertThat(a2.isSelected(), equalTo(true)); assertThat(a3.isSelected(), equalTo(true)); assertThat(b.isSelected(), equalTo(true)); assertThat(b1.isSelected(), equalTo(true)); assertThat(b2.isSelected(), equalTo(true)); assertThat(b3.isSelected(), equalTo(true)); assertThat(c.isSelected(), equalTo(false)); assertThat(c1.isSelected(), equalTo(true)); assertThat(c2.isSelected(), equalTo(true)); assertThat(c3.isSelected(), equalTo(false)); c3.setSelected(true); assertThat(root.isSelected(), equalTo(true)); assertThat(a.isSelected(), equalTo(true)); assertThat(a1.isSelected(), equalTo(true)); assertThat(a2.isSelected(), equalTo(true)); assertThat(a3.isSelected(), equalTo(true)); assertThat(b.isSelected(), equalTo(true)); assertThat(b1.isSelected(), equalTo(true)); assertThat(b2.isSelected(), equalTo(true)); assertThat(b3.isSelected(), equalTo(true)); assertThat(c.isSelected(), equalTo(true)); assertThat(c1.isSelected(), equalTo(true)); assertThat(c2.isSelected(), equalTo(true)); assertThat(c3.isSelected(), equalTo(true)); c.setSelected(false); assertThat(root.isSelected(), equalTo(false)); assertThat(a.isSelected(), equalTo(true)); assertThat(a1.isSelected(), equalTo(true)); assertThat(a2.isSelected(), equalTo(true)); assertThat(a3.isSelected(), equalTo(true)); assertThat(b.isSelected(), equalTo(true)); assertThat(b1.isSelected(), equalTo(true)); assertThat(b2.isSelected(), equalTo(true)); assertThat(b3.isSelected(), equalTo(true)); assertThat(c.isSelected(), equalTo(false)); assertThat(c1.isSelected(), equalTo(false)); assertThat(c2.isSelected(), equalTo(false)); assertThat(c3.isSelected(), equalTo(false)); c.setSelected(true); assertThat(root.isSelected(), equalTo(true)); assertThat(a.isSelected(), equalTo(true)); assertThat(a1.isSelected(), equalTo(true)); assertThat(a2.isSelected(), equalTo(true)); assertThat(a3.isSelected(), equalTo(true)); assertThat(b.isSelected(), equalTo(true)); assertThat(b1.isSelected(), equalTo(true)); assertThat(b2.isSelected(), equalTo(true)); assertThat(b3.isSelected(), equalTo(true)); assertThat(c.isSelected(), equalTo(true)); assertThat(c1.isSelected(), equalTo(true)); assertThat(c2.isSelected(), equalTo(true)); assertThat(c3.isSelected(), equalTo(true)); root.setSelected(false); assertThat(root.isSelected(), equalTo(false)); assertThat(a.isSelected(), equalTo(false)); assertThat(a1.isSelected(), equalTo(false)); assertThat(a2.isSelected(), equalTo(false)); assertThat(a3.isSelected(), equalTo(false)); assertThat(b.isSelected(), equalTo(false)); assertThat(b1.isSelected(), equalTo(false)); assertThat(b2.isSelected(), equalTo(false)); assertThat(b3.isSelected(), equalTo(false)); assertThat(c.isSelected(), equalTo(false)); assertThat(c1.isSelected(), equalTo(false)); assertThat(c2.isSelected(), equalTo(false)); assertThat(c3.isSelected(), equalTo(false)); root.setSelected(true); assertThat(root.isSelected(), equalTo(true)); assertThat(a.isSelected(), equalTo(true)); assertThat(a1.isSelected(), equalTo(true)); assertThat(a2.isSelected(), equalTo(true)); assertThat(a3.isSelected(), equalTo(true)); assertThat(b.isSelected(), equalTo(true)); assertThat(b1.isSelected(), equalTo(true)); assertThat(b2.isSelected(), equalTo(true)); assertThat(b3.isSelected(), equalTo(true)); assertThat(c.isSelected(), equalTo(true)); assertThat(c1.isSelected(), equalTo(true)); assertThat(c2.isSelected(), equalTo(true)); assertThat(c3.isSelected(), equalTo(true)); root.setSelected(false); assertThat(root.isSelected(), equalTo(false)); assertThat(a.isSelected(), equalTo(false)); assertThat(a1.isSelected(), equalTo(false)); assertThat(a2.isSelected(), equalTo(false)); assertThat(a3.isSelected(), equalTo(false)); assertThat(b.isSelected(), equalTo(false)); assertThat(b1.isSelected(), equalTo(false)); assertThat(b2.isSelected(), equalTo(false)); assertThat(b3.isSelected(), equalTo(false)); assertThat(c.isSelected(), equalTo(false)); assertThat(c1.isSelected(), equalTo(false)); assertThat(c2.isSelected(), equalTo(false)); assertThat(c3.isSelected(), equalTo(false)); c1.setSelected(true); c2.setSelected(true); c3.setSelected(true); assertThat(root.isSelected(), equalTo(false)); assertThat(a.isSelected(), equalTo(false)); assertThat(a1.isSelected(), equalTo(false)); assertThat(a2.isSelected(), equalTo(false)); assertThat(a3.isSelected(), equalTo(false)); assertThat(b.isSelected(), equalTo(false)); assertThat(b1.isSelected(), equalTo(false)); assertThat(b2.isSelected(), equalTo(false)); assertThat(b3.isSelected(), equalTo(false)); assertThat(c.isSelected(), equalTo(true)); assertThat(c1.isSelected(), equalTo(true)); assertThat(c2.isSelected(), equalTo(true)); assertThat(c3.isSelected(), equalTo(true)); a.setSelected(true); b.setSelected(true); assertThat(root.isSelected(), equalTo(true)); assertThat(a.isSelected(), equalTo(true)); assertThat(a1.isSelected(), equalTo(true)); assertThat(a2.isSelected(), equalTo(true)); assertThat(a3.isSelected(), equalTo(true)); assertThat(b.isSelected(), equalTo(true)); assertThat(b1.isSelected(), equalTo(true)); assertThat(b2.isSelected(), equalTo(true)); assertThat(b3.isSelected(), equalTo(true)); assertThat(c.isSelected(), equalTo(true)); assertThat(c1.isSelected(), equalTo(true)); assertThat(c2.isSelected(), equalTo(true)); assertThat(c3.isSelected(), equalTo(true)); } @Test public void testSetShown() { makeNodes(false); //Step 1: Select All root.setSelected(true); assertThat(root.isSelected(), equalTo(true)); assertThat(a.isSelected(), equalTo(true)); assertThat(a1.isSelected(), equalTo(true)); assertThat(a2.isSelected(), equalTo(true)); assertThat(a3.isSelected(), equalTo(true)); assertThat(b.isSelected(), equalTo(true)); assertThat(b1.isSelected(), equalTo(true)); assertThat(b2.isSelected(), equalTo(true)); assertThat(b3.isSelected(), equalTo(true)); assertThat(c.isSelected(), equalTo(true)); assertThat(c1.isSelected(), equalTo(true)); assertThat(c2.isSelected(), equalTo(true)); assertThat(c3.isSelected(), equalTo(true)); //Step 2 Deselect B b.setSelected(false); assertThat(root.isSelected(), equalTo(false)); assertThat(a.isSelected(), equalTo(true)); assertThat(a1.isSelected(), equalTo(true)); assertThat(a2.isSelected(), equalTo(true)); assertThat(a3.isSelected(), equalTo(true)); assertThat(b.isSelected(), equalTo(false)); assertThat(b1.isSelected(), equalTo(false)); assertThat(b2.isSelected(), equalTo(false)); assertThat(b3.isSelected(), equalTo(false)); assertThat(c.isSelected(), equalTo(true)); assertThat(c1.isSelected(), equalTo(true)); assertThat(c2.isSelected(), equalTo(true)); assertThat(c3.isSelected(), equalTo(true)); //Step 3 Hide all hideAll(); assertThat(root.isSelected(), equalTo(false)); assertThat(a.isSelected(), equalTo(true)); assertThat(a1.isSelected(), equalTo(true)); assertThat(a2.isSelected(), equalTo(true)); assertThat(a3.isSelected(), equalTo(true)); assertThat(b.isSelected(), equalTo(false)); assertThat(b1.isSelected(), equalTo(false)); assertThat(b2.isSelected(), equalTo(false)); assertThat(b3.isSelected(), equalTo(false)); assertThat(c.isSelected(), equalTo(true)); assertThat(c1.isSelected(), equalTo(true)); assertThat(c2.isSelected(), equalTo(true)); assertThat(c3.isSelected(), equalTo(true)); //Step 4 Show A and C matchTrue(a); matchTrue(c); assertThat(root.isSelected(), equalTo(true)); assertThat(a.isSelected(), equalTo(true)); assertThat(a1.isSelected(), equalTo(true)); assertThat(a2.isSelected(), equalTo(true)); assertThat(a3.isSelected(), equalTo(true)); assertThat(b.isSelected(), equalTo(false)); assertThat(b1.isSelected(), equalTo(false)); assertThat(b2.isSelected(), equalTo(false)); assertThat(b3.isSelected(), equalTo(false)); assertThat(c.isSelected(), equalTo(true)); assertThat(c1.isSelected(), equalTo(true)); assertThat(c2.isSelected(), equalTo(true)); assertThat(c3.isSelected(), equalTo(true)); } private void hideAll() { for (CheckBoxNode node : all) { node.hide(); } } private void matchTrue(CheckBoxNode node) { node.matches(node.getNodeName()); } private void makeNodes(boolean selected) { root = new CheckBoxNode(null, "root", "root", selected); a = new CheckBoxNode(root, "aa", "aa", selected); a1 = new CheckBoxNode(a, "a1", "a1", selected); a2 = new CheckBoxNode(a, "a2", "a2", selected); a3 = new CheckBoxNode(a, "a3", "a3", selected); b = new CheckBoxNode(root, "bb", "bb", selected); b1 = new CheckBoxNode(b, "b1", "b1", selected); b2 = new CheckBoxNode(b, "b2", "b2", selected); b3 = new CheckBoxNode(b, "b3", "b3", selected); c = new CheckBoxNode(root, "cc", "cc", selected); c1 = new CheckBoxNode(c, "c1", "c1", selected); c2 = new CheckBoxNode(c, "c2", "c2", selected); c3 = new CheckBoxNode(c, "c3", "c3", selected); all.clear(); all.add(root); all.add(a); all.add(a1); all.add(a2); all.add(a3); all.add(b); all.add(b1); all.add(b2); all.add(b3); all.add(c); all.add(c1); all.add(c2); all.add(c3); assertThat(root.isSelected(), equalTo(selected)); assertThat(root.isShown(), equalTo(true)); assertThat(a.isSelected(), equalTo(selected)); assertThat(a.isShown(), equalTo(true)); assertThat(a1.isSelected(), equalTo(selected)); assertThat(a1.isShown(), equalTo(true)); assertThat(a2.isSelected(), equalTo(selected)); assertThat(a2.isShown(), equalTo(true)); assertThat(a3.isSelected(), equalTo(selected)); assertThat(a3.isShown(), equalTo(true)); assertThat(b.isSelected(), equalTo(selected)); assertThat(b.isShown(), equalTo(true)); assertThat(b1.isSelected(), equalTo(selected)); assertThat(b1.isShown(), equalTo(true)); assertThat(b2.isSelected(), equalTo(selected)); assertThat(b2.isShown(), equalTo(true)); assertThat(b3.isSelected(), equalTo(selected)); assertThat(b3.isShown(), equalTo(true)); assertThat(c.isSelected(), equalTo(selected)); assertThat(c.isShown(), equalTo(true)); assertThat(c1.isSelected(), equalTo(selected)); assertThat(c1.isShown(), equalTo(true)); assertThat(c2.isSelected(), equalTo(selected)); assertThat(c2.isShown(), equalTo(true)); assertThat(c3.isSelected(), equalTo(selected)); assertThat(c3.isShown(), equalTo(true)); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/shared/filter/FilterExportTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import java.util.ArrayList; import java.util.List; import java.util.Map; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog.Formula; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuJumps.Jump; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager.FormulaColumn; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager.JumpColumn; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.SimpleColumnManager; import net.nikr.eve.jeveasset.gui.shared.table.containers.NumberValue; import net.nikr.eve.jeveasset.gui.tabs.agents.AgentsTab; import net.nikr.eve.jeveasset.gui.tabs.agents.AgentsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetTableFormat; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetsTab; import net.nikr.eve.jeveasset.gui.tabs.contracts.ContractsTab; import net.nikr.eve.jeveasset.gui.tabs.contracts.ContractsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.items.ItemTableFormat; import net.nikr.eve.jeveasset.gui.tabs.items.ItemsTab; import net.nikr.eve.jeveasset.gui.tabs.jobs.IndustryJobTableFormat; import net.nikr.eve.jeveasset.gui.tabs.jobs.IndustryJobsTab; import net.nikr.eve.jeveasset.gui.tabs.journal.JournalTab; import net.nikr.eve.jeveasset.gui.tabs.journal.JournalTableFormat; import net.nikr.eve.jeveasset.gui.tabs.loyalty.LoyaltyPointsTab; import net.nikr.eve.jeveasset.gui.tabs.loyalty.LoyaltyPointsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.mining.ExtractionsTab; import net.nikr.eve.jeveasset.gui.tabs.mining.ExtractionsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.mining.MiningTab; import net.nikr.eve.jeveasset.gui.tabs.mining.MiningTableFormat; import net.nikr.eve.jeveasset.gui.tabs.orders.MarketOrdersTab; import net.nikr.eve.jeveasset.gui.tabs.orders.MarketTableFormat; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTableFormat; import net.nikr.eve.jeveasset.gui.tabs.skills.SkillsTab; import net.nikr.eve.jeveasset.gui.tabs.skills.SkillsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.slots.SlotsTab; import net.nikr.eve.jeveasset.gui.tabs.slots.SlotsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.standing.NpcStandingTab; import net.nikr.eve.jeveasset.gui.tabs.standing.NpcStandingTableFormat; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileExtendedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileTab; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileTableFormat; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTab; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTableFormat; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTab; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTableFormat; import net.nikr.eve.jeveasset.gui.tabs.values.ValueTableFormat; import net.nikr.eve.jeveasset.gui.tabs.values.ValueTableTab; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import org.junit.Test; public class FilterExportTest extends TestUtil { private final String filterName = "Filter Name"; @Test public void testNull() { FilterExport filterExport = new FilterExport("Toolname", new TestColumnManager<>()); Map> importFilter = filterExport.importFilter(null); assertNotNull(importFilter); } @Test public void test() { //Primary Tools //Asset test(AssetsTab.NAME, AssetTableFormat.values()); //Contract test(ContractsTab.NAME, ContractsTableFormat.values()); //Journal test(JournalTab.NAME, JournalTableFormat.values()); //MarketOrder test(MarketOrdersTab.NAME, MarketTableFormat.values()); //Transaction test(TransactionTab.NAME, TransactionTableFormat.values()); //IndustryJob test(IndustryJobsTab.NAME, IndustryJobTableFormat.values()); //Skills test(SkillsTab.NAME, SkillsTableFormat.values()); //Mining test(MiningTab.NAME, MiningTableFormat.values()); //Loyalty Points test(LoyaltyPointsTab.NAME, LoyaltyPointsTableFormat.values()); //Agents test(AgentsTab.NAME, AgentsTableFormat.values()); //NPC Standing test(NpcStandingTab.NAME, NpcStandingTableFormat.values()); //Extractions test(ExtractionsTab.NAME, ExtractionsTableFormat.values()); //Secondary Tools //Slots test(SlotsTab.NAME, SlotsTableFormat.values()); //Tree test(TreeTab.NAME, TreeTableFormat.values()); //Item test(ItemsTab.NAME, ItemTableFormat.values()); //Loadout - No filters //test(LoadoutsTab.NAME, LoadoutTableFormat.values()); //test(LoadoutsTab.NAME, LoadoutExtendedTableFormat.values()); //Overview test(OverviewTab.NAME, OverviewTableFormat.values()); //Reprocessed - No filters //test(ReprocessedTab.NAME, ReprocessedTableFormat.values()); //test(ReprocessedTab.NAME, ReprocessedExtendedTableFormat.values()); //Stockpile test(StockpileTab.NAME, StockpileTableFormat.values()); test(StockpileTab.NAME, StockpileExtendedTableFormat.values()); //Material - No filters //test(MaterialsTab.NAME, MaterialTableFormat.values()); //test(MaterialsTab.NAME, MaterialExtendedTableFormat.values()); //ISK test(ValueTableTab.NAME, ValueTableFormat.values()); //Dialogs //AccountTableFormat - No filters } public void test(String toolName, EnumTableColumn[] columns) { System.out.println("Testing: " + toolName); FilterExport filterExport = new FilterExport(toolName, new TestColumnManager()); //Plain List plainFilters = createFilters(columns); testFilters(filterExport, plainFilters); //Formula Filter formulaFilter = createFormulaFilter(columns); if (formulaFilter != null) { List formulaFilters = new ArrayList<>(plainFilters); formulaFilters.add(formulaFilter); testFilters(filterExport, formulaFilters); } //Jump List jumpFilters = new ArrayList<>(plainFilters); jumpFilters.add(createJumpFilter()); testFilters(filterExport, jumpFilters); } public void testFilters(FilterExport filterExport, List exportFilters) { String exportString = filterExport.exportFilter(filterName, exportFilters); System.out.println(exportString); Map> importFilter = filterExport.importFilter(exportString); assertNotNull(importFilter); List importFilters = importFilter.get(filterName); assertEquals(exportFilters, importFilters); } public Filter createFormulaFilter(EnumTableColumn[] columns) { EnumTableColumn columnA = null; EnumTableColumn columnB = null; for (EnumTableColumn column : columns) { if (Number.class.isAssignableFrom(column.getType()) || NumberValue.class.isAssignableFrom(column.getType())) { if (columnA == null) { columnA = column; } else { columnB = column; break; } } } if (columnA == null || columnB == null) { return null; } Formula formula = new Formula("Formula Column", JFormulaDialog.getHardName(columnB) + " > " + JFormulaDialog.getHardName(columnA), 0); FormulaColumn column = new FormulaColumn<>(formula); return new Filter(Filter.LogicType.AND, column, Filter.CompareType.GREATER_THAN, "0"); } public Filter createJumpFilter() { Jump jump = new Jump(StaticData.get().getLocation(30000142)); //Jita JumpColumn column = new JumpColumn<>(jump); return new Filter(Filter.LogicType.AND, column, Filter.CompareType.GREATER_THAN, "0"); } public List createFilters(EnumTableColumn[] columns) { List exportFilters = new ArrayList<>(); EnumTableColumn stringColumn = null; EnumTableColumn numberColumn = null; for (EnumTableColumn column : columns) { if (stringColumn == null && column.getType().equals(String.class)) { exportFilters.add(new Filter(Filter.LogicType.AND, column, Filter.CompareType.CONTAINS, "text")); stringColumn = column; } if (numberColumn == null && column.getType().equals(Double.class)) { exportFilters.add(new Filter(Filter.LogicType.AND, column, Filter.CompareType.GREATER_THAN, "0")); numberColumn = column; } if (numberColumn != null && column.getType().equals(Double.class)) { exportFilters.add(new Filter(Filter.LogicType.AND, column, Filter.CompareType.GREATER_THAN_COLUMN, column.name())); break; } } return exportFilters; } private class TestColumnManager implements SimpleColumnManager { @Override public FormulaColumn addColumn(Formula formula) { return new FormulaColumn<>(formula); } @Override public JumpColumn addColumn(Jump jump) { return new JumpColumn<>(jump); } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/shared/filter/FilterMatcherTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.filter; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.TimeZone; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.AllColumn; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.CompareType; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import static org.junit.Assert.assertEquals; import org.junit.Test; public class FilterMatcherTest extends TestUtil { public enum TestEnum implements EnumTableColumn { TEXT(false, false), TEXT_FORMAT(false, false), LONG(true, false), INTEGER(true, false), DOUBLE(true, false), FLOAT(true, false), PERCENT(true, false), DATE(false, true), DATE_LAST(false, true), DATE_LAST_LONG(false, true), DATE_NEXT(false, true), DATE_NEXT_LONG(false, true), COLUMN_TEXT(false, false), COLUMN_NUMBER(true, false), COLUMN_PERCENT(true, false), COLUMN_DATE(false, true), NULL(true, true) ; private final boolean number; private final boolean date; private TestEnum(final boolean number, final boolean date) { this.number = number; this.date = date; } public boolean isDate() { return date; } public boolean isNumber() { return number; } @Override public Class getType() { return null; } @Override public Comparator getComparator() { return null; } @Override public String getColumnName() { return null; } @Override public Object getColumnValue(Item from) { return null; } @Override public String toString() { return getColumnName(); } } private String textColumn = null; private Number numberColumn = null; private Date dateColumn = null; private Percent percentColumn = null; private static final int BENCHMARK_ITERATIONS = 50000; private static final String TEXT = "Text"; private static final String TEXT_FORMAT = "Text\"'-"; private static final String TEXT_PART = "Tex"; private static final String TEXT_NOT = "Not"; private static final String DATE = "2005-01-02 09:00"; private static final String DATE_BEFORE = "2005-01-03 09:00"; //DATE before this private static final String DATE_NOT_BEFORE = "2005-01-02 10:00"; private static final String DATE_AFTER = "2005-01-01 9:00"; //DATE after this private static final String DATE_NOT_AFTER = "2005-01-02 8:00"; private static final String DATE_PART = "2005"; private static final String DATE_NOT = "2005-05-05"; private static final double NUMBER_DOUBLE = 222.0d; private static final float NUMBER_FLOAT = 222.0f; private static final long NUMBER_LONG = 222L; private static final int NUMBER_INTEGER = 222; private static final Percent PERCENT = Percent.create(2.22); private static final String NULL = null; private final TestTableFormat filterControl = new TestTableFormat(); private final Item item = new Item(); @Test public void testTime() { long startTime = System.currentTimeMillis(); for (int i = 0; i < 100; i++) { testMatches(); } long endTime = System.currentTimeMillis(); System.out.println("Filter time:" + (endTime - startTime) + "ms"); } /** * Speed test * @param args */ public static void main(final String[] args) { initLog(); Images.preload(); FilterMatcherTest filterMatcherTest = new FilterMatcherTest(); filterMatcherTest.testEqualsSingle(); filterMatcherTest.testRexexSingle(); filterMatcherTest.testEqualsAll(); filterMatcherTest.testRexexAll(); long duration = 0; duration += filterMatcherTest.testEqualsSingle(); duration += filterMatcherTest.testRexexSingle(); duration += filterMatcherTest.testEqualsAll(); duration += filterMatcherTest.testRexexAll(); System.out.println("Total time:" + duration + "ms"); } private long testEqualsSingle() { long startTime = System.currentTimeMillis(); for (int i = 0; i < BENCHMARK_ITERATIONS; i++) { //Equals matches(true, TestEnum.TEXT, Filter.CompareType.EQUALS, TEXT); matches(false, TestEnum.TEXT, Filter.CompareType.EQUALS, TEXT_PART); matches(false, TestEnum.TEXT, Filter.CompareType.EQUALS, TEXT_NOT); } long endTime = System.currentTimeMillis(); System.out.println("Equals Single time:" + (endTime - startTime) + "ms"); return (endTime - startTime); } private long testRexexSingle() { long startTime = System.currentTimeMillis(); for (int i = 0; i < BENCHMARK_ITERATIONS; i++) { //Regex matches(true, TestEnum.TEXT, Filter.CompareType.REGEX, TEXT); matches(true, TestEnum.TEXT, Filter.CompareType.REGEX, TEXT_PART); matches(false, TestEnum.TEXT, Filter.CompareType.REGEX, TEXT_NOT); } long endTime = System.currentTimeMillis(); System.out.println("Rexex Single time:" + (endTime - startTime) + "ms"); return (endTime - startTime); } private long testEqualsAll() { long startTime = System.currentTimeMillis(); for (int i = 0; i < BENCHMARK_ITERATIONS; i++) { //Equals matches(true, new AllColumn<>(), Filter.CompareType.EQUALS, TEXT); matches(false, new AllColumn<>(), Filter.CompareType.EQUALS, TEXT_PART); matches(false, new AllColumn<>(), Filter.CompareType.EQUALS, TEXT_NOT); } long endTime = System.currentTimeMillis(); System.out.println("Equals All time:" + (endTime - startTime) + "ms"); return (endTime - startTime); } private long testRexexAll() { long startTime = System.currentTimeMillis(); for (int i = 0; i < BENCHMARK_ITERATIONS; i++) { //Regex matches(true, TestEnum.TEXT, Filter.CompareType.REGEX, TEXT); matches(true, TestEnum.TEXT, Filter.CompareType.REGEX, TEXT_PART); matches(false, TestEnum.TEXT, Filter.CompareType.REGEX, TEXT_NOT); } long endTime = System.currentTimeMillis(); System.out.println("Rexex All time:" + (endTime - startTime) + "ms"); return (endTime - startTime); } /** * Test of matches method, of class FilterControl. */ public void testMatches() { //String stringTest(); stringFormatTest(); //Numbers doubleTest(); floatTest(); longTest(); integerTest(); //Date dateTest(); //Percent percentTest(); //All allTest(); //Logic logicTest(); //Null nullTest(); } private void matches(final boolean expected, final EnumTableColumn enumColumn, final CompareType compare, final String text) { matches(expected, enumColumn, compare, text, null, null, null, null); } private void matches(final boolean expected, final EnumTableColumn enumColumn, final CompareType compare, final String text, final String textColumn) { matches(expected, enumColumn, compare, text, textColumn, null, null, null); } private void matches(final boolean expected, final EnumTableColumn enumColumn, final CompareType compare, final String text, final Number numberColumn) { matches(expected, enumColumn, compare, text, null, numberColumn, null, null); } private void matches(final boolean expected, final EnumTableColumn enumColumn, final CompareType compare, final String text, final Date dateColumn) { matches(expected, enumColumn, compare, text, null, null, dateColumn, null); } private void matches(final boolean expected, final EnumTableColumn enumColumn, final CompareType compare, final String text, final Percent percentColumn) { matches(expected, enumColumn, compare, text, null, null, null, percentColumn); } private void matches(final boolean expected, final EnumTableColumn enumColumn, final CompareType compare, final String text, final String textColumn, final Number numberColumn, final Date dateColumn, final Percent percentColumn) { //Test matches this.textColumn = textColumn; this.numberColumn = numberColumn; this.dateColumn = dateColumn; this.percentColumn = percentColumn; FilterMatcher filterMatcher; filterMatcher = new FilterMatcher<>(filterControl, null, 1, Filter.LogicType.AND, enumColumn, compare, text, true); assertEquals("Matcher: value:" + text + " [" + compare + "]" + enumColumn.getColumnValue(item) + "(" + enumColumn.name() + ")", expected, filterMatcher.matches(item)); filterMatcher = new FilterMatcher<>(filterControl, null, new Filter(1, Filter.LogicType.AND, enumColumn, compare, text, true)); assertEquals("Filter: " + enumColumn.name() + " value:" + text, expected, filterMatcher.matches(item)); } private void matches(final Object expected, String text1, String text2, String text3, String text4, String text5) { List> filterMatchers = new ArrayList<>(); filterMatchers.add(new FilterMatcher<>(filterControl, null, 1, Filter.LogicType.OR, TestEnum.TEXT, CompareType.EQUALS, text1, true)); filterMatchers.add(new FilterMatcher<>(filterControl, null, 1, Filter.LogicType.OR, TestEnum.TEXT, CompareType.EQUALS, text2, true)); filterMatchers.add(new FilterMatcher<>(filterControl, null, 2, Filter.LogicType.OR, TestEnum.TEXT, CompareType.EQUALS, text3, true)); filterMatchers.add(new FilterMatcher<>(filterControl, null, 2, Filter.LogicType.OR, TestEnum.TEXT, CompareType.EQUALS, text4, true)); filterMatchers.add(new FilterMatcher<>(filterControl, null, 0, Filter.LogicType.AND, TestEnum.TEXT, CompareType.EQUALS, text5, true)); FilterLogicalMatcher logicalMatcher = new FilterLogicalMatcher<>(filterMatchers); assertEquals("(" + text1 + " OR " + text2 +") AND (" + text3 + " OR " + text4 + ") AND " + text5 + " --> Matching: " + TEXT, expected, logicalMatcher.matches(item)); } @Test public void logicTest() { matches(true, TEXT, TEXT_NOT, TEXT, TEXT_NOT, TEXT); //(true OR false) AND (true OR false) AND true = (true + true + true) = true matches(true, TEXT_NOT, TEXT, TEXT_NOT, TEXT, TEXT); //(false OR true) AND (false OR true) AND true = (true + true + true) = true matches(false, TEXT_NOT, TEXT, TEXT_NOT, TEXT, TEXT_NOT); //(false OR true) AND (false OR true) AND false = (true + true + false) = false matches(false, TEXT_NOT, TEXT_NOT, TEXT, TEXT_NOT, TEXT); //(false OR false) AND (true OR false) AND true = (false + true + true) = false matches(false, TEXT, TEXT_NOT, TEXT_NOT, TEXT_NOT, TEXT); //(true OR false) AND (false OR false) AND true = (true + false + true) = false matches(false, TEXT_NOT, TEXT_NOT, TEXT_NOT, TEXT_NOT, TEXT); //(false OR false) AND (false OR false) AND true = (false + false + true) = false } @Test public void nullTest() { TestEnum[] columns = {TestEnum.TEXT, TestEnum.TEXT_FORMAT, TestEnum.LONG, TestEnum.INTEGER, TestEnum.DOUBLE, TestEnum.FLOAT, TestEnum.PERCENT, TestEnum.DATE, TestEnum.DATE_LAST, TestEnum.NULL}; for (TestEnum column : columns) { matches(false, column, CompareType.EQUALS, NULL); matches(column != TestEnum.NULL, column, CompareType.EQUALS_NOT, NULL); matches(false, column, CompareType.EQUALS_DATE, NULL); matches(column != TestEnum.NULL, column, CompareType.EQUALS_NOT_DATE, NULL); matches(false, column, CompareType.CONTAINS, NULL); matches(column != TestEnum.NULL, column, CompareType.CONTAINS_NOT, NULL); matches(false, column, CompareType.AFTER, NULL); matches(false, column, CompareType.BEFORE, NULL); matches(column != TestEnum.NULL, column, CompareType.GREATER_THAN, NULL); matches(false, column, CompareType.LESS_THAN, NULL); matches(false, column, CompareType.LAST_HOURS, NULL); matches(false, column, CompareType.LAST_DAYS, NULL); matches(false, column, CompareType.NEXT_HOURS, NULL); matches(false, column, CompareType.NEXT_DAYS, NULL); matches(false, column, CompareType.REGEX, NULL); } TestEnum[] columns2 = {TestEnum.COLUMN_DATE, TestEnum.COLUMN_NUMBER, TestEnum.COLUMN_PERCENT, TestEnum.COLUMN_TEXT}; for (TestEnum column : columns2) { matches(false, column, CompareType.EQUALS_COLUMN, NULL, (String)null); matches(false, column, CompareType.EQUALS_NOT_COLUMN, NULL, (String)null); matches(false, column, CompareType.CONTAINS_COLUMN, NULL, (String)null); matches(false, column, CompareType.CONTAINS_NOT_COLUMN, NULL, (String)null); matches(false, column, CompareType.AFTER_COLUMN, NULL, (Date)null); matches(false, column, CompareType.BEFORE_COLUMN, NULL, (Date)null); matches(false, column, CompareType.GREATER_THAN_COLUMN, NULL, (Number)null); matches(false, column, CompareType.LESS_THAN_COLUMN, NULL, (Number)null); } for (CompareType compareType : CompareType.values()) { matches(true, new AllColumn<>(), compareType, NULL); } } @Test public void dateTest() { //Equals matches(true, TestEnum.DATE, Filter.CompareType.EQUALS, DATE); matches(false, TestEnum.DATE, Filter.CompareType.EQUALS, DATE_NOT_AFTER); matches(false, TestEnum.DATE, Filter.CompareType.EQUALS, DATE_NOT_BEFORE); matches(false, TestEnum.DATE, Filter.CompareType.EQUALS, DATE_PART); matches(false, TestEnum.DATE, Filter.CompareType.EQUALS, DATE_NOT); //Equals not matches(false, TestEnum.DATE, Filter.CompareType.EQUALS_NOT, DATE); matches(true, TestEnum.DATE, Filter.CompareType.EQUALS_NOT, DATE_PART); matches(true, TestEnum.DATE, Filter.CompareType.EQUALS_NOT, DATE_NOT); //Equals date matches(true, TestEnum.DATE, Filter.CompareType.EQUALS_DATE, DATE); matches(true, TestEnum.DATE, Filter.CompareType.EQUALS_DATE, DATE_NOT_AFTER); matches(true, TestEnum.DATE, Filter.CompareType.EQUALS_DATE, DATE_NOT_BEFORE); matches(false, TestEnum.DATE, Filter.CompareType.EQUALS_DATE, DATE_PART); matches(false, TestEnum.DATE, Filter.CompareType.EQUALS_DATE, DATE_NOT); //Equals not date matches(false, TestEnum.DATE, Filter.CompareType.EQUALS_NOT_DATE, DATE); matches(true, TestEnum.DATE, Filter.CompareType.EQUALS_NOT_DATE, DATE_PART); matches(true, TestEnum.DATE, Filter.CompareType.EQUALS_NOT_DATE, DATE_NOT); //Contains matches(true, TestEnum.DATE, Filter.CompareType.CONTAINS, DATE); matches(true, TestEnum.DATE, Filter.CompareType.CONTAINS, DATE_PART); matches(false, TestEnum.DATE, Filter.CompareType.CONTAINS, DATE_NOT); //Contains not matches(false, TestEnum.DATE, Filter.CompareType.CONTAINS_NOT, DATE); matches(false, TestEnum.DATE, Filter.CompareType.CONTAINS_NOT, DATE_PART); matches(true, TestEnum.DATE, Filter.CompareType.CONTAINS_NOT, DATE_NOT); //Regex matches(true, TestEnum.DATE, Filter.CompareType.REGEX, DATE); matches(true, TestEnum.DATE, Filter.CompareType.REGEX, DATE_PART); matches(false, TestEnum.DATE, Filter.CompareType.REGEX, DATE_NOT); //Before matches(false, TestEnum.DATE, Filter.CompareType.BEFORE, DATE); matches(false, TestEnum.DATE, Filter.CompareType.BEFORE, DATE_AFTER); matches(false, TestEnum.DATE, Filter.CompareType.BEFORE, DATE_NOT_BEFORE); matches(true, TestEnum.DATE, Filter.CompareType.BEFORE, DATE_BEFORE); //After matches(false, TestEnum.DATE, Filter.CompareType.AFTER, DATE); matches(true, TestEnum.DATE, Filter.CompareType.AFTER, DATE_AFTER); matches(false, TestEnum.DATE, Filter.CompareType.BEFORE, DATE_NOT_AFTER); matches(false, TestEnum.DATE, Filter.CompareType.AFTER, DATE_BEFORE); //Last x days matches(false, TestEnum.DATE_LAST, Filter.CompareType.LAST_DAYS, "1"); //Last 1 days matches(true, TestEnum.DATE_LAST, Filter.CompareType.LAST_DAYS, "2"); //Last 2 days matches(false, TestEnum.DATE_LAST_LONG, Filter.CompareType.LAST_DAYS, "399"); //Last 399 days matches(true, TestEnum.DATE_LAST_LONG, Filter.CompareType.LAST_DAYS, "400"); //Last 400 days //Next x days matches(false, TestEnum.DATE_NEXT, Filter.CompareType.NEXT_DAYS, "1"); //Next 1 days matches(true, TestEnum.DATE_NEXT, Filter.CompareType.NEXT_DAYS, "2"); //Next 2 days matches(false, TestEnum.DATE_NEXT_LONG, Filter.CompareType.NEXT_DAYS, "399"); //Next 399 days matches(true, TestEnum.DATE_NEXT_LONG, Filter.CompareType.NEXT_DAYS, "400"); //Next 400 days //Last x hours matches(false, TestEnum.DATE_LAST, Filter.CompareType.LAST_HOURS, "24"); //Last 24 hours matches(true, TestEnum.DATE_LAST, Filter.CompareType.LAST_HOURS, "48"); //Last 48 hours matches(false, TestEnum.DATE_LAST_LONG, Filter.CompareType.LAST_HOURS, "9599"); //Last 9599 hours matches(true, TestEnum.DATE_LAST_LONG, Filter.CompareType.LAST_HOURS, "9600"); //Last 9600 hours //Next x hours matches(false, TestEnum.DATE_NEXT, Filter.CompareType.NEXT_HOURS, "24"); //Next 24 hours matches(true, TestEnum.DATE_NEXT, Filter.CompareType.NEXT_HOURS, "48"); //Next 48 hours matches(false, TestEnum.DATE_NEXT_LONG, Filter.CompareType.NEXT_HOURS, "9599"); //Next 9599 hours matches(true, TestEnum.DATE_NEXT_LONG, Filter.CompareType.NEXT_HOURS, "9600"); //Next 9600 hours //Equals column matches(true, TestEnum.DATE, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE)); matches(false, TestEnum.DATE, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE_NOT_AFTER)); matches(false, TestEnum.DATE, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE_NOT_BEFORE)); matches(false, TestEnum.DATE, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE_NOT)); //Equals not column matches(false, TestEnum.DATE, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE)); matches(true, TestEnum.DATE, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE_NOT)); //Contains column matches(true, TestEnum.DATE, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE)); matches(false, TestEnum.DATE, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE_NOT)); //Contains not column matches(false, TestEnum.DATE, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE)); matches(true, TestEnum.DATE, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE_NOT)); //Before column matches(false, TestEnum.DATE, Filter.CompareType.BEFORE_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE)); matches(false, TestEnum.DATE, Filter.CompareType.BEFORE_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE_AFTER)); matches(false, TestEnum.DATE, Filter.CompareType.BEFORE_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE_NOT_BEFORE)); matches(true, TestEnum.DATE, Filter.CompareType.BEFORE_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE_BEFORE)); //After column matches(false, TestEnum.DATE, Filter.CompareType.AFTER_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE)); matches(true, TestEnum.DATE, Filter.CompareType.AFTER_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE_AFTER)); matches(false, TestEnum.DATE, Filter.CompareType.AFTER_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE_NOT_AFTER)); matches(false, TestEnum.DATE, Filter.CompareType.AFTER_COLUMN, TestEnum.COLUMN_DATE.name(), Formatter.columnStringToDate(DATE_BEFORE)); } @Test public void stringTest() { //Equals matches(true, TestEnum.TEXT, Filter.CompareType.EQUALS, TEXT); matches(false, TestEnum.TEXT, Filter.CompareType.EQUALS, TEXT_PART); matches(false, TestEnum.TEXT, Filter.CompareType.EQUALS, TEXT_NOT); //Equals not matches(false, TestEnum.TEXT, Filter.CompareType.EQUALS_NOT, TEXT); matches(true, TestEnum.TEXT, Filter.CompareType.EQUALS_NOT, TEXT_PART); matches(true, TestEnum.TEXT, Filter.CompareType.EQUALS_NOT, TEXT_NOT); //Contains matches(true, TestEnum.TEXT, Filter.CompareType.CONTAINS, TEXT); matches(true, TestEnum.TEXT, Filter.CompareType.CONTAINS, TEXT_PART); matches(false, TestEnum.TEXT, Filter.CompareType.CONTAINS, TEXT_NOT); //Contains not matches(false, TestEnum.TEXT, Filter.CompareType.CONTAINS_NOT, TEXT); matches(false, TestEnum.TEXT, Filter.CompareType.CONTAINS_NOT, TEXT_PART); matches(true, TestEnum.TEXT, Filter.CompareType.CONTAINS_NOT, TEXT_NOT); //Regex matches(true, TestEnum.TEXT, Filter.CompareType.REGEX, TEXT); matches(true, TestEnum.TEXT, Filter.CompareType.REGEX, TEXT_PART); matches(false, TestEnum.TEXT, Filter.CompareType.REGEX, TEXT_NOT); //Equals column matches(true, TestEnum.TEXT, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_TEXT.name(), TEXT); matches(false, TestEnum.TEXT, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_TEXT.name(), TEXT_PART); matches(false, TestEnum.TEXT, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_TEXT.name(), TEXT_NOT); //Equals not matches(false, TestEnum.TEXT, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_TEXT.name(), TEXT); matches(true, TestEnum.TEXT, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_TEXT.name(), TEXT_PART); matches(true, TestEnum.TEXT, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_TEXT.name(), TEXT_NOT); //Contains matches(true, TestEnum.TEXT, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_TEXT.name(), TEXT); matches(true, TestEnum.TEXT, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_TEXT.name(), TEXT_PART); matches(false, TestEnum.TEXT, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_TEXT.name(), TEXT_NOT); //Contains not matches(false, TestEnum.TEXT, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_TEXT.name(), TEXT); matches(false, TestEnum.TEXT, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_TEXT.name(), TEXT_PART); matches(true, TestEnum.TEXT, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_TEXT.name(), TEXT_NOT); } @Test public void stringFormatTest() { //Equals matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.EQUALS, TEXT + "\"'-"); matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.EQUALS, TEXT + "„‘–"); matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.EQUALS, TEXT + "“’‐"); matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.EQUALS, TEXT + "”`‑"); matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.EQUALS, TEXT + "\"´‒"); matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.EQUALS, TEXT + "\"'—"); //Contains matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "\""); matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "'"); matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "-"); matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "„"); //Index matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "“"); //Set transmit state matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "”"); //Cancel character matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "‘"); //Private use one matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "’"); //Private use two matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "`"); //Grave accent matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "´"); //Acute accent matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "–"); //En dash matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "‐"); //Hyphen matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "‑"); //Non-breaking hyphen matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "‒"); //Figure dEash matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.CONTAINS, "—"); //Em dash //Regex matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "\""); matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "'"); matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "-"); matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "„"); //Index matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "“"); //Set transmit state matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "”"); //Cancel character matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "‘"); //Private use one matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "’"); //Private use two matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "`"); //Grave accent matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "´"); //Acute accent matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "–"); //En dash matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "‐"); //Hyphen matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "‑"); //Non-breaking hyphen matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "‒"); //Figure dash matches(true, TestEnum.TEXT_FORMAT, Filter.CompareType.REGEX, "—"); //Em dash //All - Regex matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "\""); matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "'"); matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "-"); matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "„"); //Index matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "“"); //Set transmit state matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "”"); //Cancel character matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "‘"); //Private use one matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "’"); //Private use two matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "`"); //Grave accent matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "´"); //Acute accent matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "–"); //En dash matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "‐"); //Hyphen matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "‑"); //Non-breaking hyphen matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "‒"); //Figure dash matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "—"); //Em dash //All - Contains matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "\""); matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "'"); matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "-"); matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "„"); //Index matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "“"); //Set transmit state matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "”"); //Cancel character matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "‘"); //Private use one matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "’"); //Private use two matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "`"); //Grave accent matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "´"); //Acute accent matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "–"); //En dash matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "‐"); //Hyphen matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "‑"); //Non-breaking hyphen matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "‒"); //Figure dash matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "—"); //Em dash //All - Equals matches(true, new AllColumn<>(), Filter.CompareType.EQUALS, TEXT + "\"'-"); matches(true, new AllColumn<>(), Filter.CompareType.EQUALS, TEXT + "„‘–"); matches(true, new AllColumn<>(), Filter.CompareType.EQUALS, TEXT + "“’‐"); matches(true, new AllColumn<>(), Filter.CompareType.EQUALS, TEXT + "”`‑"); matches(true, new AllColumn<>(), Filter.CompareType.EQUALS, TEXT + "\"´‒"); matches(true, new AllColumn<>(), Filter.CompareType.EQUALS, TEXT + "\"'—"); } @Test public void doubleTest() { numberTest(TestEnum.DOUBLE); } @Test public void floatTest() { numberTest(TestEnum.FLOAT); } @Test public void longTest() { numberTest(TestEnum.LONG); } @Test public void integerTest() { numberTest(TestEnum.INTEGER); } private void numberTest(final TestEnum testEnum) { //Equals matches(true, testEnum, Filter.CompareType.EQUALS, "222"); matches(true, testEnum, Filter.CompareType.EQUALS, "222.0"); matches(false, testEnum, Filter.CompareType.EQUALS, "223"); matches(false, testEnum, Filter.CompareType.EQUALS, "223.1"); matches(false, testEnum, Filter.CompareType.EQUALS, "222.1"); //Equals not matches(true, testEnum, Filter.CompareType.EQUALS_NOT, "223"); matches(true, testEnum, Filter.CompareType.EQUALS_NOT, "223.1"); matches(true, testEnum, Filter.CompareType.EQUALS_NOT, "222.1"); matches(false, testEnum, Filter.CompareType.EQUALS_NOT, "222"); matches(false, testEnum, Filter.CompareType.EQUALS_NOT, "222.0"); //Contains matches(true, testEnum, Filter.CompareType.CONTAINS, "222"); matches(true, testEnum, Filter.CompareType.CONTAINS, "222.0"); matches(false, testEnum, Filter.CompareType.CONTAINS, "223"); matches(false, testEnum, Filter.CompareType.CONTAINS, "223.1"); matches(false, testEnum, Filter.CompareType.CONTAINS, "222.1"); //Contains not matches(true, testEnum, Filter.CompareType.CONTAINS_NOT, "223"); matches(true, testEnum, Filter.CompareType.CONTAINS_NOT, "223.1"); matches(true, testEnum, Filter.CompareType.CONTAINS_NOT, "222.1"); matches(false, testEnum, Filter.CompareType.CONTAINS_NOT, "222"); matches(false, testEnum, Filter.CompareType.CONTAINS_NOT, "222.0"); //Regex matches(true, testEnum, Filter.CompareType.REGEX, "222"); matches(false, testEnum, Filter.CompareType.REGEX, "222.0"); matches(false, testEnum, Filter.CompareType.REGEX, "223"); matches(false, testEnum, Filter.CompareType.REGEX, "223.1"); matches(false, testEnum, Filter.CompareType.REGEX, "222.1"); //Great than matches(false, testEnum, Filter.CompareType.GREATER_THAN, "222.0"); matches(false, testEnum, Filter.CompareType.GREATER_THAN, "222"); matches(false, testEnum, Filter.CompareType.GREATER_THAN, "222.1"); matches(false, testEnum, Filter.CompareType.GREATER_THAN, "223"); matches(true, testEnum, Filter.CompareType.GREATER_THAN, "221.0"); matches(true, testEnum, Filter.CompareType.GREATER_THAN, "221.9"); matches(true, testEnum, Filter.CompareType.GREATER_THAN, "221"); //Less than matches(false, testEnum, Filter.CompareType.LESS_THAN, "222.0"); matches(false, testEnum, Filter.CompareType.LESS_THAN, "222"); matches(true, testEnum, Filter.CompareType.LESS_THAN, "222.1"); matches(true, testEnum, Filter.CompareType.LESS_THAN, "223"); matches(false, testEnum, Filter.CompareType.LESS_THAN, "221.0"); matches(false, testEnum, Filter.CompareType.LESS_THAN, "221.9"); matches(false, testEnum, Filter.CompareType.LESS_THAN, "221"); //Equals column matches(true, testEnum, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222); matches(true, testEnum, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222.0); matches(false, testEnum, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_NUMBER.name(), 223); matches(false, testEnum, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_NUMBER.name(), 223.1); matches(false, testEnum, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222.1); //Equals not column matches(true, testEnum, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_NUMBER.name(), 223); matches(true, testEnum, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_NUMBER.name(), 223.1); matches(true, testEnum, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222.1); matches(false, testEnum, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222); matches(false, testEnum, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222.0); //Contains column matches(true, testEnum, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222); matches(true, testEnum, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222.0); matches(false, testEnum, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_NUMBER.name(), 223); matches(false, testEnum, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_NUMBER.name(), 223.1); matches(false, testEnum, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222.1); //Contains not column matches(true, testEnum, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_NUMBER.name(), 223); matches(true, testEnum, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_NUMBER.name(), 223.1); matches(true, testEnum, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222.1); matches(false, testEnum, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222); matches(false, testEnum, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222.0); //Great than column matches(false, testEnum, Filter.CompareType.GREATER_THAN_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222.0); matches(false, testEnum, Filter.CompareType.GREATER_THAN_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222); matches(false, testEnum, Filter.CompareType.GREATER_THAN_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222.1); matches(false, testEnum, Filter.CompareType.GREATER_THAN_COLUMN, TestEnum.COLUMN_NUMBER.name(), 223); matches(true, testEnum, Filter.CompareType.GREATER_THAN_COLUMN, TestEnum.COLUMN_NUMBER.name(), 221.0); matches(true, testEnum, Filter.CompareType.GREATER_THAN_COLUMN, TestEnum.COLUMN_NUMBER.name(), 221.9); matches(true, testEnum, Filter.CompareType.GREATER_THAN_COLUMN, TestEnum.COLUMN_NUMBER.name(), 221); //Less than column matches(false, testEnum, Filter.CompareType.LESS_THAN_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222.0); matches(false, testEnum, Filter.CompareType.LESS_THAN_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222); matches(true, testEnum, Filter.CompareType.LESS_THAN_COLUMN, TestEnum.COLUMN_NUMBER.name(), 222.1); matches(true, testEnum, Filter.CompareType.LESS_THAN_COLUMN, TestEnum.COLUMN_NUMBER.name(), 223); matches(false, testEnum, Filter.CompareType.LESS_THAN_COLUMN, TestEnum.COLUMN_NUMBER.name(), 221.0); matches(false, testEnum, Filter.CompareType.LESS_THAN_COLUMN, TestEnum.COLUMN_NUMBER.name(), 221.9); matches(false, testEnum, Filter.CompareType.LESS_THAN_COLUMN, TestEnum.COLUMN_NUMBER.name(), 221); } @Test public void percentTest() { //Equals matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS, "222%"); matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS, "222.0%"); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS, "223%"); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS, "223.1%"); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS, "222.1%"); //Equals not matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT, "223%"); matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT, "223.1%"); matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT, "222.1%"); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT, "222%"); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT, "222.0%"); //Contains matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS, "222%"); matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS, "222.0%"); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS, "223%"); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS, "223.1%"); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS, "222.1%"); //Contains not matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT, "223%"); matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT, "223.1%"); matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT, "222.1%"); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT, "222%"); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT, "222.0%"); //Regex matches(true, TestEnum.PERCENT, Filter.CompareType.REGEX, "222"); matches(false, TestEnum.PERCENT, Filter.CompareType.REGEX, "222.0%"); matches(false, TestEnum.PERCENT, Filter.CompareType.REGEX, "223%"); matches(false, TestEnum.PERCENT, Filter.CompareType.REGEX, "223.1%"); matches(false, TestEnum.PERCENT, Filter.CompareType.REGEX, "222.1%"); //Great than matches(false, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN, "222.0%"); matches(false, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN, "222%"); matches(false, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN, "222.1%"); matches(false, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN, "223%"); matches(true, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN, "221.0%"); matches(true, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN, "221.9%"); matches(true, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN, "221%"); //Less than matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN, "222.0%"); matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN, "222%"); matches(true, TestEnum.PERCENT, Filter.CompareType.LESS_THAN, "222.1%"); matches(true, TestEnum.PERCENT, Filter.CompareType.LESS_THAN, "223%"); matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN, "221.0%"); matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN, "221.9%"); matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN, "221%"); //Equals matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS, "222"); matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS, "222.0"); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS, "223"); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS, "223.1"); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS, "222.1"); //Equals not matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT, "223"); matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT, "223.1"); matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT, "222.1"); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT, "222"); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT, "222.0"); //Contains matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS, "222"); matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS, "222.0"); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS, "223"); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS, "223.1"); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS, "222.1"); //Contains not matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT, "223"); matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT, "223.1"); matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT, "222.1"); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT, "222"); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT, "222.0"); //Great than matches(false, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN, "222.0"); matches(false, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN, "222"); matches(false, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN, "222.1"); matches(false, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN, "223"); matches(true, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN, "221.0"); matches(true, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN, "221.9"); matches(true, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN, "221"); //Less than matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN, "222.0"); matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN, "222"); matches(true, TestEnum.PERCENT, Filter.CompareType.LESS_THAN, "222.1"); matches(true, TestEnum.PERCENT, Filter.CompareType.LESS_THAN, "223"); matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN, "221.0"); matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN, "221.9"); matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN, "221"); //Equals column matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.22)); matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.220)); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.23)); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.231)); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.221)); //Equals not column matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.23)); matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.231)); matches(true, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.221)); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.22)); matches(false, TestEnum.PERCENT, Filter.CompareType.EQUALS_NOT_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.220)); //Contains column matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.22)); matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.220)); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.23)); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.231)); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.221)); //Contains not column matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.23)); matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.231)); matches(true, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.221)); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.22)); matches(false, TestEnum.PERCENT, Filter.CompareType.CONTAINS_NOT_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.220)); //Great than column matches(false, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.220)); matches(false, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.22)); matches(false, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.221)); matches(false, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.23)); matches(true, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.210)); matches(true, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.219)); matches(true, TestEnum.PERCENT, Filter.CompareType.GREATER_THAN_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.21)); //Less than column matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.220)); matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.22)); matches(true, TestEnum.PERCENT, Filter.CompareType.LESS_THAN_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.221)); matches(true, TestEnum.PERCENT, Filter.CompareType.LESS_THAN_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.23)); matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.210)); matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.219)); matches(false, TestEnum.PERCENT, Filter.CompareType.LESS_THAN_COLUMN, TestEnum.COLUMN_PERCENT.name(), Percent.create(2.21)); } @Test public void allTest() { //Text //Equals matches(true, new AllColumn<>(), Filter.CompareType.EQUALS, TEXT); matches(false, new AllColumn<>(), Filter.CompareType.EQUALS, TEXT_PART); matches(false, new AllColumn<>(), Filter.CompareType.EQUALS, TEXT_NOT); //Equals not matches(false, new AllColumn<>(), Filter.CompareType.EQUALS_NOT, TEXT); matches(true, new AllColumn<>(), Filter.CompareType.EQUALS_NOT, TEXT_PART); matches(true, new AllColumn<>(), Filter.CompareType.EQUALS_NOT, TEXT_NOT); //Contains matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, TEXT); matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, TEXT_PART); matches(false, new AllColumn<>(), Filter.CompareType.CONTAINS, TEXT_NOT); //Contains not matches(false, new AllColumn<>(), Filter.CompareType.CONTAINS_NOT, TEXT); matches(false, new AllColumn<>(), Filter.CompareType.CONTAINS_NOT, TEXT_PART); matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS_NOT, TEXT_NOT); //Regex matches(true, new AllColumn<>(), Filter.CompareType.REGEX, TEXT); matches(true, new AllColumn<>(), Filter.CompareType.REGEX, TEXT_PART); matches(false, new AllColumn<>(), Filter.CompareType.REGEX, TEXT_NOT); //Number //Equals matches(true, new AllColumn<>(), Filter.CompareType.EQUALS, "222"); matches(true, new AllColumn<>(), Filter.CompareType.EQUALS, "222.0"); matches(false, new AllColumn<>(), Filter.CompareType.EQUALS, "223"); matches(false, new AllColumn<>(), Filter.CompareType.EQUALS, "223.1"); matches(false, new AllColumn<>(), Filter.CompareType.EQUALS, "222.1"); //Equals not matches(true, new AllColumn<>(), Filter.CompareType.EQUALS_NOT, "223"); matches(true, new AllColumn<>(), Filter.CompareType.EQUALS_NOT, "223.1"); matches(true, new AllColumn<>(), Filter.CompareType.EQUALS_NOT, "222.1"); matches(false, new AllColumn<>(), Filter.CompareType.EQUALS_NOT, "222"); matches(false, new AllColumn<>(), Filter.CompareType.EQUALS_NOT, "222.0"); //Contains matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "222"); matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, "222.0"); matches(false, new AllColumn<>(), Filter.CompareType.CONTAINS, "223"); matches(false, new AllColumn<>(), Filter.CompareType.CONTAINS, "223.1"); matches(false, new AllColumn<>(), Filter.CompareType.CONTAINS, "222.1"); //Contains not matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS_NOT, "223"); matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS_NOT, "223.1"); matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS_NOT, "222.1"); matches(false, new AllColumn<>(), Filter.CompareType.CONTAINS_NOT, "222"); matches(false, new AllColumn<>(), Filter.CompareType.CONTAINS_NOT, "222.0"); //Contains matches(true, new AllColumn<>(), Filter.CompareType.REGEX, "222"); matches(false, new AllColumn<>(), Filter.CompareType.REGEX, "222\\.0"); matches(false, new AllColumn<>(), Filter.CompareType.REGEX, "223"); matches(false, new AllColumn<>(), Filter.CompareType.REGEX, "223\\.1"); matches(false, new AllColumn<>(), Filter.CompareType.REGEX, "222\\.1"); //Date //Equals matches(true, new AllColumn<>(), Filter.CompareType.EQUALS, DATE); matches(false, new AllColumn<>(), Filter.CompareType.EQUALS, DATE_PART); matches(false, new AllColumn<>(), Filter.CompareType.EQUALS, DATE_NOT); //Equals not matches(false, new AllColumn<>(), Filter.CompareType.EQUALS_NOT, DATE); matches(true, new AllColumn<>(), Filter.CompareType.EQUALS_NOT, DATE_PART); matches(true, new AllColumn<>(), Filter.CompareType.EQUALS_NOT, DATE_NOT); //Contains matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, DATE); matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS, DATE_PART); matches(false, new AllColumn<>(), Filter.CompareType.CONTAINS, DATE_NOT); //Contains not matches(false, new AllColumn<>(), Filter.CompareType.CONTAINS_NOT, DATE); matches(false, new AllColumn<>(), Filter.CompareType.CONTAINS_NOT, DATE_PART); matches(true, new AllColumn<>(), Filter.CompareType.CONTAINS_NOT, DATE_NOT); //Contains matches(true, new AllColumn<>(), Filter.CompareType.REGEX, DATE); matches(true, new AllColumn<>(), Filter.CompareType.REGEX, DATE_PART); matches(false, new AllColumn<>(), Filter.CompareType.REGEX, DATE_NOT); } public static class Item { } public class TestTableFormat implements SimpleTableFormat { @Override public EnumTableColumn valueOf(final String column) { return TestEnum.valueOf(column); } @Override public Object getColumnValue(final Item item, final String columnString) { Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT")); EnumTableColumn column = valueOf(columnString); if (column instanceof TestEnum) { TestEnum format = (TestEnum) column; switch (format) { case TEXT: return TEXT; case TEXT_FORMAT: return TEXT_FORMAT; case DOUBLE: return NUMBER_DOUBLE; case FLOAT: return NUMBER_FLOAT; case LONG: return NUMBER_LONG; case INTEGER: return NUMBER_INTEGER; case PERCENT: return PERCENT; case DATE: return Formatter.columnStringToDate(DATE); case DATE_LAST: //minus 47 hours calendar.setTime(new Date()); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); calendar.add(Calendar.HOUR_OF_DAY, +1); calendar.add(Calendar.DAY_OF_MONTH, -2); return calendar.getTime(); case DATE_LAST_LONG: //minus 400 days calendar.setTime(new Date()); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); calendar.add(Calendar.HOUR_OF_DAY, +1); calendar.add(Calendar.DAY_OF_MONTH, -400); return calendar.getTime(); case DATE_NEXT: //plus 49 hours calendar.setTime(new Date()); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); calendar.add(Calendar.DAY_OF_MONTH, 2); return calendar.getTime(); case DATE_NEXT_LONG: //plus 400 days calendar.setTime(new Date()); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); calendar.add(Calendar.DAY_OF_MONTH, 400); return calendar.getTime(); case COLUMN_TEXT: return textColumn; case COLUMN_NUMBER: return numberColumn; case COLUMN_PERCENT: return percentColumn; case COLUMN_DATE: return dateColumn; case NULL: return null; default: break; } } return null; } @Override public List> getAllColumns() { return new ArrayList<>(Arrays.asList(TestEnum.values())); } @Override public List> getShownColumns() { return null; //Only used by the GUI } @Override public void addColumn(EnumTableColumn column) { } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/shared/menu/ExpressionExceptionTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import com.udojava.evalex.Expression; import java.util.HashSet; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import org.junit.Test; public class ExpressionExceptionTest extends TestUtil { @Test public void testNullPointerException() { eval("\""); } @Test public void testStringIndexOutOfBoundsException() { eval("100\""); } @Test public void testArithmeticException() { eval("100/0"); } @Test public void testNumberFormatException() { eval("1.0."); } @Test public void testExpressionException() { eval(""); } private void eval(String eval) { //Re-use expression Expression expression = new Expression(eval, JFormulaDialog.FORMULA_PRECISION); JFormulaDialog.safeEval(new HashSet<>(), expression); EnumTableFormatAdaptor.safeEval(expression); //One time use JFormulaDialog.safeEval(new HashSet<>(), new Expression(eval, JFormulaDialog.FORMULA_PRECISION)); EnumTableFormatAdaptor.safeEval(new Expression(eval, JFormulaDialog.FORMULA_PRECISION)); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuInfoTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import ca.odell.glazedlists.BasicEventList; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.SeparatorList; import ch.qos.logback.classic.Level; import java.util.ArrayList; import java.util.List; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuInfo.MaterialTotal; import net.nikr.eve.jeveasset.gui.tabs.materials.Material; import net.nikr.eve.jeveasset.gui.tabs.materials.MaterialSeparatorComparator; import net.nikr.eve.jeveasset.i18n.TabsMaterials; import org.junit.*; import static org.junit.Assert.assertEquals; public class JMenuInfoTest extends TestUtil { private static Material summaryAll; private static Material summaryTotal_group1; private static Material summaryTotal_group2; private static Material summary_group1; private static Material summary_group2; private static Material all_location1; private static Material all_location2; private static Material total_location1_group1; private static Material total_location1_group2; private static Material total_location2_group1; private static Material total_location2_group2; private static Material name1_location1_group1; private static Material name2_location1_group2; private static Material name1_location2_group1; private static Material name2_location2_group2; /* private static Material location_location1_group1; private static Material location_location1_group2; private static Material location_location2_group1; private static Material location_location2_group2; */ private static final String NAME_1 = "NAME_1"; private static final String NAME_2 = "NAME_2"; private static final String NAME_3 = "NAME_3"; private static final String NAME_4 = "NAME_4"; private static final String GROUP_1 = "GROUP_1"; private static final String GROUP_2 = "GROUP_2"; private static final String LOCATION_1 = "LOCATION_1"; private static final String LOCATION_2 = "LOCATION_2"; private static final List ALL = new ArrayList(); public JMenuInfoTest() { } @BeforeClass public static void setUpClass() throws Exception { TestUtil.setLoggingLevel(Level.OFF); summaryAll = new Material(Material.MaterialType.SUMMARY_ALL, null, TabsMaterials.get().summary(), "", ""); summaryAll.updateValue(1, 400); ALL.add(summaryAll); summaryTotal_group1 = new Material(Material.MaterialType.SUMMARY_TOTAL, null, TabsMaterials.get().summary(), "", GROUP_1); summaryTotal_group1.updateValue(1, 200); ALL.add(summaryTotal_group1); summaryTotal_group2 = new Material(Material.MaterialType.SUMMARY_TOTAL, null, TabsMaterials.get().summary(), "", GROUP_2); summaryTotal_group2.updateValue(1, 200); ALL.add(summaryTotal_group2); summary_group1 = new Material(Material.MaterialType.SUMMARY, null, TabsMaterials.get().summary(), GROUP_1, NAME_1); summary_group1.updateValue(1, 200); ALL.add(summary_group1); summary_group2 = new Material(Material.MaterialType.SUMMARY, null, TabsMaterials.get().summary(), GROUP_2, NAME_2); summary_group2.updateValue(1, 200); ALL.add(summary_group2); all_location1 = new Material(Material.MaterialType.LOCATIONS_ALL, null, LOCATION_1, "", ""); all_location1.updateValue(1, 200); ALL.add(all_location1); all_location2 = new Material(Material.MaterialType.LOCATIONS_ALL, null, LOCATION_2, "", ""); all_location2.updateValue(1, 200); ALL.add(all_location2); total_location1_group1 = new Material(Material.MaterialType.LOCATIONS_TOTAL, null, LOCATION_1, "", GROUP_1); total_location1_group1.updateValue(1, 100); ALL.add(total_location1_group1); total_location1_group2 = new Material(Material.MaterialType.LOCATIONS_TOTAL, null, LOCATION_1, "", GROUP_2); total_location1_group2.updateValue(1, 100); ALL.add(total_location1_group2); total_location2_group1 = new Material(Material.MaterialType.LOCATIONS_TOTAL, null, LOCATION_2, "", GROUP_1); total_location2_group1.updateValue(1, 100); ALL.add(total_location2_group1); total_location2_group2 = new Material(Material.MaterialType.LOCATIONS_TOTAL, null, LOCATION_2, "", GROUP_2); total_location2_group2.updateValue(1, 100); ALL.add(total_location2_group2); name1_location1_group1 = new Material(Material.MaterialType.LOCATIONS, null, LOCATION_1, GROUP_1, NAME_1); name1_location1_group1.updateValue(1, 100); ALL.add(name1_location1_group1); name2_location1_group2 = new Material(Material.MaterialType.LOCATIONS, null, LOCATION_1, GROUP_2, NAME_2); name2_location1_group2.updateValue(1, 100); ALL.add(name2_location1_group2); name1_location2_group1 = new Material(Material.MaterialType.LOCATIONS, null, LOCATION_2, GROUP_1, NAME_1); name1_location2_group1.updateValue(1, 100); ALL.add(name1_location2_group1); name2_location2_group2 = new Material(Material.MaterialType.LOCATIONS, null, LOCATION_2, GROUP_2, NAME_2); name2_location2_group2.updateValue(1, 100); ALL.add(name2_location2_group2); } @AfterClass public static void tearDownClass() throws Exception { TestUtil.setLoggingLevel(Level.INFO); } @Before public void setUp() { } @After public void tearDown() { } /** * Test of calcMaterialTotal method, of class JMenuInfo. */ @Test public void testCalcMaterialTotal() { List selected; MaterialTotal result; selected = new ArrayList(); selected.add(summaryAll); selected.add(summaryTotal_group1); selected.add(summaryTotal_group2); selected.add(summary_group1); selected.add(summary_group2); selected.add(all_location1); selected.add(all_location2); selected.add(total_location1_group1); selected.add(total_location1_group2); selected.add(total_location2_group1); selected.add(total_location2_group2); selected.add(name1_location1_group1); selected.add(name2_location1_group2); selected.add(name1_location2_group1); selected.add(name2_location2_group2); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(400, result.getTotalValue(), 0); EventList materialEventList = new BasicEventList(); materialEventList.add(summaryAll); materialEventList.add(summaryTotal_group1); materialEventList.add(summaryTotal_group2); materialEventList.add(summary_group1); materialEventList.add(summary_group2); materialEventList.add(all_location1); materialEventList.add(all_location2); materialEventList.add(total_location1_group1); materialEventList.add(total_location1_group2); materialEventList.add(total_location2_group1); materialEventList.add(total_location2_group2); materialEventList.add(name1_location1_group1); materialEventList.add(name2_location1_group2); materialEventList.add(name1_location2_group1); materialEventList.add(name2_location2_group2); SeparatorList separatorList = new SeparatorList(materialEventList, new MaterialSeparatorComparator(), 1, Integer.MAX_VALUE); result = JMenuInfo.calcMaterialTotal(separatorList, ALL); assertEquals(400, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summaryTotal_group1); selected.add(summaryTotal_group2); selected.add(summary_group1); selected.add(summary_group2); selected.add(all_location1); selected.add(all_location2); selected.add(total_location1_group1); selected.add(total_location1_group2); selected.add(total_location2_group1); selected.add(total_location2_group2); selected.add(name1_location1_group1); selected.add(name2_location1_group2); selected.add(name1_location2_group1); selected.add(name2_location2_group2); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(400, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summary_group1); selected.add(summary_group2); selected.add(all_location1); selected.add(all_location2); selected.add(total_location1_group1); selected.add(total_location1_group2); selected.add(total_location2_group1); selected.add(total_location2_group2); selected.add(name1_location1_group1); selected.add(name2_location1_group2); selected.add(name1_location2_group1); selected.add(name2_location2_group2); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(400, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(all_location1); selected.add(all_location2); selected.add(total_location1_group1); selected.add(total_location1_group2); selected.add(total_location2_group1); selected.add(total_location2_group2); selected.add(name1_location1_group1); selected.add(name2_location1_group2); selected.add(name1_location2_group1); selected.add(name2_location2_group2); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(400, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(total_location1_group1); selected.add(total_location1_group2); selected.add(total_location2_group1); selected.add(total_location2_group2); selected.add(name1_location1_group1); selected.add(name2_location1_group2); selected.add(name1_location2_group1); selected.add(name2_location2_group2); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(400, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(name1_location1_group1); selected.add(name2_location1_group2); selected.add(name1_location2_group1); selected.add(name2_location2_group2); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(400, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summary_group1); selected.add(all_location1); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(300, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summaryTotal_group1); selected.add(all_location1); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(300, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summary_group1); selected.add(total_location1_group1); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(200, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summary_group1); selected.add(total_location1_group2); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(300, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summaryTotal_group1); selected.add(total_location1_group2); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(300, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summary_group1); selected.add(name1_location1_group1); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(200, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summary_group1); selected.add(name2_location1_group2); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(300, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summary_group1); selected.add(name1_location2_group1); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(200, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summary_group1); selected.add(name2_location2_group2); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(300, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summaryTotal_group1); selected.add(name1_location1_group1); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(200, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summaryTotal_group1); selected.add(name2_location1_group2); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(300, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summaryTotal_group1); selected.add(name1_location2_group1); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(200, result.getTotalValue(), 0); selected = new ArrayList(); selected.add(summaryTotal_group1); selected.add(name2_location2_group2); result = JMenuInfo.calcMaterialTotal(selected, ALL); assertEquals(300, result.getTotalValue(), 0); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/shared/menu/JMenuLookupOnlineTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.shared.menu; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Set; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuLookup.LookupLinks; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.junit.Test; public class JMenuLookupOnlineTest extends TestUtil { @Test public void testLookup() { MenuData menuData = new MenuData<>(); menuData.getSystemLocations().add(ApiIdConverter.getLocation(30003392)); menuData.getRegionLocations().add(ApiIdConverter.getLocation(10000042)); menuData.getConstellationLocations().add(ApiIdConverter.getLocation(20000001)); //San Matar menuData.getStationNames().add("Eygfe VII - Moon 19 - Minmatar Mining Corporation Refinery"); menuData.getPlanetNames().add("Balle III"); menuData.getSystemNames().add("Eygfe"); menuData.getRegionNames().add("Metropolis"); menuData.getMarketTypeIDs().add(10679); menuData.getItemCounts().put(ApiIdConverter.getItem(10679), 1L); menuData.getTypeIDs().add(10679); menuData.getBlueprintTypeIDs().add(10679); menuData.getInventionTypeIDs().add(10679); menuData.getCorporationIDs().add(1000055); menuData.getCorporationNames().add("Minmatar Mining Corporation"); List lookups = new ArrayList<>(); for (LookupLinks lookupLinks : LookupLinks.values()) { if (lookupLinks == LookupLinks.ZKILLBOARD_ITEM || lookupLinks == LookupLinks.ZKILLBOARD_SYSTEM || lookupLinks == LookupLinks.ZKILLBOARD_CONSTELLATION || lookupLinks == LookupLinks.ZKILLBOARD_REGION || lookupLinks == LookupLinks.EVECONOMY ) { continue; //Protected by cloudflare } if (lookupLinks == LookupLinks.EVEMISSIONEER_SYSTEM || lookupLinks == LookupLinks.EVEMISSIONEER_CONSTELLATION || lookupLinks == LookupLinks.EVEMISSIONEER_REGION || lookupLinks == LookupLinks.EVEMISSIONEER_CORPORATION ) { continue; //Returns http code 429 } Set links = lookupLinks.getLinks(menuData); assertNotNull(lookupLinks.name() + " is null", links); Boolean enabled = lookupLinks.isEnabled(menuData); if (lookupLinks != LookupLinks.EVEMAPS_DOTLAN_OVERVIEW_GROUP && lookupLinks != LookupLinks.ZKILLBOARD_OVERVIEW_GROUP ) { assertFalse(lookupLinks.name() + " links are empty", links.isEmpty()); assertNotNull(lookupLinks.name() + " enabled is null", enabled); assertTrue(lookupLinks.name() + " enabled is false", enabled); } else { assertTrue(lookupLinks.name() + " enabled is not null", enabled == null); } for (String link : links) { lookups.add(new Lookup(lookupLinks, link)); } } for (Lookup lookup : lookups) { lookup.start(); } for (Lookup lookup : lookups) { try { lookup.join(); assertEquals(lookup.lookupLinks.name() + " returned " + lookup.code + " for " + lookup.link, HttpURLConnection.HTTP_OK, lookup.code); } catch (InterruptedException ex) { fail(ex.getMessage()); } } } private static class Lookup extends Thread { private final LookupLinks lookupLinks; private final String link; private int code = -1; public Lookup(LookupLinks lookupLinks, String link) { this.lookupLinks = lookupLinks; this.link = link; } @Override public void run() { HttpURLConnection connection = null; try { URL url = new URL(link); connection = (HttpURLConnection)url.openConnection(); connection.setRequestMethod("GET"); connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0"); connection.setInstanceFollowRedirects(false); connection.connect(); code = connection.getResponseCode(); } catch (IOException ex) { fail(lookupLinks.name() + " failed with " + ex.getMessage() + " for " + link); } finally { if (connection != null) { connection.disconnect(); } } } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/sounds/SoundsTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.sounds; import java.io.File; import java.net.URISyntaxException; import net.nikr.eve.jeveasset.TestUtil; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.junit.Test; public class SoundsTest extends TestUtil { @Test public void testExists() { for (DefaultSound i : DefaultSound.values()) { try { File file = new File(DefaultSound.class.getResource(i.getFilename()).toURI()); assertTrue(i.getFilename() + " not found", file.exists()); } catch (URISyntaxException ex) { fail(ex.getMessage()); } } } @Test public void testUnused() { try { File dir = new File(DefaultSound.class.getResource("DefaultSound.class").toURI()).getParentFile(); for (String filename : dir.list()) { if (filename.endsWith(".class")) { continue; } boolean ok = false; //Images Class for (DefaultSound i : DefaultSound.values()) { if (filename.equals(i.getFilename())) { ok = true; break; } } assertTrue(filename + " is not used anywhere", ok); } } catch (URISyntaxException ex) { fail("Directory not found"); } } @Test public void testFilenames() { for (DefaultSound i : DefaultSound.values()) { String properFilename = i.name().toLowerCase() + ".mp3"; if (!i.getFilename().isEmpty() && !properFilename.equals(i.getFilename())) { fail(i.toString() + " filename should be " + properFilename + " but is " + i.getFilename()); } } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/tabs/TableFormatTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs; import ca.odell.glazedlists.GlazedLists; import java.awt.Color; import java.awt.Component; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import javax.swing.JComponent; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.api.raw.RawNpcStanding.FromType; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.ReprocessedMaterial; import net.nikr.eve.jeveasset.data.settings.PriceData; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.dialogs.account.AccountTableFormat; import net.nikr.eve.jeveasset.gui.dialogs.settings.ColorsTableFormat; import net.nikr.eve.jeveasset.gui.shared.StringComparators; import net.nikr.eve.jeveasset.gui.shared.filter.Filter.AllColumn; import net.nikr.eve.jeveasset.gui.shared.filter.FilterMatcherTest.TestEnum; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager.FormulaColumn; import net.nikr.eve.jeveasset.gui.shared.table.ColumnManager.JumpColumn; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.containers.ISK; import net.nikr.eve.jeveasset.gui.shared.table.containers.ModulePriceValue; import net.nikr.eve.jeveasset.gui.tabs.agents.AgentsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetTableFormat; import net.nikr.eve.jeveasset.gui.tabs.contracts.ContractsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.items.ItemTableFormat; import net.nikr.eve.jeveasset.gui.tabs.jobs.IndustryJobTableFormat; import net.nikr.eve.jeveasset.gui.tabs.journal.JournalTableFormat; import net.nikr.eve.jeveasset.gui.tabs.loadout.Loadout; import net.nikr.eve.jeveasset.gui.tabs.loadout.LoadoutExtendedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.loadout.LoadoutTableFormat; import net.nikr.eve.jeveasset.gui.tabs.loyalty.LoyaltyPointsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.materials.Material; import net.nikr.eve.jeveasset.gui.tabs.materials.MaterialExtendedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.materials.MaterialTableFormat; import net.nikr.eve.jeveasset.gui.tabs.mining.ExtractionsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.mining.MiningTableFormat; import net.nikr.eve.jeveasset.gui.tabs.orders.MarketTableFormat; import net.nikr.eve.jeveasset.gui.tabs.overview.Overview; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTableFormat; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceChangesTab.PriceChange; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceChangesTableFormat; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedExtendedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedInterface; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedItem; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedTotal; import net.nikr.eve.jeveasset.gui.tabs.skills.SkillsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.slots.SlotsTableFormat; import net.nikr.eve.jeveasset.gui.tabs.standing.NpcStandingTableFormat; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileExtendedTableFormat; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileTableFormat; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerSkillPointsFilterTableFormat; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTableFormat; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeAsset; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTableFormat; import net.nikr.eve.jeveasset.gui.tabs.values.Value; import net.nikr.eve.jeveasset.gui.tabs.values.ValueTableFormat; import net.nikr.eve.jeveasset.io.shared.ConverterTestOptions; import net.nikr.eve.jeveasset.io.shared.ConverterTestOptionsGetter; import net.nikr.eve.jeveasset.io.shared.ConverterTestUtil; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.junit.Test; public class TableFormatTest extends TestUtil { private static final Boolean BOOLEAN_VALUE = true; private static final String STRING_VALUE = "A String"; private static final Integer INTEGER_VALUE = 5; private static final Long LONG_VALUE = 5L; private static final Float FLOAT_VALUE = 5.1f; private static final Double DOUBLE_VALUE = 5.1; private static final Date DATE_VALUE = new Date(); @Test public void testTableFormatClass() { boolean setValues = true; boolean setNull = false; for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { //Shared Tags tags = new Tags(); EsiOwner owner = ConverterTestUtil.getEsiOwner(options); Item item = new Item(INTEGER_VALUE, STRING_VALUE, STRING_VALUE, STRING_VALUE, LONG_VALUE, FLOAT_VALUE, FLOAT_VALUE, FLOAT_VALUE, INTEGER_VALUE, STRING_VALUE, BOOLEAN_VALUE, INTEGER_VALUE, INTEGER_VALUE, INTEGER_VALUE, STRING_VALUE, STRING_VALUE, STRING_VALUE); MyLocation location = new MyLocation(LONG_VALUE, STRING_VALUE, LONG_VALUE, STRING_VALUE, LONG_VALUE, STRING_VALUE, LONG_VALUE, STRING_VALUE, STRING_VALUE); //Diaglogs //Options test(ColorsTableFormat.class); //Accounts test(AccountTableFormat.class); for (AccountTableFormat tableFormat : AccountTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(owner)); } //Primary Tools //Asset test(AssetTableFormat.class); MyAsset asset = ConverterTestUtil.getMyAsset(owner, setNull, setValues, options); for (AssetTableFormat tableFormat : AssetTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(asset)); } //Contract test(ContractsTableFormat.class); MyContract saveMyContract = ConverterTestUtil.getMyContract(setNull, setValues, options); MyContractItem saveMyContractItem = ConverterTestUtil.getMyContractItem(saveMyContract, setNull, setValues, options); for (ContractsTableFormat tableFormat : ContractsTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(saveMyContractItem)); } //Journal test(JournalTableFormat.class); MyJournal saveMyJournal = ConverterTestUtil.getMyJournal(owner, setNull, setValues, options); for (JournalTableFormat tableFormat : JournalTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(saveMyJournal)); } //Market Order test(MarketTableFormat.class); MyMarketOrder saveMyMarketOrder = ConverterTestUtil.getMyMarketOrder(owner, setNull, setValues, options); for (MarketTableFormat tableFormat : MarketTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(saveMyMarketOrder)); } //Transaction test(TransactionTableFormat.class); MyTransaction saveMyTransaction = ConverterTestUtil.getMyTransaction(owner, setNull, setValues, options); for (TransactionTableFormat tableFormat : TransactionTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(saveMyTransaction)); } //Industry Job test(IndustryJobTableFormat.class); MyIndustryJob saveMyIndustryJob = ConverterTestUtil.getMyIndustryJob(owner, setNull, setValues, options); for (IndustryJobTableFormat tableFormat : IndustryJobTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(saveMyIndustryJob)); } //Skills test(SkillsTableFormat.class); //Loyalty Points test(LoyaltyPointsTableFormat.class); //NPC Standing test(NpcStandingTableFormat.class); //Agents test(AgentsTableFormat.class); //Mining test(MiningTableFormat.class); //Extractions test(ExtractionsTableFormat.class); //Secondary Tools //Slots test(SlotsTableFormat.class); //Item test(ItemTableFormat.class); for (ItemTableFormat tableFormat : ItemTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(item)); } //Loadout test(LoadoutTableFormat.class); test(LoadoutExtendedTableFormat.class); Loadout loadout = new Loadout(item, location, owner, STRING_VALUE, asset, STRING_VALUE, DOUBLE_VALUE, DOUBLE_VALUE, LONG_VALUE, BOOLEAN_VALUE); for (LoadoutTableFormat tableFormat : LoadoutTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(loadout)); } for (LoadoutExtendedTableFormat tableFormat : LoadoutExtendedTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(loadout)); } //Overview test(OverviewTableFormat.class); Overview overview = new Overview(STRING_VALUE, location, DOUBLE_VALUE, DOUBLE_VALUE, LONG_VALUE, DOUBLE_VALUE); for (OverviewTableFormat tableFormat : OverviewTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(overview)); } //Price Change test(PriceChangesTableFormat.class); PriceChange priceChange = new PriceChange(INTEGER_VALUE, item, LONG_VALUE); for (PriceChangesTableFormat tableFormat : PriceChangesTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(priceChange)); } //Reprocessed test(ReprocessedTableFormat.class); ReprocessedMaterial reprocessedMaterial = new ReprocessedMaterial(INTEGER_VALUE, INTEGER_VALUE, INTEGER_VALUE); ReprocessedTotal parent = new ReprocessedTotal(null, item, DOUBLE_VALUE, LONG_VALUE); ReprocessedInterface reprocessedItem = new ReprocessedItem(parent, item, reprocessedMaterial, BOOLEAN_VALUE, DOUBLE_VALUE); for (ReprocessedTableFormat tableFormat : ReprocessedTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(reprocessedItem)); } for (ReprocessedExtendedTableFormat tableFormat : ReprocessedExtendedTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(reprocessedItem)); } //StockpileItem test(StockpileTableFormat.class); test(StockpileExtendedTableFormat.class); Stockpile stockpile = new Stockpile(STRING_VALUE, null, new ArrayList<>(), DOUBLE_VALUE, BOOLEAN_VALUE); stockpile.setOwnerName(Collections.singletonList(owner.getOwnerName())); stockpile.setFlagName(Collections.singleton(asset.getItemFlag())); StockpileItem stockpileItem = new StockpileItem(stockpile, item, INTEGER_VALUE, DOUBLE_VALUE, BOOLEAN_VALUE); stockpileItem.setTags(tags); stockpileItem.updateValues(0, 0, DOUBLE_VALUE, PriceData.EMPTY); for (StockpileTableFormat tableFormat : StockpileTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(stockpileItem)); } for (StockpileExtendedTableFormat tableFormat : StockpileExtendedTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(stockpileItem)); } //Material test(MaterialTableFormat.class); test(MaterialExtendedTableFormat.class); Material material = new Material(Material.MaterialType.LOCATIONS, asset, STRING_VALUE, STRING_VALUE, STRING_VALUE); for (MaterialTableFormat tableFormat : MaterialTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(material)); } for (MaterialExtendedTableFormat tableFormat : MaterialExtendedTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(material)); } //Isk test(ValueTableFormat.class); Value value = new Value(STRING_VALUE, DATE_VALUE); for (int i = 1; i < 8; i++) { value.addBalance(String.valueOf(i), 0); } for (ValueTableFormat tableFormat : ValueTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(value)); } //Tracker test(TrackerSkillPointsFilterTableFormat.class); //Tree test(TreeTableFormat.class); TreeAsset treeAsset = new TreeAsset(asset, TreeAsset.TreeType.CATEGORY, new ArrayList<>(), STRING_VALUE, true); TreeAsset sub = new TreeAsset(asset, TreeAsset.TreeType.CATEGORY, Collections.singletonList(treeAsset), STRING_VALUE, false); treeAsset.addAsset(sub); treeAsset.updateParents(); sub.updateParents(); for (TreeTableFormat tableFormat : TreeTableFormat.values()) { test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(treeAsset)); test(tableFormat, tableFormat.getType(), tableFormat.getColumnValue(sub)); } //Tables testClass(FormulaColumn.class); testClass(JumpColumn.class); testClass(AllColumn.class); //Tests testClass(TestEnum.class); } } private void testClass(Class tableFormat) { try { assertTrue(tableFormat + " does not implement toString", tableFormat.getMethod("toString").getDeclaringClass() == tableFormat); } catch (NoSuchMethodException | SecurityException ex) { fail(ex.getMessage()); } } private & EnumTableColumn, Q> void test(Class tableFormat) { try { assertTrue(tableFormat + " does not implement toString", tableFormat.getMethod("toString").getDeclaringClass() == tableFormat); //Test Comparator for (EnumTableColumn enumColumn : tableFormat.getEnumConstants()) { Comparator comparator = enumColumn.getComparator(); Class type = enumColumn.getType(); assertNotNull(enumColumn.getClass().getName() + "." + enumColumn.name() + " -> is null", type); if (String.class.isAssignableFrom(type)) { assertEquals(StringComparators.TO_STRING, comparator); } else if (FromType.class.isAssignableFrom(type)) { assertEquals(MyNpcStanding.FROM_TYPE_COMPARATOR, comparator); } else if (Comparable.class.isAssignableFrom(type)) { assertEquals(GlazedLists.comparableComparator(), comparator); } else if (Component.class.isAssignableFrom(type) || ModulePriceValue.class.isAssignableFrom(type) || ISK.class.isAssignableFrom(type) || Color.class.isAssignableFrom(type) ) { assertEquals(null, comparator); } else { fail(enumColumn.getClass().getName() + "." + enumColumn.name() + " -> " + type.getName() + " is not comparable"); } } } catch (NoSuchMethodException | SecurityException ex) { fail(ex.getMessage()); } } private void test(EnumTableColumn enumColumn, Class expecteds, Object object) { assertNotNull(enumColumn.getClass().getSuperclass().getSimpleName() + "->" + enumColumn.name() + " was null", object); Class actual = object.getClass(); if ((actual.isAssignableFrom(Double.class) || actual.isAssignableFrom(Float.class)) && (expecteds.isAssignableFrom(Double.class) || expecteds.isAssignableFrom(Float.class))) { //No problem } else if ((actual.isAssignableFrom(Long.class) || actual.isAssignableFrom(Integer.class)) && (expecteds.isAssignableFrom(Long.class) || expecteds.isAssignableFrom(Integer.class))) { //No problem } else if (Number.class.isAssignableFrom(actual)) { fail("Column: " + enumColumn.name() + " Class: " + actual + " is an unsupported number type"); } else if (JComponent.class.isAssignableFrom(actual)) { //No problem } else if (String.class.isAssignableFrom(actual)) { //No problem } else if (String.class.isAssignableFrom(expecteds)) { try { if (actual.getSuperclass().isEnum()) { actual = actual.getSuperclass(); } Method method = actual.getMethod("toString"); assertTrue("Column: " + enumColumn.name() + " Class: " + actual + " does not implement toString: " + method.getDeclaringClass() , method.getDeclaringClass().equals(actual)); } catch (NoSuchMethodException ex) { fail("Column: " + enumColumn.name() + " Class: " + actual + " has no toString method"); } catch (SecurityException ex) { fail("Column: " + enumColumn.name() + " Class: " + actual + " has no toString method"); } } else if (!actual.isAssignableFrom(expecteds)) { fail(enumColumn.name() + "is not the right type"); } else { assertTrue(enumColumn.getClass().getSuperclass().getSimpleName() + "->" + enumColumn.name() + " expected: " + expecteds.getSimpleName() + " was: " + actual.getSimpleName(), expecteds.isAssignableFrom(actual)); try { assertTrue(actual + " does not implement hashCode", actual.getMethod("hashCode").getDeclaringClass() == actual); assertTrue(actual + " does not implement equals", actual.getMethod("equals").getDeclaringClass() == actual); assertTrue(actual + " does not implement compareTo", actual.getMethod("compareTo").getDeclaringClass() == actual); } catch (NoSuchMethodException | SecurityException ex) { //fail(ex.getMessage()); } } String text = JFormulaDialog.getHardName(enumColumn) + " * 100 / 90"; JFormulaDialog.replaceAll(enumColumn, text); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/tabs/assets/AssetAndTreeTableFormatTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.assets; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTableFormat; import static org.junit.Assert.*; import org.junit.Test; public class AssetAndTreeTableFormatTest extends TestUtil { @Test public void testColumns() { for (AssetTableFormat format : AssetTableFormat.values()) { try { TreeTableFormat.valueOf(format.name()); } catch (IllegalArgumentException es) { fail(format.name() + " is missing from TreeTableFormat"); } } for (TreeTableFormat format : TreeTableFormat.values()) { try { AssetTableFormat.valueOf(format.name()); } catch (IllegalArgumentException es) { fail(format.name() + " is missing from AssetTableFormat"); } } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/tabs/orders/MarketOrdersTabTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.orders; import net.nikr.eve.jeveasset.TestUtil; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import org.junit.Test; public class MarketOrdersTabTest extends TestUtil { public MarketOrdersTabTest() { } @Test public void testSignificantIncrement() { assertThat(MarketOrdersTab.significantIncrement(0.00), equalTo(0.00)); assertThat(MarketOrdersTab.significantIncrement(0.01), equalTo(0.02)); assertThat(MarketOrdersTab.significantIncrement(0.1), equalTo(0.11)); assertThat(MarketOrdersTab.significantIncrement(1), equalTo(1.01)); assertThat(MarketOrdersTab.significantIncrement(10), equalTo(10.01)); assertThat(MarketOrdersTab.significantIncrement(100), equalTo(100.10)); assertThat(MarketOrdersTab.significantIncrement(1000), equalTo(1001.00)); assertThat(MarketOrdersTab.significantIncrement(10000), equalTo(10010.00)); assertThat(MarketOrdersTab.significantIncrement(1001), equalTo(1002.00)); assertThat(MarketOrdersTab.significantIncrement(10010), equalTo(10020.00)); assertThat(MarketOrdersTab.significantIncrement(0.99), equalTo(1.00)); assertThat(MarketOrdersTab.significantIncrement(9.99), equalTo(10.00)); assertThat(MarketOrdersTab.significantIncrement(99.99), equalTo(100.00)); assertThat(MarketOrdersTab.significantIncrement(999.90), equalTo(1000.00)); assertThat(MarketOrdersTab.significantIncrement(9999), equalTo(10000.00)); assertThat(MarketOrdersTab.significantIncrement(99990), equalTo(100000.00)); assertThat(MarketOrdersTab.significantIncrement(2), equalTo(2.01)); assertThat(MarketOrdersTab.significantIncrement(20), equalTo(20.01)); assertThat(MarketOrdersTab.significantIncrement(200), equalTo(200.10)); assertThat(MarketOrdersTab.significantIncrement(2000), equalTo(2001.00)); assertThat(MarketOrdersTab.significantIncrement(20000), equalTo(20010.0)); } @Test public void testsignificantDecrement() { assertThat(MarketOrdersTab.significantDecrement(0.00), equalTo(0.00)); assertThat(MarketOrdersTab.significantDecrement(0.01), equalTo(0.01)); assertThat(MarketOrdersTab.significantDecrement(0.1), equalTo(0.09)); assertThat(MarketOrdersTab.significantDecrement(1), equalTo(0.99)); assertThat(MarketOrdersTab.significantDecrement(10), equalTo(9.99)); assertThat(MarketOrdersTab.significantDecrement(100), equalTo(99.99)); assertThat(MarketOrdersTab.significantDecrement(1000), equalTo(999.90)); assertThat(MarketOrdersTab.significantDecrement(10000), equalTo(9999.00)); assertThat(MarketOrdersTab.significantDecrement(1001), equalTo(1000.00)); assertThat(MarketOrdersTab.significantDecrement(10010), equalTo(10000.00)); assertThat(MarketOrdersTab.significantDecrement(0.99), equalTo(0.98)); assertThat(MarketOrdersTab.significantDecrement(9.99), equalTo(9.98)); assertThat(MarketOrdersTab.significantDecrement(99.99), equalTo(99.98)); assertThat(MarketOrdersTab.significantDecrement(999.90), equalTo(999.80)); assertThat(MarketOrdersTab.significantDecrement(9999), equalTo(9998.0)); assertThat(MarketOrdersTab.significantDecrement(99990), equalTo(99980.0)); assertThat(MarketOrdersTab.significantDecrement(2), equalTo(1.99)); assertThat(MarketOrdersTab.significantDecrement(20), equalTo(19.99)); assertThat(MarketOrdersTab.significantDecrement(200), equalTo(199.90)); assertThat(MarketOrdersTab.significantDecrement(2000), equalTo(1999.00)); assertThat(MarketOrdersTab.significantDecrement(20000), equalTo(19990.0)); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/tabs/routing/TestEditableModel.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.routing; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import net.nikr.eve.jeveasset.TestUtil; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import org.junit.Before; import org.junit.Test; /** * * @author Candle */ public class TestEditableModel extends TestUtil { private Comparator comp; private List contents; @Before public void setup() { comp = new Comparator() { @Override public int compare(final ListContents o1, final ListContents o2) { return o1.getName().compareToIgnoreCase(o2.getName()); } }; contents = new ArrayList(); contents.add(new ListContents("abc")); contents.add(new ListContents("abcd")); contents.add(new ListContents("tgv")); contents.add(new ListContents("123")); contents.add(new ListContents("gt")); contents.add(new ListContents("lt")); } @Test public void testCreate() { EditableListModel elm = new EditableListModel(contents, comp); assertNotSame("contents should be a different object (unmodifiable list)", contents, elm.getAll()); assertSame("The comparator should be the same", comp, elm.getSortComparator()); } class ListContents { private final String name; public ListContents(final String name) { this.name = name; } public String getName() { return name; } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/tabs/routing/TestMoveJList.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.routing; import java.util.Arrays; import java.util.Comparator; import net.nikr.eve.jeveasset.TestUtil; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; /** * * @author Candle */ public class TestMoveJList extends TestUtil { private MoveJList a; private MoveJList b; private Something[] somethings; @Before public void setup() { Comparator comp = new Comparator() { @Override public int compare(final Something o1, final Something o2) { return o1.getName().compareToIgnoreCase(o2.getName()); } }; somethings = new Something[] {new Something("foo"), new Something("foobar"), new Something("zap") }; EditableListModel editableListModel = new EditableListModel(Arrays.asList(somethings)); a = new MoveJList(editableListModel); a.getEditableModel().setSortComparator(comp); b = new MoveJList(); b.getEditableModel().setSortComparator(comp); } @Test public void testMove() { a.setSelectedIndices(new int[] {1}); a.move(b, 10); assertEquals(2, a.getEditableModel().getSize()); assertEquals(somethings[1], b.getEditableModel().getElementAt(0)); } @Test public void testMoveAndMoveAgain() { a.setSelectedIndices(new int[] {1}); a.move(b, 10); assertEquals(2, a.getEditableModel().getSize()); assertEquals(somethings[1], b.getEditableModel().getElementAt(0)); b.setSelectedIndices(new int[] {0}); b.move(a, 10); assertEquals(3, a.getEditableModel().getSize()); assertEquals(0, b.getEditableModel().getSize()); } @Test public void testMoveAllAndMoveBack() { a.setSelectedIndices(new int[] {0, 1, 2}); a.move(b, 10); assertEquals(0, a.getEditableModel().getSize()); assertEquals(3, b.getEditableModel().getSize()); b.setSelectedIndices(new int[] {0, 1, 2}); b.move(a, 10); assertEquals(3, a.getEditableModel().getSize()); assertEquals(0, b.getEditableModel().getSize()); } class Something { String name; public Something(String name) { this.name = name; } public String getName() { return name; } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/tabs/routing/TestRouting.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.routing; import ch.qos.logback.classic.Level; import java.util.ArrayList; import java.util.List; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.gui.tabs.routing.mocks.FakeRoutingTab; import net.nikr.eve.jeveasset.gui.tabs.routing.mocks.RoutingMockProgram; import net.nikr.eve.jeveasset.tests.mocks.FakeProgress; import org.junit.AfterClass; import static org.junit.Assert.assertEquals; import org.junit.BeforeClass; import org.junit.Test; import uk.me.candle.eve.routing.BruteForce; import uk.me.candle.eve.routing.Crossover; import uk.me.candle.eve.routing.CrossoverHibrid2opt; import uk.me.candle.eve.routing.NearestNeighbour; import uk.me.candle.eve.routing.NearestNeighbourIteration; import uk.me.candle.eve.routing.RoutingAlgorithm; import uk.me.candle.eve.routing.SimpleUnisexMutator; import uk.me.candle.eve.routing.SimpleUnisexMutatorHibrid2Opt; /** * * @author Candle */ public class TestRouting extends TestUtil { @BeforeClass public static void setUpClass() throws Exception { setLoggingLevel(Level.OFF); } @AfterClass public static void tearDownClass() throws Exception { setLoggingLevel(Level.INFO); } private List getErentaList() { /* * Erenta * Haajinen * Kakakela * Kiskoken * Oipo * Torrinos * Umokka */ List waypointNames = new ArrayList<>(); waypointNames.add("Erenta"); waypointNames.add("Haajinen"); waypointNames.add("Kakakela"); waypointNames.add("Kiskoken"); waypointNames.add("Oipo"); waypointNames.add("Torrinos"); waypointNames.add("Umokka"); return waypointNames; } @Test public void testErentaBruteForce() { testRoute(getErentaList(), new BruteForce<>(), 40); } @Test public void testErentaCrossover() { testRoute(getErentaList(), new Crossover<>(), 40); } @Test public void testErentaCrossoverHibrid2opt() { testRoute(getErentaList(), new CrossoverHibrid2opt<>(), 40); } @Test public void testErentaNearestNeighbour() { testRoute(getErentaList(), new NearestNeighbour<>(), 42); } @Test public void testErentaNearestNeighbourIteration() { testRoute(getErentaList(), new NearestNeighbourIteration<>(), 40); } @Test public void testErentaSimpleUnisexMutator() { testRoute(getErentaList(), new SimpleUnisexMutator<>(), 40); } @Test public void testErentaSimpleUnisexMutatorHibrid2Opt() { testRoute(getErentaList(), new SimpleUnisexMutatorHibrid2Opt<>(), 40); } private void testRoute(final List waypointNames, final RoutingAlgorithm ra, final int exptectedDistance) { FakeRoutingTab frd = new FakeRoutingTab(new RoutingMockProgram()); frd.buildTestGraph(); List initial = frd.getNodesFromNames(waypointNames); List route = ra.execute(new FakeProgress(), frd.getGraph(), new ArrayList<>(initial)); System.out.println("--- " + ra.getName() + " ---"); for (int i = 0; i < initial.size(); ++i) { System.out.println(i + " " + initial.get(i)); } SolarSystem last = null; int totalDistance = 0; for (SolarSystem current : route) { if (last != null) { totalDistance = totalDistance + frd.getGraph().distanceBetween(last, current); } last = current; } if (last != null) { totalDistance = totalDistance + frd.getGraph().distanceBetween(last, route.get(0)); } short[][] distances = ra.getLastDistanceMatrix(); for (int i = 0; i < distances.length; ++i) { System.out.print("" + i + ":"); for (int j = 0; j < distances[i].length && j <= i; ++j) { String id = "" + distances[i][j]; switch (id.length()) { // HAAAAAX. case 1: id = " " + id; break; case 2: id = " " + id; break; case 3: id = "" + id; break; } System.out.print(" " + id); } System.out.println(); } for (SolarSystem n : route) { System.out.println(n + "(" + initial.indexOf(n) + ")"); } System.out.println("Length: " + totalDistance + " or " + ra.getLastDistance()); assertEquals("Not the same stating system", route.get(0), initial.get(0)); assertEquals("totalDistance != exptectedDistance", exptectedDistance, totalDistance); assertEquals("totalDistance != LastDistance", totalDistance, ra.getLastDistance()); } @Test public void testArtisineBruteForce() { testRoute(getArtisineList(), new BruteForce<>(), 61); } @Test public void testArtisineCrossover() { testRoute(getArtisineList(), new Crossover<>(), 61); } @Test public void testArtisineCrossoverHibrid2opt() { testRoute(getArtisineList(), new CrossoverHibrid2opt<>(), 61); } @Test public void testArtisineNearestNeighbour() { testRoute(getArtisineList(), new NearestNeighbour<>(), 63); } @Test public void testArtisineNearestNeighbourIteration() { testRoute(getArtisineList(), new NearestNeighbourIteration<>(), 61); } @Test public void testArtisineSimpleUnisexMutator() { testRoute(getArtisineList(), new SimpleUnisexMutator<>(), 61); } @Test public void testArtisineSimpleUnisexMutatorHibrid2Opt() { testRoute(getArtisineList(), new SimpleUnisexMutatorHibrid2Opt<>(), 61); } private List getArtisineList() { /* * Artisine * Deltole * Jolia * Doussivitte * Misneden * Bawilan * Ney * Stegette * Odette * Inghenges * Sileperer */ List waypointNames = new ArrayList<>(); waypointNames.add("Artisine"); waypointNames.add("Deltole"); waypointNames.add("Jolia"); waypointNames.add("Doussivitte"); waypointNames.add("Misneden"); waypointNames.add("Bawilan"); waypointNames.add("Ney"); waypointNames.add("Stegette"); waypointNames.add("Odette"); waypointNames.add("Inghenges"); waypointNames.add("Sileperer"); return waypointNames; } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/tabs/routing/mocks/FakeRoutingTab.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.routing.mocks; import java.util.ArrayList; import java.util.List; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.gui.tabs.routing.RoutingTab; import net.nikr.eve.jeveasset.gui.tabs.routing.SolarSystem; import uk.me.candle.eve.graph.Graph; /** * * @author Candle */ public class FakeRoutingTab extends RoutingTab { public FakeRoutingTab(final Program program) { super(false); this.program = program; } public void buildTestGraph() { super.buildGraph(true); } public List getNodesFromNames(final List names) { List nodes = new ArrayList<>(); for (String name : names) { SolarSystem nn = null; for (SolarSystem n : filteredGraph.getNodes()) { if (n.getName().equals(name)) { nn = n; break; } } if (nn == null) { throw new RuntimeException("Failed to find the node for name: " + name); } nodes.add(nn); } return nodes; } @Override public Graph getGraph() { return filteredGraph; } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/tabs/routing/mocks/RoutingMockProgram.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.routing.mocks; import net.nikr.eve.jeveasset.tests.mocks.FakeProgram; /** * * @author Candle */ public class RoutingMockProgram extends FakeProgram { public RoutingMockProgram() { } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/tabs/stockpile/StockpileTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.stockpile; import java.util.Collections; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileContainer; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileFlag; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileItem; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileTotal; import static org.junit.Assert.*; import org.junit.Test; public class StockpileTest extends TestUtil { @Test public void testSomeMethod() { StockpileFilter filter = new StockpileFilter(MyLocation.create(0), false, //Exclude Collections.singletonList(new StockpileFlag(0, true)), Collections.singletonList(new StockpileContainer("Container", false)), Collections.singletonList(0L), null, //JobsDaysLess null, //JobsDaysMore true, true, true, true, true, true, true, true, true, true, true); Stockpile stockpile = new Stockpile("Name", null, Collections.singletonList(filter), 1, false); StockpileItem item1 = new StockpileItem(stockpile, new Item(0), 0, 0, false); StockpileItem item2 = new StockpileItem(stockpile, new Item(0), 0, 0, false); StockpileTotal total1 = new StockpileTotal(stockpile); StockpileTotal total2 = new StockpileTotal(stockpile); assertEquals(item1.compareTo(item2), item2.compareTo(item2), 0); assertEquals(total1.compareTo(total2), total2.compareTo(total1), 0); assertEquals(0, total1.compareTo(total2), 0); assertEquals(0, item1.compareTo(item2), 0); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/gui/tabs/values/DataSetCreatorTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.values; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.raw.RawContract; import net.nikr.eve.jeveasset.data.api.raw.RawContract.ContractStatus; import net.nikr.eve.jeveasset.data.api.raw.RawContract.ContractType; import net.nikr.eve.jeveasset.data.api.raw.RawContractItem; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import org.junit.Test; public class DataSetCreatorTest extends TestUtil { private static enum AssetDate { UPDATED, NOT_UPDATED } private static enum BalanceDate { UPDATED, NOT_UPDATED } private static enum Included { TRUE, FALSE, BOTH } private static enum Completed { TRUE, FALSE, BOTH } private static final double NONE = 0; private static final double COLLATERAL = 100; private static final double PRICE = 1000; private static final double REWARD = 10000; private static final double ITEM = 100000; private static final long ISSUER_ID = 1; private static final long ISSUER_CORPORATION_ID = 2; private static final long ACCEPTOR_ID = 3; private static final long ACCEPTOR_CORPORATION_ID = 4; private final Date now = new Date(); private final Date before = getBefore(); private final Date after = getAfter(); private final DataSetCreatorTester creator = new DataSetCreatorTester(); @Test public void testContract() { List matchs = new ArrayList<>(); //Contract Collateral (Courier) //issuer matchs.add(new TestMatch(1, issuer(AssetDate.UPDATED, null), acceptor(null, null), Included.BOTH, Completed.BOTH, COLLATERAL, NONE, contractType(ContractType.COURIER), contractStatus(ContractStatus.IN_PROGRESS, ContractStatus.OUTSTANDING), contractStatus())); matchs.add(new TestMatch(1, issuer(AssetDate.NOT_UPDATED, null), acceptor(null, null), Included.BOTH, Completed.TRUE, COLLATERAL, NONE, contractType(ContractType.COURIER), contractStatus(), contractStatus())); //acceptor matchs.add(new TestMatch(2, issuer(null, null), acceptor(null, BalanceDate.UPDATED), Included.BOTH, Completed.BOTH, COLLATERAL, NONE, contractType(ContractType.COURIER), contractStatus(ContractStatus.IN_PROGRESS), contractStatus())); //Contract ISK //issuer matchs.add(new TestMatch(3, issuer(null, BalanceDate.UPDATED), acceptor(null, null), Included.BOTH, Completed.BOTH, NONE, REWARD, contractType(), contractStatus(ContractStatus.OUTSTANDING), contractStatus())); matchs.add(new TestMatch(3, issuer(null, BalanceDate.NOT_UPDATED), acceptor(null, null), Included.BOTH, Completed.TRUE, NONE, (PRICE-REWARD), contractType(), contractStatus(), contractStatus(ContractStatus.OUTSTANDING))); //acceptor matchs.add(new TestMatch(4, issuer(null, null), acceptor(null, BalanceDate.NOT_UPDATED), Included.BOTH, Completed.TRUE, NONE, (REWARD + -PRICE), contractType(), contractStatus(), contractStatus())); //Contract Items //issuer matchs.add(new TestMatch(5, issuer(AssetDate.UPDATED, null), acceptor(null, null), Included.TRUE, Completed.BOTH, NONE, ITEM, contractType(ContractType.AUCTION, ContractType.ITEM_EXCHANGE), contractStatus(ContractStatus.OUTSTANDING), contractStatus())); matchs.add(new TestMatch(5, issuer(AssetDate.NOT_UPDATED, null), acceptor(null, null), Included.TRUE, Completed.TRUE, NONE, -ITEM, contractType(ContractType.AUCTION, ContractType.ITEM_EXCHANGE), contractStatus(), contractStatus(ContractStatus.OUTSTANDING))); matchs.add(new TestMatch(5, issuer(AssetDate.NOT_UPDATED, null), acceptor(null, null), Included.FALSE, Completed.TRUE, NONE, ITEM, contractType(ContractType.AUCTION, ContractType.ITEM_EXCHANGE), contractStatus(), contractStatus(ContractStatus.OUTSTANDING))); //acceptor matchs.add(new TestMatch(6, issuer(null, null), acceptor(AssetDate.NOT_UPDATED, null), Included.TRUE, Completed.TRUE, NONE, ITEM, contractType(ContractType.AUCTION, ContractType.ITEM_EXCHANGE), contractStatus(), contractStatus())); matchs.add(new TestMatch(6, issuer(null, null), acceptor(AssetDate.NOT_UPDATED, null), Included.FALSE, Completed.TRUE, NONE, -ITEM, contractType(ContractType.AUCTION, ContractType.ITEM_EXCHANGE), contractStatus(), contractStatus())); boolean[] includedValues = {true, false}; boolean[] completedValues = {true, false}; int iteration = 0; for (ContractStatus status : ContractStatus.values()) { for (ContractType type : ContractType.values()) { for (AssetDate issuerAssetDate : AssetDate.values()) { for (AssetDate acceptorAssetDate : AssetDate.values()) { for (BalanceDate issuerBalanceDate : BalanceDate.values()) { for (BalanceDate acceptorBalanceDate : BalanceDate.values()) { for (boolean included : includedValues) { for (boolean completed : completedValues) { iteration++; test(iteration, matchs, new TestData(issuer(issuerAssetDate, issuerBalanceDate), acceptor(acceptorAssetDate, acceptorBalanceDate), included, completed, type, status)); } } } } } } } } } private void test(int iteration, final List matchs, final TestData test) { OwnerType issuer = EsiOwner.create(); issuer.setOwnerID(ISSUER_ID); issuer.setOwnerName("issuer"); //issuer.setCorporationID(ISSUER_CORPORATION_ID); issuer.setCorporationName("issuer corporation"); setOwnerData(issuer, test.getIssuer()); OwnerType acceptor = EsiOwner.create(); acceptor.setOwnerID(ACCEPTOR_ID); acceptor.setOwnerName("acceptor"); //acceptor.setCorporationID(ACCEPTOR_CORPORATION_ID); acceptor.setCorporationName("acceptor corporation"); setOwnerData(acceptor, test.getAcceptor()); Map owners = new HashMap<>(); owners.put(issuer.getOwnerID(), issuer); owners.put(acceptor.getOwnerID(), acceptor); Map values = new HashMap<>(); List contractItems = new ArrayList<>(); List contracts = new ArrayList<>(); MyContract contract = getContract(test, issuer, acceptor); contracts.add(contract); contractItems.add(getContractItem(contract, test.isIncluded())); Value total = new Value(now); creator.addContractItems(contractItems, values, owners, total, now); creator.addContracts(contracts, values, owners, total, now); double collateral = 0; double value = 0; for (TestMatch match : test.match(matchs)) { collateral = collateral + match.getCollateral(); value = value + match.getValue(); } assertThat(print(iteration, test, total), total.getContractCollateral(), equalTo(collateral)); assertThat(print(iteration, test, total), total.getContractValue(), equalTo(value)); } private String print(final int iteration, final TestData test, final Value total) { StringBuilder builder = new StringBuilder(); builder.append("\r\niteration: "); builder.append(iteration); builder.append("\r\nTestData\r\n Status: "); builder.append(test.getContractStatus()); builder.append("\r\n Type: "); builder.append(test.getContractType()); builder.append("\r\n Complated: "); builder.append(test.isComplated()); builder.append("\r\n Included: "); builder.append(test.isIncluded()); builder.append("\r\n Issue:\r\n AssetDate."); builder.append(test.getIssuer().getAssetDate()); builder.append("\r\n BalanceDate."); builder.append(test.getIssuer().getBalanceDate()); builder.append("\r\n Acceptor:\r\n AssetDate."); builder.append(test.getAcceptor().getAssetDate()); builder.append("\r\n BalanceDate."); builder.append(test.getAcceptor().getBalanceDate()); builder.append("\r\nTotal\r\n Collateral: "); builder.append(total.getContractCollateral()); builder.append("\r\n Value: "); builder.append(total.getContractValue()); builder.append("\r\n"); return builder.toString(); } private Issuer issuer(AssetDate assetDate, BalanceDate balanceDate) { return new Issuer(assetDate, balanceDate); } private Acceptor acceptor(AssetDate assetDate, BalanceDate balanceDate) { return new Acceptor(assetDate, balanceDate); } public Set contractStatus(ContractStatus ... data) { return new HashSet<>(Arrays.asList(data)); } public Set contractType(ContractType ... data) { return new HashSet<>(Arrays.asList(data)); } private void setOwnerData(OwnerType ownerType, OwnerData ownerData) { if (ownerData.getAssetDate() == null) { ownerType.setAssetLastUpdate(now); } else switch (ownerData.getAssetDate()) { case UPDATED: ownerType.setAssetLastUpdate(after); break; case NOT_UPDATED: ownerType.setAssetLastUpdate(before); break; default: throw new RuntimeException("AssetLastUpdate not set"); } if (ownerData.getBalanceDate() == null) { ownerType.setBalanceLastUpdate(now); } else switch (ownerData.getBalanceDate()) { case UPDATED: ownerType.setBalanceLastUpdate(after); break; case NOT_UPDATED: ownerType.setBalanceLastUpdate(before); break; default: throw new RuntimeException("BalanceLastUpdate not set"); } } private MyContract getContract(TestData data, OwnerType issuer, OwnerType acceptor) { RawContract contract = RawContract.create(); if (data.isComplated()) { contract.setDateCompleted(now); } else { contract.setDateCompleted(null); } contract.setDateExpired(after); //Required, never null contract.setDateIssued(now); contract.setCollateral(COLLATERAL); contract.setPrice(PRICE); contract.setReward(REWARD); contract.setStatus(data.getContractStatus()); contract.setForCorporation(false); contract.setType(data.getContractType()); contract.setIssuerID((int) ISSUER_ID); contract.setIssuerCorporationID((int) ISSUER_CORPORATION_ID); contract.setAcceptorID((int) ACCEPTOR_ID); contract.setAssigneeID(0); MyContract myContract = new MyContract(contract); myContract.setIssuer(issuer.getOwnerName()); myContract.setIssuerCorp(issuer.getCorporationName()); myContract.setAcceptor(acceptor.getOwnerName()); return myContract; } private MyContractItem getContractItem(MyContract contract, boolean included) { RawContractItem item = RawContractItem.create(); item.setQuantity(1); item.setIncluded(included); MyContractItem contractItem = new MyContractItem(item, contract, null); contractItem.setDynamicPrice(ITEM); return contractItem; } private Date getAfter() { Calendar cal = Calendar.getInstance(); cal.setTime(new Date()); cal.add(Calendar.HOUR_OF_DAY, 1); return cal.getTime(); } private Date getBefore() { Calendar cal = Calendar.getInstance(); cal.setTime(new Date()); cal.add(Calendar.HOUR_OF_DAY, -1); return cal.getTime(); } private static class DataSetCreatorTester extends DataSetCreator { public DataSetCreatorTester() { } @Override public void addContractItems(List contractItems, Map values, Map owners, Value total, Date date) { super.addContractItems(contractItems, values, owners, total, date); } @Override public void addContracts(List contracts, Map values, Map owners, Value total, Date date) { super.addContracts(contracts, values, owners, total, date); } } private static class TestMatch { private final int group; private final Issuer issuer; private final Acceptor acceptor; private final Included included; private final Completed completed; private final double collateral; private final double value; private final Set contractType; private final Set contractStatus; private final Set notContractStatus; public TestMatch(int group, Issuer issuer, Acceptor acceptor, Included included, Completed completed, double collateral, double value, Set contractType, Set contractStatus, Set notContractStatus) { this.group = group; this.issuer = issuer; this.acceptor = acceptor; this.included = included; this.completed = completed; this.collateral = collateral; this.value = value; this.contractType = contractType; this.contractStatus = contractStatus; this.notContractStatus = notContractStatus; } public int getGroup() { return group; } public Issuer getIssuer() { return issuer; } public Acceptor getAcceptor() { return acceptor; } public Included getIncluded() { return included; } public Completed getCompleted() { return completed; } public double getCollateral() { return collateral; } public double getValue() { return value; } public Set getContractType() { return contractType; } public Set getContractStatus() { return contractStatus; } public Set getNotContractStatus() { return notContractStatus; } } private static class TestData { private final Issuer issuer; private final Acceptor acceptor; private final boolean included; private final boolean completed; private final ContractType contractType; private final ContractStatus contractStatus; public TestData(Issuer issuer, Acceptor acceptor, boolean included, boolean completed, ContractType contractType, ContractStatus contractStatus) { this.issuer = issuer; this.acceptor = acceptor; this.included = included; this.completed = completed; this.contractType = contractType; this.contractStatus = contractStatus; } public Issuer getIssuer() { return issuer; } public Acceptor getAcceptor() { return acceptor; } public boolean isIncluded() { return included; } public boolean isComplated() { return completed; } public ContractType getContractType() { return contractType; } public ContractStatus getContractStatus() { return contractStatus; } public List match(final List matchs) { final List ok = new ArrayList<>(); Set found = new HashSet<>(); for (TestMatch match : matchs) { if (found.contains(match.getGroup())) { continue; } if (!match.getAcceptor().match(acceptor)) { continue; } if (!match.getIssuer().match(issuer)) { continue; } switch(match.getIncluded()) { case TRUE: if (!included) { continue; } break; case FALSE: if (included) { continue; } break; } switch(match.getCompleted()) { case TRUE: if (!completed) { continue; } break; case FALSE: if (completed) { continue; } break; } if (!match.getContractType().isEmpty() && !match.getContractType().contains(contractType)) { continue; } if (!match.getContractStatus().isEmpty() && !match.getContractStatus().contains(contractStatus)) { continue; } if (!match.getNotContractStatus().isEmpty() && match.getNotContractStatus().contains(contractStatus)) { continue; } found.add(match.getGroup()); ok.add(match); } return ok; } } private static class Acceptor implements OwnerData { protected final AssetDate assetDate; protected final BalanceDate balanceDate; public Acceptor(AssetDate assetDate, BalanceDate balanceDate) { this.assetDate = assetDate; this.balanceDate = balanceDate; } @Override public AssetDate getAssetDate() { return assetDate; } @Override public BalanceDate getBalanceDate() { return balanceDate; } @Override public boolean match(Acceptor acceptor) { return match(this, acceptor); } } private static class Issuer implements OwnerData { protected final AssetDate assetDate; protected final BalanceDate balanceDate; public Issuer(AssetDate assetDate, BalanceDate balanceDate) { this.assetDate = assetDate; this.balanceDate = balanceDate; } @Override public AssetDate getAssetDate() { return assetDate; } @Override public BalanceDate getBalanceDate() { return balanceDate; } @Override public boolean match(Issuer issuer) { return match(this, issuer); } } private static interface OwnerData> { public AssetDate getAssetDate(); public BalanceDate getBalanceDate(); public boolean match(T ownerData); default boolean match(T o1, T o2) { return match(o1.getAssetDate(), o2.getAssetDate()) && match(o1.getBalanceDate(), o2.getBalanceDate()); } default boolean match(AssetDate o1, AssetDate o2) { if (o1 == null || o2 == null) { return true; } else { return o1 == o2; } } default boolean match(BalanceDate o1, BalanceDate o2) { if (o1 == null || o2 == null) { return true; } else { return o1 == o2; } } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/i18n/TestI18N.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.i18n; import net.nikr.eve.jeveasset.TestUtil; import static org.junit.Assert.assertNotNull; import org.junit.Test; /** * * @author Candle */ public class TestI18N extends TestUtil { @Test public void testDataColors_en() throws Exception { DataColors g = BundleServiceFactory.getBundleService().get(DataColors.class); assertNotNull(g.assetsReprocessingEqual()); } @Test public void testDataModelAsset_en() throws Exception { DataModelAsset g = BundleServiceFactory.getBundleService().get(DataModelAsset.class); assertNotNull(g.packaged()); } @Test public void testDataModelIndustryJob_en() throws Exception { DataModelIndustryJob g = BundleServiceFactory.getBundleService().get(DataModelIndustryJob.class); assertNotNull(g.activityAll()); } @Test public void testDataModelPriceDataSettings_en() throws Exception { DataModelPriceDataSettings g = BundleServiceFactory.getBundleService().get(DataModelPriceDataSettings.class); assertNotNull(g.priceBuyAvg()); } @Test public void testDialoguesAbout_en() throws Exception { DialoguesAbout g = BundleServiceFactory.getBundleService().get(DialoguesAbout.class); assertNotNull(g.about()); } @Test public void testDialoguesAccount_en() throws Exception { DialoguesAccount g = BundleServiceFactory.getBundleService().get(DialoguesAccount.class); assertNotNull(g.accessKey()); } @Test public void testDialoguesExport_en() throws Exception { DialoguesExport g = BundleServiceFactory.getBundleService().get(DialoguesExport.class); assertNotNull(g.noFilter()); } @Test public void testDialoguesProfiles_en() throws Exception { DialoguesProfiles g = BundleServiceFactory.getBundleService().get(DialoguesProfiles.class); assertNotNull(g.deleteProfileConfirm("delete me!")); } @Test public void testDialoguesSettings_en() throws Exception { DialoguesSettings g = BundleServiceFactory.getBundleService().get(DialoguesSettings.class); assertNotNull(g.enterFilter()); } @Test public void testDialoguesStructure_en() throws Exception { DialoguesStructure g = BundleServiceFactory.getBundleService().get(DialoguesStructure.class); assertNotNull(g.invalid()); } @Test public void testDialoguesUpdate_en() throws Exception { DialoguesUpdate g = BundleServiceFactory.getBundleService().get(DialoguesUpdate.class); assertNotNull(g.accountBalance()); } @Test public void testGeneral_en() throws Exception { General g = BundleServiceFactory.getBundleService().get(General.class); assertNotNull(g.uncaughtErrorMessage()); } @Test public void testGuiFrame_en() throws Exception { GuiFrame g = BundleServiceFactory.getBundleService().get(GuiFrame.class); assertNotNull(g.about()); } @Test public void testGuiShared_en() throws Exception { GuiShared g = BundleServiceFactory.getBundleService().get(GuiShared.class); assertNotNull(g.add()); } @Test public void testTabNpcStandingPoints_en() throws Exception { TabsNpcStanding g = BundleServiceFactory.getBundleService().get(TabsNpcStanding.class); assertNotNull(g.npcStanding()); } @Test public void testTabsAssets_en() throws Exception { TabsAssets g = BundleServiceFactory.getBundleService().get(TabsAssets.class); assertNotNull(g.assets()); } @Test public void testTabsContracts_en() throws Exception { TabsContracts g = BundleServiceFactory.getBundleService().get(TabsContracts.class); assertNotNull(g.auction()); } @Test public void testTabsItems_en() throws Exception { TabsItems g = BundleServiceFactory.getBundleService().get(TabsItems.class); assertNotNull(g.columnName()); } @Test public void testTabsJobs_en() throws Exception { TabsJobs g = BundleServiceFactory.getBundleService().get(TabsJobs.class); assertNotNull(g.all()); } @Test public void testTabsJournal_en() throws Exception { TabsJournal g = BundleServiceFactory.getBundleService().get(TabsJournal.class); assertNotNull(g.clearNew()); } @Test public void testTabsLoadout_en() throws Exception { TabsLoadout g = BundleServiceFactory.getBundleService().get(TabsLoadout.class); assertNotNull(g.cancel()); } @Test public void testTabsLoyaltyPoints_en() throws Exception { TabsLoyaltyPoints g = BundleServiceFactory.getBundleService().get(TabsLoyaltyPoints.class); assertNotNull(g.loyaltyPoints()); } @Test public void testTabsMaterials_en() throws Exception { TabsMaterials g = BundleServiceFactory.getBundleService().get(TabsMaterials.class); assertNotNull(g.collapse()); } @Test public void testTabsMining_en() throws Exception { TabsMining g = BundleServiceFactory.getBundleService().get(TabsMining.class); assertNotNull(g.miningLog()); } @Test public void testTabsOrders_en() throws Exception { TabsOrders g = BundleServiceFactory.getBundleService().get(TabsOrders.class); assertNotNull(g.columnExpires()); } @Test public void testTabsOverview_en() throws Exception { TabsOverview g = BundleServiceFactory.getBundleService().get(TabsOverview.class); assertNotNull(g.add()); } @Test public void testTabsPriceChanges_en() throws Exception { TabsPriceChanges g = BundleServiceFactory.getBundleService().get(TabsPriceChanges.class); assertNotNull(g.columnCategory()); } @Test public void testTabsPriceHistory_en() throws Exception { TabsPriceHistory g = BundleServiceFactory.getBundleService().get(TabsPriceHistory.class); assertNotNull(g.add()); } @Test public void testTabsReprocessed_en() throws Exception { TabsReprocessed g = BundleServiceFactory.getBundleService().get(TabsReprocessed.class); assertNotNull(g.addItem()); } @Test public void testTabsRouting_en() throws Exception { TabsRouting g = BundleServiceFactory.getBundleService().get(TabsRouting.class); assertNotNull(g.add()); } @Test public void testTabsSkills_en() throws Exception { TabsSkills g = BundleServiceFactory.getBundleService().get(TabsSkills.class); assertNotNull(g.skills()); } @Test public void testTabsSlots_en() throws Exception { TabsSlots g = BundleServiceFactory.getBundleService().get(TabsSlots.class); assertNotNull(g.title()); } @Test public void testTabsStockpile_en() throws Exception { TabsStockpile g = BundleServiceFactory.getBundleService().get(TabsStockpile.class); assertNotNull(g.addItem()); } @Test public void testTabsTracker_en() throws Exception { TabsTracker g = BundleServiceFactory.getBundleService().get(TabsTracker.class); assertNotNull(g.allProfiles()); } @Test public void testTabsTransaction_en() throws Exception { TabsTransaction g = BundleServiceFactory.getBundleService().get(TabsTransaction.class); assertNotNull(g.buy()); } @Test public void testTabsTabsTree_en() throws Exception { TabsTree g = BundleServiceFactory.getBundleService().get(TabsTree.class); assertNotNull(g.categories()); } @Test public void testTabsValues_en() throws Exception { TabsValues g = BundleServiceFactory.getBundleService().get(TabsValues.class); assertNotNull(g.columnAssets()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/esi/EsiConverterTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyAccountBalance; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.api.raw.RawBlueprint; import net.nikr.eve.jeveasset.io.shared.ConverterTestOptions; import net.nikr.eve.jeveasset.io.shared.ConverterTestOptionsGetter; import net.nikr.eve.jeveasset.io.shared.ConverterTestUtil; import net.troja.eve.esi.model.CharacterAssetsResponse; import net.troja.eve.esi.model.CharacterBlueprintsResponse; import net.troja.eve.esi.model.ContractItemsResponse; import net.troja.eve.esi.model.CharacterContractsResponse; import net.troja.eve.esi.model.CharacterIndustryJobsResponse; import net.troja.eve.esi.model.CharacterLocationResponse; import net.troja.eve.esi.model.CharacterOrdersHistoryResponse; import net.troja.eve.esi.model.CharacterOrdersResponse; import net.troja.eve.esi.model.CharacterShipResponse; import net.troja.eve.esi.model.CharacterWalletJournalResponse; import net.troja.eve.esi.model.CharacterWalletTransactionsResponse; import net.troja.eve.esi.model.CorporationAssetsResponse; import net.troja.eve.esi.model.CorporationBlueprintsResponse; import net.troja.eve.esi.model.CorporationContractsResponse; import net.troja.eve.esi.model.CorporationIndustryJobsResponse; import net.troja.eve.esi.model.CorporationOrdersHistoryResponse; import net.troja.eve.esi.model.CorporationOrdersResponse; import net.troja.eve.esi.model.CorporationWalletJournalResponse; import net.troja.eve.esi.model.CorporationWalletTransactionsResponse; import net.troja.eve.esi.model.CorporationWalletsResponse; import static org.junit.Assert.assertEquals; import org.junit.Test; public class EsiConverterTest extends TestUtil { private static final boolean SAVE_HISTORY = false; @Test public void testToAccountBalance() { testToAccountBalance(null); } public void testToAccountBalance(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { List accountBalances = EsiConverter.toAccountBalance(options.getDouble(), ConverterTestUtil.getEsiOwner(options), options.getInteger()); ConverterTestUtil.testValues(accountBalances.get(0), options, esi); } } @Test public void testToAccountBalanceCorporation() { testToAccountBalanceCorporation(null); } @Test public void testToAccountBalanceCorporationOptional() { testToAccountBalanceCorporation(CorporationWalletsResponse.class); } public void testToAccountBalanceCorporation(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CorporationWalletsResponse walletsResponse = new CorporationWalletsResponse(); ConverterTestUtil.setValues(walletsResponse, options, esi); List accountBalances = EsiConverter.toAccountBalanceCorporation(Collections.singletonList(walletsResponse), ConverterTestUtil.getEsiOwner(options)); ConverterTestUtil.testValues(accountBalances.get(0), options, esi); } } @Test public void testToAssets() { testToAssets(null); } @Test public void testToAssetsOptional() { testToAssets(CharacterAssetsResponse.class); } public void testToAssets(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { List assetsResponses = new ArrayList<>(); CharacterAssetsResponse rootAssetsResponse = new CharacterAssetsResponse(); assetsResponses.add(rootAssetsResponse); ConverterTestUtil.setValues(rootAssetsResponse, options, esi); rootAssetsResponse.setItemId(rootAssetsResponse.getItemId() + 1); CharacterAssetsResponse childAssetsResponse = new CharacterAssetsResponse(); assetsResponses.add(childAssetsResponse); ConverterTestUtil.setValues(childAssetsResponse, options, esi); childAssetsResponse.setLocationId(rootAssetsResponse.getItemId()); EsiOwner owner = ConverterTestUtil.getEsiOwner(options); List assets = EsiConverter.toAssets(assetsResponses, owner); if (!assets.isEmpty()) { assertEquals("List empty @" + options.getIndex(), 1, assets.size()); ConverterTestUtil.testValues(assets.get(0), options, esi); assertEquals("List empty @" + options.getIndex(), 1, assets.get(0).getAssets().size()); MyAsset childAsset = assets.get(0).getAssets().get(0); ConverterTestUtil.testValues(childAsset, options, esi); } else { assertEquals(assets.size(), 0); } } } @Test public void testToAssetsCorporation() { testToAssetsCorporation(null); } @Test public void testToAssetsCorporationOptional() { testToAssetsCorporation(CorporationAssetsResponse.class); } public void testToAssetsCorporation(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { List assetsResponses = new ArrayList<>(); CorporationAssetsResponse rootAssetsResponse = new CorporationAssetsResponse(); assetsResponses.add(rootAssetsResponse); ConverterTestUtil.setValues(rootAssetsResponse, options, esi); rootAssetsResponse.setItemId(rootAssetsResponse.getItemId() + 1); CorporationAssetsResponse childAssetsResponse = new CorporationAssetsResponse(); assetsResponses.add(childAssetsResponse); ConverterTestUtil.setValues(childAssetsResponse, options, esi); childAssetsResponse.setLocationId(rootAssetsResponse.getItemId()); EsiOwner owner = ConverterTestUtil.getEsiOwner(options); List assets = EsiConverter.toAssetsCorporation(assetsResponses, owner); if (!assets.isEmpty()) { assertEquals("List empty @" + options.getIndex(), 1, assets.size()); ConverterTestUtil.testValues(assets.get(0), options, esi); assertEquals("List empty @" + options.getIndex(), 1, assets.get(0).getAssets().size()); MyAsset childAsset = assets.get(0).getAssets().get(0); ConverterTestUtil.testValues(childAsset, options, esi); } else { assertEquals(assets.size(), 0); } } } @Test public void testToBlueprints() { testBlueprints(null); } @Test public void testToBlueprintsOptional() { testBlueprints(CharacterBlueprintsResponse.class); } private void testBlueprints(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CharacterBlueprintsResponse blueprintsResponse = new CharacterBlueprintsResponse(); ConverterTestUtil.setValues(blueprintsResponse, options, esi); Map blueprints = EsiConverter.toBlueprints(Collections.singletonList(blueprintsResponse)); ConverterTestUtil.testValues(blueprints.values().iterator().next(), options, esi); } } @Test public void testToBlueprintsCorporation() { testToBlueprintsCorporation(null); } @Test public void testToBlueprintsCorporationOptional() { testToBlueprintsCorporation(CorporationBlueprintsResponse.class); } public void testToBlueprintsCorporation(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CorporationBlueprintsResponse blueprintsResponse = new CorporationBlueprintsResponse(); ConverterTestUtil.setValues(blueprintsResponse, options, esi); Map blueprints = EsiConverter.toBlueprintsCorporation(Collections.singletonList(blueprintsResponse)); ConverterTestUtil.testValues(blueprints.values().iterator().next(), options, esi); } } @Test public void testToIndustryJobs() { testToIndustryJobs(null); } @Test public void testToIndustryJobsOptional() { testToIndustryJobs(CharacterIndustryJobsResponse.class); } private void testToIndustryJobs(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CharacterIndustryJobsResponse industryJobsResponse = new CharacterIndustryJobsResponse(); ConverterTestUtil.setValues(industryJobsResponse, options, esi); Set industryJobs = EsiConverter.toIndustryJobs(Collections.singletonList(industryJobsResponse), ConverterTestUtil.getEsiOwner(options), SAVE_HISTORY); ConverterTestUtil.testValues(industryJobs.iterator().next(), options, esi); } } @Test public void testToIndustryJobsCorporation() { testToIndustryJobsCorporation(null); } @Test public void testToIndustryJobsCorporationOptional() { testToIndustryJobsCorporation(CorporationIndustryJobsResponse.class); } private void testToIndustryJobsCorporation(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CorporationIndustryJobsResponse industryJobsResponse = new CorporationIndustryJobsResponse(); ConverterTestUtil.setValues(industryJobsResponse, options, esi); Set industryJobs = EsiConverter.toIndustryJobsCorporation(Collections.singletonList(industryJobsResponse), ConverterTestUtil.getEsiOwner(options), SAVE_HISTORY); ConverterTestUtil.testValues(industryJobs.iterator().next(), options, esi); } } @Test public void testToJournals() { testToJournals(null); } @Test public void testToJournalsOptional() { testToJournals(CharacterWalletJournalResponse.class); } private void testToJournals(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CharacterWalletJournalResponse journalResponse = new CharacterWalletJournalResponse(); ConverterTestUtil.setValues(journalResponse, options, esi); Set journals = EsiConverter.toJournals(Collections.singletonList(journalResponse), ConverterTestUtil.getEsiOwner(options), options.getInteger(), SAVE_HISTORY); ConverterTestUtil.testValues(journals.iterator().next(), options, esi); } } @Test public void testToJournalsCorporation() { testToJournalsCorporation(null); } @Test public void testToJournalsCorporationOptional() { testToJournalsCorporation(CorporationWalletJournalResponse.class); } public void testToJournalsCorporation(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CorporationWalletJournalResponse journalResponse = new CorporationWalletJournalResponse(); ConverterTestUtil.setValues(journalResponse, options, esi); Set journals = EsiConverter.toJournalsCorporation(Collections.singletonList(journalResponse), ConverterTestUtil.getEsiOwner(options), options.getInteger(), SAVE_HISTORY); ConverterTestUtil.testValues(journals.iterator().next(), options, esi); } } @Test public void testToContracts() { testToContracts(null); } @Test public void testToContractsOptional() { testToContracts(CharacterContractsResponse.class); } public void testToContracts(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CharacterContractsResponse contractsResponse = new CharacterContractsResponse(); ConverterTestUtil.setValues(contractsResponse, options, esi); Map> contracts = EsiConverter.toContracts(Collections.singletonList(contractsResponse), ConverterTestUtil.getEsiOwner(options), SAVE_HISTORY); ConverterTestUtil.testValues(contracts.keySet().iterator().next(), options, esi); } } @Test public void testToContractsCorporation() { testToContractsCorporation(null); } @Test public void testToContractsCorporationOptional() { testToContractsCorporation(CorporationContractsResponse.class); } public void testToContractsCorporation(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CorporationContractsResponse contractsResponse = new CorporationContractsResponse(); ConverterTestUtil.setValues(contractsResponse, options, esi); Map> contracts = EsiConverter.toContractsCorporation(Collections.singletonList(contractsResponse), ConverterTestUtil.getEsiOwner(options), SAVE_HISTORY); ConverterTestUtil.testValues(contracts.keySet().iterator().next(), options, esi); } } @Test public void testToContractItems() { testToContractItems(null); } @Test public void testToContractItemsOptional() { testToContractItems(ContractItemsResponse.class); } public void testToContractItems(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { ContractItemsResponse contractsItemsResponse = new ContractItemsResponse(); ConverterTestUtil.setValues(contractsItemsResponse, options, esi); Map> contractItems = EsiConverter.toContractItems(Collections.singletonMap(ConverterTestUtil.getMyContract(false, true, options), Collections.singletonList(contractsItemsResponse)), ConverterTestUtil.getEsiOwner(options), SAVE_HISTORY); ConverterTestUtil.testValues(contractItems.values().iterator().next().get(0), options, esi); } } @Test public void testToMarketOrders() { testToMarketOrders(null); } @Test public void testToMarketOrdersOptional() { testToMarketOrders(CharacterOrdersResponse.class); } public void testToMarketOrders(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CharacterOrdersResponse ordersResponse = new CharacterOrdersResponse(); ConverterTestUtil.setValues(ordersResponse, options, esi); Set marketOrders = EsiConverter.toMarketOrders(Collections.singletonList(ordersResponse), new ArrayList<>(), ConverterTestUtil.getEsiOwner(options), SAVE_HISTORY); ConverterTestUtil.testValues(marketOrders.iterator().next(), options, esi); } } @Test public void testToMarketOrdersHistory() { testToMarketOrdersHistory(null); } @Test public void testToMarketOrdersHistoryOptional() { testToMarketOrdersHistory(CharacterOrdersHistoryResponse.class); } public void testToMarketOrdersHistory(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CharacterOrdersHistoryResponse ordersHistoryResponse = new CharacterOrdersHistoryResponse(); ConverterTestUtil.setValues(ordersHistoryResponse, options, esi); Set marketOrders = EsiConverter.toMarketOrders(new ArrayList<>(), Collections.singletonList(ordersHistoryResponse), ConverterTestUtil.getEsiOwner(options), SAVE_HISTORY); ConverterTestUtil.testValues(marketOrders.iterator().next(), options, esi); } } @Test public void testToMarketOrdersCorporation() { testToMarketOrdersCorporation(null); } @Test public void testToMarketOrdersCorporationOptional() { testToMarketOrdersCorporation(CorporationOrdersResponse.class); } public void testToMarketOrdersCorporation(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CorporationOrdersResponse ordersResponse = new CorporationOrdersResponse(); ConverterTestUtil.setValues(ordersResponse, options, esi); Set marketOrders = EsiConverter.toMarketOrdersCorporation(Collections.singletonList(ordersResponse), new ArrayList<>(), ConverterTestUtil.getEsiOwner(options), SAVE_HISTORY); ConverterTestUtil.testValues(marketOrders.iterator().next(), options, esi); } } @Test public void testToMarketOrdersHistoryCorporation() { testToMarketOrdersHistoryCorporation(null); } @Test public void testToMarketOrdersHistoryCorporationOptional() { testToMarketOrdersHistoryCorporation(CorporationOrdersHistoryResponse.class); } public void testToMarketOrdersHistoryCorporation(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CorporationOrdersHistoryResponse ordersHistoryResponse = new CorporationOrdersHistoryResponse(); ConverterTestUtil.setValues(ordersHistoryResponse, options, esi); Set marketOrders = EsiConverter.toMarketOrdersCorporation(new ArrayList<>(), Collections.singletonList(ordersHistoryResponse), ConverterTestUtil.getEsiOwner(options), SAVE_HISTORY); ConverterTestUtil.testValues(marketOrders.iterator().next(), options, esi); } } @Test public void testToTransaction() { testToTransaction(null); } @Test public void testToTransactionOptional() { testToTransaction(CharacterWalletTransactionsResponse.class); } public void testToTransaction(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CharacterWalletTransactionsResponse transactionsResponse = new CharacterWalletTransactionsResponse(); ConverterTestUtil.setValues(transactionsResponse, options, esi); Set transactions = EsiConverter.toTransaction(Collections.singletonList(transactionsResponse), ConverterTestUtil.getEsiOwner(options), options.getInteger(), SAVE_HISTORY); ConverterTestUtil.testValues(transactions.iterator().next(), options, esi); } } @Test public void testToTransactionCorporation() { testToTransactionCorporation(null); } @Test public void testToTransactionCorporationOptional() { testToTransactionCorporation(CorporationWalletTransactionsResponse.class); } public void testToTransactionCorporation(Class esi) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CorporationWalletTransactionsResponse transactionsResponse = new CorporationWalletTransactionsResponse(); ConverterTestUtil.setValues(transactionsResponse, options, esi); Set transactions = EsiConverter.toTransactionCorporation(Collections.singletonList(transactionsResponse), ConverterTestUtil.getEsiOwner(options), options.getInteger(), SAVE_HISTORY); MyTransaction myTransaction = transactions.iterator().next(); myTransaction.setPersonal(true); ConverterTestUtil.testValues(transactions.iterator().next(), options, esi); } } @Test public void testToAssetsShip() { testToAssetsShip(null, null); } @Test public void testToAssetsShipOptional() { testToAssetsShip(CharacterShipResponse.class, CharacterLocationResponse.class); } public void testToAssetsShip(Class esiShip, Class esiLocation) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { CharacterShipResponse shipType = new CharacterShipResponse(); ConverterTestUtil.setValues(shipType, options, esiShip); CharacterLocationResponse shipLocation = new CharacterLocationResponse(); ConverterTestUtil.setValues(shipLocation, options, esiLocation); MyAsset asset = EsiConverter.toAssetsShip(shipType, shipLocation, ConverterTestUtil.getEsiOwner(options)); asset.setQuantity(options.getInteger()); //Always 1 -> set to 5 to pass test asset.setItemFlag(options.getItemFlag()); //Always "None" -> set to option value to pass test ConverterTestUtil.testValues(asset, options, null); } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/esi/EsiDeprecationOnlineTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.awt.Desktop; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URI; import java.net.URISyntaxException; import java.time.LocalDate; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.TestUtil; import net.troja.eve.esi.ApiClient; import net.troja.eve.esi.ApiClientBuilder; import net.troja.eve.esi.ApiException; import net.troja.eve.esi.ApiResponse; import net.troja.eve.esi.api.AssetsApi; import net.troja.eve.esi.api.CharacterApi; import net.troja.eve.esi.api.ContractsApi; import net.troja.eve.esi.api.CorporationApi; import net.troja.eve.esi.api.FactionWarfareApi; import net.troja.eve.esi.api.IndustryApi; import net.troja.eve.esi.api.LocationApi; import net.troja.eve.esi.api.MarketApi; import net.troja.eve.esi.api.PlanetaryInteractionApi; import net.troja.eve.esi.api.SkillsApi; import net.troja.eve.esi.api.SovereigntyApi; import net.troja.eve.esi.api.UniverseApi; import net.troja.eve.esi.api.UserInterfaceApi; import net.troja.eve.esi.api.WalletApi; import net.troja.eve.esi.auth.JWT; import net.troja.eve.esi.auth.JWT.Payload; import net.troja.eve.esi.auth.OAuth; import net.troja.eve.esi.model.CategoryResponse; import net.troja.eve.esi.model.CharacterAffiliationResponse; import net.troja.eve.esi.model.AssetsNamesResponse; import net.troja.eve.esi.model.CharacterAssetsResponse; import net.troja.eve.esi.model.CharacterBlueprintsResponse; import net.troja.eve.esi.model.CharacterContractsResponse; import net.troja.eve.esi.model.CharacterIndustryJobsResponse; import net.troja.eve.esi.model.CharacterLocationResponse; import net.troja.eve.esi.model.CharacterMiningResponse; import net.troja.eve.esi.model.CharacterOrdersHistoryResponse; import net.troja.eve.esi.model.CharacterOrdersResponse; import net.troja.eve.esi.model.CharacterPlanetResponse; import net.troja.eve.esi.model.CharacterRolesResponse; import net.troja.eve.esi.model.CharacterShipResponse; import net.troja.eve.esi.model.CharacterSkillsResponse; import net.troja.eve.esi.model.CharacterWalletJournalResponse; import net.troja.eve.esi.model.CharacterWalletTransactionsResponse; import net.troja.eve.esi.model.CorporationAssetsResponse; import net.troja.eve.esi.model.CorporationBlueprintsResponse; import net.troja.eve.esi.model.ContractItemsResponse; import net.troja.eve.esi.model.CorporationContractsResponse; import net.troja.eve.esi.model.CorporationDivisionsResponse; import net.troja.eve.esi.model.CorporationIndustryJobsResponse; import net.troja.eve.esi.model.CorporationMiningExtractionsResponse; import net.troja.eve.esi.model.CorporationMiningObserverResponse; import net.troja.eve.esi.model.CorporationMiningObserversResponse; import net.troja.eve.esi.model.CorporationOrdersHistoryResponse; import net.troja.eve.esi.model.CorporationOrdersResponse; import net.troja.eve.esi.model.CorporationResponse; import net.troja.eve.esi.model.CorporationWalletJournalResponse; import net.troja.eve.esi.model.CorporationWalletTransactionsResponse; import net.troja.eve.esi.model.CorporationWalletsResponse; import net.troja.eve.esi.model.FactionWarfareSystemsResponse; import net.troja.eve.esi.model.FactionsResponse; import net.troja.eve.esi.model.GroupResponse; import net.troja.eve.esi.model.IndustrySystemsResponse; import net.troja.eve.esi.model.MarketGroupResponse; import net.troja.eve.esi.model.MarketRegionOrdersResponse; import net.troja.eve.esi.model.MarketPricesResponse; import net.troja.eve.esi.model.MarketStructureResponse; import net.troja.eve.esi.model.MoonResponse; import net.troja.eve.esi.model.NamesResponse; import net.troja.eve.esi.model.PlanetResponse; import net.troja.eve.esi.model.PublicContractsItemsResponse; import net.troja.eve.esi.model.SovereigntyStructuresResponse; import net.troja.eve.esi.model.StructureResponse; import net.troja.eve.esi.model.TypeResponse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import org.junit.Test; public class EsiDeprecationOnlineTest extends TestUtil { private final static LocalDate COMPATIBILITY_DATE = UniverseApi.COMPATIBILITY_DATE; private final static ApiClient API_CLIENT = setupAuth(); private final static WalletApi WALLET_API = new WalletApi(API_CLIENT); private final static AssetsApi ASSETS_API = new AssetsApi(API_CLIENT); private final static CharacterApi CHARACTER_API = new CharacterApi(API_CLIENT); private final static CorporationApi CORPORATION_API = new CorporationApi(API_CLIENT); private final static SovereigntyApi SOVEREIGNTY_API = new SovereigntyApi(); private final static ContractsApi CONTRACTS_API = new ContractsApi(API_CLIENT); private final static IndustryApi INDUSTRY_API = new IndustryApi(API_CLIENT); private final static MarketApi MARKET_API = new MarketApi(API_CLIENT); private final static UniverseApi UNIVERSE_API = new UniverseApi(API_CLIENT); private final static PlanetaryInteractionApi PLANETARY_INTERACTION_API = new PlanetaryInteractionApi(API_CLIENT); private final static LocationApi LOCATION_API = new LocationApi(API_CLIENT); private final static UserInterfaceApi USER_INTERFACE_API = new UserInterfaceApi(API_CLIENT); private final static SkillsApi SKILLS_API = new SkillsApi(API_CLIENT); private static final FactionWarfareApi FACTION_WARFARE_API = new FactionWarfareApi(API_CLIENT); public EsiDeprecationOnlineTest() { } public static ApiClient setupAuth() { String clientId = System.getenv().get("SSO_CLIENT_ID"); String refreshToken = System.getenv().get("SSO_REFRESH_TOKEN"); if (clientId != null && refreshToken != null) { return new ApiClientBuilder().clientID(clientId).refreshToken(refreshToken).build(); } else { return new ApiClient(); } } /** * This main method can be used to generate a refresh token to run the unit * tests that need authentication. * * @param args * @throws java.io.IOException * @throws java.net.URISyntaxException * @throws net.troja.eve.esi.ApiException */ public static void main(final String... args) throws IOException, URISyntaxException, ApiException { initLog(); final String state = "somesecret"; final ApiClient client = new ApiClientBuilder().clientID(EsiCallbackURL.LOCALHOST.getA()).build(); final OAuth auth = (OAuth) client.getAuthentication(ApiClientBuilder.AUTHENTICATION); final Set scopes = new HashSet<>(); for (EsiScopes scope : EsiScopes.values()) { if (scope.isPublicScope()) { continue; } scopes.add(scope.getScope()); } final String authorizationUri = auth.getAuthorizationUri(EsiCallbackURL.LOCALHOST.getUrl(), scopes, state); System.out.println("Authorization URL: " + authorizationUri); Desktop.getDesktop().browse(new URI(authorizationUri)); System.out.println("Code from Answer: "); final BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); final String code = br.readLine(); auth.finishFlow(code, state); System.out.println("Refresh Token: " + auth.getRefreshToken()); } @Test public void testScopes() { OAuth oAuth = (OAuth) API_CLIENT.getAuthentication(ApiClientBuilder.AUTHENTICATION); JWT jwt = oAuth.getJWT(); assumeTrue(jwt != null); assertNotNull("JWT is null", jwt); Payload payload = jwt.getPayload(); assertNotNull("Payload is null", payload); for (EsiScopes scope : EsiScopes.values()) { if (scope.isPublicScope()) { continue; } assertTrue(scope.getScope() + " not included", payload.getScopes().contains(scope.getScope())); } } @Test public void esiAccountBalanceGetterCharacter() { try { ApiResponse apiResponse = WALLET_API.getCharacterWalletWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiAccountBalanceGetterCorporation() { try { ApiResponse> apiResponse = WALLET_API.getCorporationWalletsWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiAssetsGetterCharacter() { try { ApiResponse> apiResponse = ASSETS_API.getCharacterAssetsWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiAssetsGetterCorporation() { try { ApiResponse> apiResponse = ASSETS_API.getCorporationAssetsWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiBlueprintsGetterCharacter() { try { ApiResponse> apiResponse = CHARACTER_API.getCharacterBlueprintsWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiBlueprintsGetterCorporation() { try { ApiResponse> apiResponse = CORPORATION_API.getCorporationBlueprintsWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiConquerableStationsGetter() { try { ApiResponse> apiResponse = SOVEREIGNTY_API.getSovereigntyStructuresWithHttpInfo(COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiContractItemsGetterCharacter() { try { ApiResponse> apiResponse = CONTRACTS_API.getCharacterContractItemsWithHttpInfo(1L, 1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiContractItemsGetterCorporation() { try { ApiResponse> apiResponse = CONTRACTS_API.getCorporationContractItemsWithHttpInfo(1L, 1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiContractItemsGetterPublic() { try { ApiResponse> apiResponse = CONTRACTS_API.getPublicContractsItemsContractIdWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiContractsGetterCharacter() { try { ApiResponse> apiResponse = CONTRACTS_API.getCharacterContractsWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiContractsGetterCorporation() { try { ApiResponse> apiResponse = CONTRACTS_API.getCorporationContractsWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiDivisionsGetter() { try { ApiResponse apiResponse = CORPORATION_API.getCorporationDivisionsWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiFactionWarfareGetterFactions() { try { ApiResponse> apiResponse = UNIVERSE_API.getFactionsWithHttpInfo(COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiFactionWarfareGetterSystems() { try { ApiResponse> apiResponse = FACTION_WARFARE_API.getFactionWarfareSystemsWithHttpInfo(COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiIndustryJobsGetterCharacter() { try { ApiResponse> apiResponse = INDUSTRY_API.getCharacterIndustryJobsWithHttpInfo(1L, COMPATIBILITY_DATE, true, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiIndustryJobsGetterCorporation() { try { ApiResponse> apiResponse = INDUSTRY_API.getCorporationIndustryJobsWithHttpInfo(1L, COMPATIBILITY_DATE, true, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiItemsGetterCategories() { try { ApiResponse apiResponse = UNIVERSE_API.getCategoryWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiItemsGetterGroups() { try { ApiResponse apiResponse = UNIVERSE_API.getGroupWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiItemsGetterMarketGroups() { try { ApiResponse apiResponse = MARKET_API.getMarketGroupWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiItemsGetterTypes() { try { ApiResponse apiResponse = UNIVERSE_API.getTypeWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiJournalGetterCharacter() { try { ApiResponse> apiResponse = WALLET_API.getCharacterWalletJournalWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiJournalGetterCorporation() { try { ApiResponse> apiResponse = WALLET_API.getCorporationWalletJournalWithHttpInfo(1L, 1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiLocationsGetterCharacterLocations() { try { ApiResponse> apiResponse = ASSETS_API.postCharacterAssetsNamesWithHttpInfo(1L, COMPATIBILITY_DATE, Collections.singleton(1L), null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiLocationsGetterCorporation() { try { ApiResponse> apiResponse = ASSETS_API.postCorporationAssetsNamesWithHttpInfo(1L, COMPATIBILITY_DATE, Collections.singleton(1L), null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiManufacturingPricesIndustrySystems() { try { ApiResponse> apiResponse = INDUSTRY_API.getIndustrySystemsWithHttpInfo(COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiManufacturingPricesMarketsPrices() { try { ApiResponse> apiResponse = MARKET_API.getMarketPricesWithHttpInfo(COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiMarketOrdersGetterCharacter() { try { ApiResponse> apiResponse = MARKET_API.getCharacterOrdersWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiMarketOrdersGetterCorporation() { try { ApiResponse> apiResponse = MARKET_API.getCorporationOrdersWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiMarketOrdersHistoryGetterCharacter() { try { ApiResponse> apiResponse = MARKET_API.getCharacterOrdersHistoryWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiMarketOrdersHistoryGetterCorporation() { try { ApiResponse> apiResponse = MARKET_API.getCorporationOrdersHistoryWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiMiningGetterCharacter() { try { ApiResponse> apiResponse = INDUSTRY_API.getCharacterMiningWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiMiningGetterCorporationExtractions() { try { ApiResponse> apiResponse = INDUSTRY_API.getCorporationMiningExtractionsWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiMiningGetterCorporationObserver() { try { ApiResponse> apiResponse = INDUSTRY_API.getCorporationMiningObserverWithHttpInfo(1L, 1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiMiningGetterCorporationObservers() { try { ApiResponse> apiResponse = INDUSTRY_API.getCorporationMiningObserversWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiMiningGetterMoons() { try { ApiResponse apiResponse = UNIVERSE_API.getMoonWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiNameGetter() { try { ApiResponse> apiResponse = UNIVERSE_API.postNamesWithHttpInfo(COMPATIBILITY_DATE, Collections.singleton(1L), null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiOwnerGetterCharacter() { try { ApiResponse> apiResponse = CHARACTER_API.postCharactersAffiliationWithHttpInfo(COMPATIBILITY_DATE, Collections.singleton(1L), null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiOwnerGetterCorporation() { try { ApiResponse apiResponse = CORPORATION_API.getCorporationWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiOwnerGetterRoles() { try { ApiResponse apiResponse = CHARACTER_API.getCharacterRolesWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiPlanetaryInteractionGetterPlanet() { try { ApiResponse apiResponse = PLANETARY_INTERACTION_API.getCharacterPlanetWithHttpInfo(1L, 1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiPlanetaryInteractionGetterPlanets() { try { ApiResponse apiResponse = PLANETARY_INTERACTION_API.getCharacterPlanetWithHttpInfo(1L, 1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiPlanetaryInteractionGetterPublicPlanets() { try { ApiResponse apiResponse = UNIVERSE_API.getPlanetWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiPublicMarketOrdersGetterPublicOrders() { try { ApiResponse> apiResponse = MARKET_API.getMarketRegionOrdersWithHttpInfo("all", 1L, COMPATIBILITY_DATE, null, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiPublicMarketOrdersGetterPublicStructures() { try { ApiResponse> apiResponse = UNIVERSE_API.getStructuresWithHttpInfo(COMPATIBILITY_DATE, "market", null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiPublicMarketOrdersGetterStructureOrders() { try { ApiResponse> apiResponse = MARKET_API.getMarketStructureWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiShipLocationGetter() { try { ApiResponse apiResponse = LOCATION_API.getCharacterLocationWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiShipTypeGetter() { try { ApiResponse apiResponse = LOCATION_API.getCharacterShipWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiSkillsGetter() { try { ApiResponse apiResponse = SKILLS_API.getCharacterSkillsWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiStructuresGetter() { try { ApiResponse apiResponse = UNIVERSE_API.getStructureWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiTransactionsGetterCharacter() { try { ApiResponse> apiResponse = WALLET_API.getCharacterWalletTransactionsWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiTransactionsGetterCorporation() { try { ApiResponse> apiResponse = WALLET_API.getCorporationWalletTransactionsWithHttpInfo(1L, 1L, COMPATIBILITY_DATE, null, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiUiAutopilot() { try { ApiResponse apiResponse = USER_INTERFACE_API.postUiAutopilotWaypointWithHttpInfo(false, false, 1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiUiOpenWindowContract() { try { ApiResponse apiResponse = USER_INTERFACE_API.postUiOpenwindowContractWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiUiOpenWindowInformation() { try { ApiResponse apiResponse = USER_INTERFACE_API.postUiOpenwindowInformationWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } @Test public void esiUiOpenWindowMarketDetails() { try { ApiResponse apiResponse = USER_INTERFACE_API.postUiOpenwindowMarketdetailsWithHttpInfo(1L, COMPATIBILITY_DATE, null, null, null); validate(apiResponse.getHeaders()); } catch (ApiException ex) { validate(ex.getResponseHeaders()); } } private void validate(Map> responseHeaders) { if (responseHeaders != null) { for (Map.Entry> entry : responseHeaders.entrySet()) { if (entry.getKey().toLowerCase().equals("warning")) { if (entry.getValue().get(0).startsWith("199")) { assumeTrue(entry.getValue().get(0), false); } else { fail(entry.getValue().get(0)); } } } } else { fail("No headers"); } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/esi/EsiNameGetterOnlineTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.settings.Settings; import org.junit.Assert; import org.junit.Test; public class EsiNameGetterOnlineTest extends TestUtil { @Test public void testEsi() { Set ids = new HashSet<>(); ids.add(1232111352L); ids.add(2112730710L); ids.add(500016L); ids.add(93678202L); ids.add(96503035L); List owners = new ArrayList<>(); for (Long id : ids) { EsiOwner esiOwner = EsiOwner.create(); esiOwner.setOwnerID(id); owners.add(esiOwner); } Settings.get().getOwners().clear(); EsiNameGetter esiNameGetter = new EsiNameGetter(null, owners); esiNameGetter.run(); for (Long id : ids) { Assert.assertNotNull(id + " not set", Settings.get().getOwners().get(id)); Assert.assertFalse(id + " is empty", Settings.get().getOwners().get(id).isEmpty()); } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/esi/EsiScopesTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.esi; import net.nikr.eve.jeveasset.TestUtil; import static org.junit.Assert.*; import org.junit.Test; public class EsiScopesTest extends TestUtil { @Test public void testLocalhost() { String s = "[\"esi-location.read_location.v1\",\"esi-location.read_ship_type.v1\",\"esi-skills.read_skills.v1\",\"esi-wallet.read_character_wallet.v1\",\"esi-clones.read_clones.v1\",\"esi-universe.read_structures.v1\",\"esi-assets.read_assets.v1\",\"esi-planets.manage_planets.v1\",\"esi-ui.open_window.v1\",\"esi-ui.write_waypoint.v1\",\"esi-markets.structure_markets.v1\",\"esi-characters.read_loyalty.v1\",\"esi-characters.read_standings.v1\",\"esi-industry.read_character_jobs.v1\",\"esi-markets.read_character_orders.v1\",\"esi-characters.read_blueprints.v1\",\"esi-characters.read_corporation_roles.v1\",\"esi-contracts.read_character_contracts.v1\",\"esi-clones.read_implants.v1\",\"esi-wallet.read_corporation_wallets.v1\",\"esi-corporations.read_divisions.v1\",\"esi-assets.read_corporation_assets.v1\",\"esi-corporations.read_blueprints.v1\",\"esi-contracts.read_corporation_contracts.v1\",\"esi-corporations.read_standings.v1\",\"esi-industry.read_corporation_jobs.v1\",\"esi-markets.read_corporation_orders.v1\",\"esi-corporations.read_container_logs.v1\",\"esi-industry.read_character_mining.v1\",\"esi-industry.read_corporation_mining.v1\",\"esi-planets.read_customs_offices.v1\"]"; for (EsiScopes scope : EsiScopes.values()) { assertTrue(scope.getScope() + " not included", s.contains(scope.getScope())); } } @Test public void testNiKR() { String s = "[\"esi-location.read_location.v1\",\"esi-location.read_ship_type.v1\",\"esi-skills.read_skills.v1\",\"esi-wallet.read_character_wallet.v1\",\"esi-clones.read_clones.v1\",\"esi-universe.read_structures.v1\",\"esi-assets.read_assets.v1\",\"esi-planets.manage_planets.v1\",\"esi-ui.open_window.v1\",\"esi-ui.write_waypoint.v1\",\"esi-markets.structure_markets.v1\",\"esi-characters.read_loyalty.v1\",\"esi-characters.read_standings.v1\",\"esi-industry.read_character_jobs.v1\",\"esi-markets.read_character_orders.v1\",\"esi-characters.read_blueprints.v1\",\"esi-characters.read_corporation_roles.v1\",\"esi-contracts.read_character_contracts.v1\",\"esi-clones.read_implants.v1\",\"esi-wallet.read_corporation_wallets.v1\",\"esi-corporations.read_divisions.v1\",\"esi-assets.read_corporation_assets.v1\",\"esi-corporations.read_blueprints.v1\",\"esi-contracts.read_corporation_contracts.v1\",\"esi-corporations.read_standings.v1\",\"esi-industry.read_corporation_jobs.v1\",\"esi-markets.read_corporation_orders.v1\",\"esi-corporations.read_container_logs.v1\",\"esi-industry.read_character_mining.v1\",\"esi-industry.read_corporation_mining.v1\",\"esi-planets.read_customs_offices.v1\"]"; for (EsiScopes scope : EsiScopes.values()) { assertTrue(scope.getScope() + " not included", s.contains(scope.getScope())); } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/local/AssetAddedReaderTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.File; import java.net.URISyntaxException; import java.net.URL; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.settings.AddedData; import org.junit.Assert; import org.junit.Test; public class AssetAddedReaderTest extends TestUtil { @Test public void testAddedJson() { TestAssetAddedReader.load(); Assert.assertTrue(!AddedData.getAssets().isEmpty()); } private static class TestAssetAddedReader extends AssetAddedReader { public static void load() { try { TestAssetAddedReader assetAddedReader = new TestAssetAddedReader(); URL resource = BackwardCompatibilitySettings.class.getResource("/added.json"); String filename = new File(resource.toURI()).getAbsolutePath(); assetAddedReader.read(filename); } catch (URISyntaxException ex) { Assert.fail(ex.getMessage()); } } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/local/BackupTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.junit.AfterClass; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; public class BackupTest extends TestUtil { private static final Logger LOG = LoggerFactory.getLogger(BackupTest.class); private static File targetFile; private static File bacFile; private static File newFile; private static File getFile(String extension) { return new File(new File(FileUtil.getPathRunJar()).getParentFile().getAbsolutePath() + File.separator + "test." + extension); } @BeforeClass public static void setUpClass() { targetFile = getFile("xml"); newFile = getFile("new"); bacFile = getFile("bac"); } @AfterClass public static void tearDownClass() throws Exception { targetFile.delete(); newFile.delete(); bacFile.delete(); File file; int count = 0; boolean next = true; while (next) { count++; file = getFile("error" + count); next = file.exists(); file.delete(); } } @Test public void testCreateBackup() { LOG.info("testCreateBackup"); cleanUp(); SimpleWriter writer = new SimpleWriter(); SimpleReader reader = new SimpleReader(); //First run assertTrue(writer.write(targetFile, true)); assertTrue(targetFile.exists()); assertFalse(newFile.exists()); assertFalse(bacFile.exists()); assertTrue(reader.read(targetFile)); //Second run assertTrue(writer.write(targetFile, true)); assertTrue(targetFile.exists()); assertFalse(newFile.exists()); assertTrue(bacFile.exists()); assertTrue(reader.read(targetFile)); } @Test public void testRestoreBackup() { LOG.info("testRestoreBackup"); SimpleWriter writer = new SimpleWriter(); SimpleReader reader = new SimpleReader(); SimpleWriterCorrupted writerCorrupted = new SimpleWriterCorrupted(); //Test working cleanUp(); assertTrue(writer.write(targetFile, true)); //xml = OK assertTrue(reader.read(targetFile)); //Read target //Test .new (1 of 2) cleanUp(); writerCorrupted.write(targetFile); //xml = Corrupted assertTrue(writer.write(newFile, false)); //new = OK writerCorrupted.write(bacFile); //bac = Corrupted assertTrue(reader.read(targetFile)); //Read target //Test .new (2 of 2) cleanUp(); writerCorrupted.write(targetFile); //xml = Corrupted assertTrue(writer.write(newFile, false)); //new = OK //bac = Does not exist assertTrue(reader.read(targetFile)); //Read target //Test .bac (1 of 2) cleanUp(); writerCorrupted.write(targetFile); //xml = Corrupted writerCorrupted.write(newFile); //new = Corrupted assertTrue(writer.write(bacFile, false)); //bac = OK assertTrue(reader.read(targetFile)); //Read target //Test .bac (2 of 2) cleanUp(); writerCorrupted.write(targetFile); //xml = Corrupted //new = Does not exist assertTrue(writer.write(bacFile, false)); //bac = OK assertTrue(reader.read(targetFile)); //Read target } @Test public void testCorrupted() { SimpleReader reader = new SimpleReader(); SimpleWriterCorrupted writerCorrupted = new SimpleWriterCorrupted(); //Test All Corrupted cleanUp(); writerCorrupted.write(targetFile); //xml = Corrupted writerCorrupted.write(bacFile); //bac = Corrupted writerCorrupted.write(newFile); //bac = Corrupted assertFalse(reader.read(targetFile)); //Read target //Test bac missing cleanUp(); writerCorrupted.write(targetFile); //xml = Corrupted writerCorrupted.write(newFile); //new = Corrupted //bac = Does not exist assertFalse(reader.read(targetFile)); //Read target //Test new missing cleanUp(); writerCorrupted.write(targetFile); //xml = Corrupted //new = Does not exist writerCorrupted.write(newFile); //bac = Corrupted assertFalse(reader.read(targetFile)); //Read target //Test bac & new missing cleanUp(); writerCorrupted.write(targetFile); //xml = Corrupted //new = Does not exist //bac = Does not exist assertFalse(reader.read(targetFile)); //Read target //Test all missing cleanUp(); //xml = Does not exist //new = Does not exist //bac = Does not exist assertFalse(reader.read(targetFile)); //Read target } private void cleanUp() { if (targetFile.exists()) { targetFile.delete(); } if (newFile.exists()) { newFile.delete(); } if (bacFile.exists()) { bacFile.delete(); } } private static class SimpleWriter extends AbstractXmlWriter { private boolean write(File file, boolean createBackup) { Document xmldoc; try { xmldoc = getXmlDocument("test"); } catch (XmlException ex) { LOG.error(ex.getMessage(), ex); return false; } try { writeXmlFile(xmldoc, file.getAbsolutePath(), createBackup); return true; } catch (XmlException ex) { LOG.error(ex.getMessage(), ex); return false; } } } private static class SimpleWriterCorrupted { private void write(File file) { BufferedWriter writer = null; try { writer = new BufferedWriter(new FileWriter(file)); writer.write("Corrupted"); } catch (Exception ex) { LOG.error(ex.getMessage(), ex); } finally { if (writer != null) { try { writer.close(); } catch (Exception ex) { LOG.error(ex.getMessage(), ex); } } } } } private static class SimpleReader extends AbstractXmlReader { private boolean read(File file) { return read("Simple reader", file.getAbsolutePath(), AbstractXmlReader.XmlType.DYNAMIC); } @Override protected Boolean parse(Element element) throws XmlException { return true; } @Override protected Boolean failValue() { return false; } @Override protected Boolean doNotExistValue() { return false; } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/local/BackwardCompatibilitySettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.awt.Dimension; import java.awt.Point; import java.io.File; import java.net.URISyntaxException; import java.net.URL; import java.util.*; import net.nikr.eve.jeveasset.data.settings.AddedData; import net.nikr.eve.jeveasset.data.settings.ExportSettings; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings; import net.nikr.eve.jeveasset.data.settings.ProxyData; import net.nikr.eve.jeveasset.data.settings.ReprocessSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.Settings.SettingsFactory; import net.nikr.eve.jeveasset.data.settings.StockpileGroupSettings; import net.nikr.eve.jeveasset.data.settings.TrackerData; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.data.settings.tag.Tag; import net.nikr.eve.jeveasset.data.settings.tag.TagID; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog.Formula; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuJumps.Jump; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.View; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewGroup; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile; import net.nikr.eve.jeveasset.tests.mocks.FakeSettings; public class BackwardCompatibilitySettings extends FakeSettings implements SettingsFactory { public enum Function { GET_ASSET_ADDED, GET_EXPORT_SETTINGS, GET_FLAGS, GET_OVERVIEW_GROUPS, GET_OWNERS, GET_PRICE_DATA_SETTINGS, GET_STOCKPILES, GET_TABLE_COLUMNS, GET_TABLE_COLUMNS_WIDTH, GET_TABLE_FILTERS, GET_TABLE_FILTERS_KEY, GET_TABLE_RESIZE, GET_TABLE_VIEWS, GET_TABLE_FORMULAS, GET_TABLE_JUMPS, GET_TAGS, GET_TAGS_ID, GET_TRACKER_DATA, GET_USER_ITEM_NAMES, GET_USER_PRICES, SET_MAXIMUM_PURCHASE_AGE, SET_TRANSACTION_PROFIT_PRICE, SET_TRANSACTION_PROFIT_MARGIN, SET_PRICE_DATA_SETTINGS, SET_PROXY_DATA, SET_REPROCESS_SETTINGS, SET_WINDOW_ALWAYS_ON_TOP, SET_WINDOW_AUTO_SAVE, SET_WINDOW_LOCATION, SET_WINDOW_MAXIMIZED, SET_WINDOW_SIZE, } private final String settingsPath; private final String name; private final Map ok = new EnumMap<>(Function.class); private final List tested = new ArrayList<>(); private boolean settingsLoadError; public BackwardCompatibilitySettings() { for (Function function : Function.values()) { ok.put(function, false); } this.settingsPath = null; this.name = null; } public BackwardCompatibilitySettings(final String name) throws URISyntaxException { this.name = name; for (Function function : Function.values()) { ok.put(function, false); } URL resource = BackwardCompatibilitySettings.class.getResource("/" + name + "/settings.xml"); settingsPath = new File(resource.toURI()).getAbsolutePath(); } @Override public Settings create() { return this; } @Override public boolean isSettingsLoadError() { return settingsLoadError; } @Override public void setSettingsLoadError(boolean settingsLoadError) { this.settingsLoadError = settingsLoadError; } public boolean test(Function function) { if (tested.contains(function)) { throw new UnsupportedOperationException("Double test of: "+function.name()); } else { tested.add(function); } switch (function) { case GET_TRACKER_DATA: try { TrackerData.readLock(); return !TrackerData.get().isEmpty(); } finally { TrackerData.readUnlock(); } case GET_ASSET_ADDED: return !AddedData.getAssets().isEmpty(); default: return ok.get(function); } } public List test() { List functions = new ArrayList<>(); for (Function key : Function.values()) { boolean wasOk = ok.get(key); boolean wasTested = tested.contains(key); if (wasOk && !wasTested) { functions.add(key); } } return functions; } public String getName() { return name.replace("data-", "").replace("-", "."); } @Override public Map getExportSettings() { ok.put(Function.GET_EXPORT_SETTINGS, true); return new HashMap<>(); } @Override public Map getFlags() { ok.put(Function.GET_FLAGS, true); return new EnumMap<>(SettingFlag.class); } @Override public Map getOverviewGroups() { ok.put(Function.GET_OVERVIEW_GROUPS, true); return new HashMap<>(); } @Override public Map getOwners() { ok.put(Function.GET_OWNERS, true); return new HashMap<>(); } @Override public Map getOwnersNextUpdate() { return new HashMap<>(); } @Override public PriceDataSettings getPriceDataSettings() { ok.put(Function.GET_PRICE_DATA_SETTINGS, true); return new PriceDataSettings(); } public String getPathSettings() { return settingsPath; } @Override public List getStockpiles() { ok.put(Function.GET_STOCKPILES, true); return new ArrayList<>(); } @Override public Map> getTableColumns() { ok.put(Function.GET_TABLE_COLUMNS, true); return new HashMap<>(); } @Override public Map> getTableColumnsWidth() { ok.put(Function.GET_TABLE_COLUMNS_WIDTH, true); return new HashMap<>(); } @Override public Map>> getTableFilters() { ok.put(Function.GET_TABLE_FILTERS, true); return new HashMap<>(); } @Override public Map> getTableFilters(final String key) { ok.put(Function.GET_TABLE_FILTERS_KEY, true); return new HashMap<>(); } @Override public Map getTableResize() { ok.put(Function.GET_TABLE_RESIZE, true); return new HashMap<>(); } @Override public Map> getTableViews() { ok.put(Function.GET_TABLE_VIEWS, true); return new HashMap<>(); } @Override public Map getTags() { ok.put(Function.GET_TAGS, true); return new HashMap<>(); } @Override public Tags getTags(TagID tagID) { ok.put(Function.GET_TAGS_ID, true); return new Tags(); } @Override public Map> getUserItemNames() { ok.put(Function.GET_USER_ITEM_NAMES, true); return new HashMap<>(); } @Override public Map> getUserPrices() { ok.put(Function.GET_USER_PRICES, true); return new HashMap<>(); } @Override public void setMaximumPurchaseAge(int maximumPurchaseAge) { ok.put(Function.SET_MAXIMUM_PURCHASE_AGE, true); } @Override public void setTransactionProfitPrice(TransactionProfitPrice transactionProfitPrice) { ok.put(Function.SET_TRANSACTION_PROFIT_PRICE, true); } @Override public void setTransactionProfitMargin(int transactionProfitMargin) { ok.put(Function.SET_TRANSACTION_PROFIT_MARGIN, true); } @Override public void setPriceDataSettings(final PriceDataSettings priceDataSettings) { ok.put(Function.SET_PRICE_DATA_SETTINGS, true); } @Override public void setProxyData(ProxyData proxyData) { ok.put(Function.SET_PROXY_DATA, true); } @Override public void setReprocessSettings(final ReprocessSettings reprocessSettings) { ok.put(Function.SET_REPROCESS_SETTINGS, true); } @Override public void setWindowAlwaysOnTop(final boolean windowAlwaysOnTop) { ok.put(Function.SET_WINDOW_ALWAYS_ON_TOP, true); } @Override public void setWindowAutoSave(final boolean windowAutoSave) { ok.put(Function.SET_WINDOW_AUTO_SAVE, true); } @Override public void setWindowLocation(final Point windowLocation) { ok.put(Function.SET_WINDOW_LOCATION, true); } @Override public void setWindowMaximized(final boolean windowMaximized) { ok.put(Function.SET_WINDOW_MAXIMIZED, true); } @Override public void setWindowSize(final Dimension windowSize) { ok.put(Function.SET_WINDOW_SIZE, true); } @Override public List getTableFormulas(String name) { ok.put(Function.GET_TABLE_FORMULAS, true); return new ArrayList<>(); } @Override public List getTableJumps(String toolName) { ok.put(Function.GET_TABLE_JUMPS, true); return new ArrayList<>(); } @Override public StockpileGroupSettings getStockpileGroupSettings() { return new StockpileGroupSettings(); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/local/FileLockSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.File; import java.net.URISyntaxException; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.Settings.SettingsFactory; public class FileLockSettings extends Settings implements SettingsFactory { private static final String SETTINGS = "settings_test"; private static final String TIMEOUT = "timeout"; private static final String XML = ".xml"; private static final String BAC = ".bac"; private static final String ERROR = ".error1"; public FileLockSettings() { super(); } @Override public Settings create() { return new FileLockSettings(); } public String getPathSettings() { return getPath(SETTINGS+XML); } public static String getPathSettingsBackup() { return getPath(SETTINGS+BAC); } public static String getPathSettingsVersionBackup() { return getVersionBackup(getPath(SETTINGS+XML)); } public static String getPathSettingsStatic() { return getPath(SETTINGS+XML); } public static String getPathSettingsError() { return getPath(SETTINGS+ERROR); } public static String getPathTimeout() { return getPath(TIMEOUT); } private static String getVersionBackup(String filename) { return filename.substring(0, filename.lastIndexOf(".")) + "_" + Program.PROGRAM_VERSION.replaceAll(" ", "_") + "_backup.zip"; } private static String getPath(String filename) { try { File file; File ret; file = new File(net.nikr.eve.jeveasset.Program.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParentFile(); ret = new File(file.getAbsolutePath() + File.separator + filename); return ret.getAbsolutePath(); } catch (URISyntaxException ex) { return null; } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/local/FileLockTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import ch.qos.logback.classic.Level; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.io.local.FileLock.SafeFileIO; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.junit.AfterClass; import static org.junit.Assert.assertFalse; import org.junit.BeforeClass; import org.junit.Test; public class FileLockTest extends TestUtil { @BeforeClass public static void setUpClass() throws Exception { setLoggingLevel(Level.OFF); } @AfterClass public static void tearDownClass() throws Exception { setLoggingLevel(Level.INFO); //Cleanup File settings = new File(FileLockSettings.getPathSettingsStatic()); File settingsBackup = new File(FileLockSettings.getPathSettingsBackup()); File settingsVersionBackup = new File(FileLockSettings.getPathSettingsVersionBackup()); File settingsError = new File(FileLockSettings.getPathSettingsError()); File timeout = new File(FileLockSettings.getPathTimeout()); settings.delete(); settingsBackup.delete(); settingsVersionBackup.delete(); settingsError.delete(); timeout.delete(); } private static class LoadSettings extends Thread implements TestThread { private final FileLockSettings settings; public LoadSettings(FileLockSettings settings) { this.settings = settings; } @Override public void run() { SettingsReader.load(settings, settings.getPathSettings()); } @Override public Boolean isOk() { return !settings.isSettingsLoadError(); } } private static class SaveSettings extends Thread implements TestThread { private final FileLockSettings settings; private Boolean ok = null; public SaveSettings(FileLockSettings settings) { this.settings = settings; } @Override public void run() { ok = SettingsWriter.save(settings, settings.getPathSettings()); } @Override public Boolean isOk() { return ok; } } //@Test public void timeoutTest() throws IOException { File file = new File(FileLockSettings.getPathTimeout()); try (SafeFileIO aLock = new SafeFileIO(file); SafeFileIO bLock = new SafeFileIO(file);){ aLock.getFileInputStream(); bLock.getFileInputStream(); } } @Test public void restoreBackupSettingsTest() throws IOException { FileLockSettings settings = new FileLockSettings(); File file = new File (settings.getPathSettings()); boolean saved; saved = SettingsWriter.save(settings, settings.getPathSettings()); assertTrue("LockTest: Backup - Save settings failed (1 of 2)", saved); saved = SettingsWriter.save(settings, settings.getPathSettings()); assertTrue("LockTest: Backup - Save settings failed (2 of 2)", saved); boolean deleted = file.delete(); assertTrue("LockTest: Backup - Delete settings failed", deleted); boolean created = file.createNewFile(); assertTrue("LockTest: Backup - Create settings failed", created); System.out.println("\"Premature end of file\": Is an expected error:"); SettingsReader.load(settings, settings.getPathSettings()); assertFalse("LockTest: Backup - Load settings failed", settings.isSettingsLoadError()); } @Test public void unlockAllTest() throws IOException { List files = new ArrayList<>(); File items = new File(FileUtil.getPathItems()); files.add(items); File flags = new File(FileUtil.getPathFlags()); files.add(flags); File jumps = new File(FileUtil.getPathJumps()); files.add(jumps); File locations = new File(FileUtil.getPathLocations()); files.add(locations); File profile = new File(FileUtil.getPathProfilesDirectory() + File.separator + "some_test_profile.xml"); profile.getParentFile().mkdirs(); profile.createNewFile(); files.add(profile); File conquerableStations = new File(FileUtil.getPathConquerableStations()); files.add(conquerableStations); boolean emptyConquerableStations = false; if (!conquerableStations.exists()) { conquerableStations.createNewFile(); emptyConquerableStations = true; } try (SafeFileIO itemsLock = new SafeFileIO(items); SafeFileIO flagsLock = new SafeFileIO(flags); SafeFileIO jumpsLock = new SafeFileIO(jumps); SafeFileIO locationsLock = new SafeFileIO(locations); SafeFileIO profileLock = new SafeFileIO(profile); SafeFileIO conquerableStationsLock = new SafeFileIO(conquerableStations); ){ itemsLock.getFileInputStream(); flagsLock.getFileInputStream(); jumpsLock.getFileInputStream(); locationsLock.getFileInputStream(); profileLock.getFileInputStream(); conquerableStationsLock.getFileInputStream(); //Data directory FileLock.unlockAll(); for (File file : files) { if (FileLock.isLocked(file)) { fail(file.getName() + " was not unlocked by unlockAll"); } } } finally { profile.delete(); if (emptyConquerableStations) { conquerableStations.delete(); } } } @Test public void settingsLockTest() throws InterruptedException { //Setup FileLockSettings settings = new FileLockSettings(); boolean ok = SettingsWriter.save(settings, settings.getPathSettings()); assertTrue("LockTest: Setup failed", ok); //Load TestThread load1 = new LoadSettings(settings); TestThread load2 = new LoadSettings(settings); load1.start(); load2.start(); try { load2.join(); load1.join(); } catch (InterruptedException ex) { fail("Thread Interrupted"); } assertTrue(load1.isOk()); assertTrue(load2.isOk()); //Save TestThread save1 = new SaveSettings(settings); TestThread save2 = new SaveSettings(settings); save1.start(); save2.start(); try { save1.join(); save2.join(); } catch (InterruptedException ex) { fail("Thread Interrupted"); } assertTrue(save1.isOk()); assertTrue(save2.isOk()); //Save & Load TestThread load = new LoadSettings(settings); TestThread save = new SaveSettings(settings); load.start(); save.start(); try { //wait load.join(); save.join(); } catch (InterruptedException ex) { fail("Thread Interrupted"); } assertTrue(load.isOk()); assertTrue(save.isOk()); //Chaos! :D List threads = new ArrayList<>(); for (int i = 0; i < 8; i++) { threads.add(new SaveSettings(settings)); } for (int i = 0; i < 8; i++) { threads.add(new LoadSettings(settings)); } for (TestThread thread : threads) { thread.start(); } for (TestThread thread : threads) { thread.join(); } for (TestThread thread : threads) { assertTrue(thread.isOk()); } } public static interface TestThread { public Boolean isOk(); public void start(); public void join() throws InterruptedException; } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/local/ItemFlagsTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.sde.StaticData; import static org.junit.Assert.assertEquals; import org.junit.Test; public class ItemFlagsTest extends TestUtil { @Test public void testItemFlags() { assertEquals(141, StaticData.get().getItemFlags().size()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/local/ProfileReadWriteTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import ch.qos.logback.classic.Level; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.profile.Profile; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.settings.AddedData; import net.nikr.eve.jeveasset.io.shared.ConverterTestOptions; import net.nikr.eve.jeveasset.io.shared.ConverterTestOptionsGetter; import net.nikr.eve.jeveasset.io.shared.ConverterTestUtil; import org.junit.AfterClass; import static org.junit.Assert.assertEquals; import org.junit.BeforeClass; import org.junit.Test; public class ProfileReadWriteTest extends TestUtil { @BeforeClass public static void setUpClass() { setLoggingLevel(Level.WARN); } @AfterClass public static void tearDownClass() { setLoggingLevel(Level.INFO); } @Test public void testNotNull() { test(false); } @Test public void testNull() { test(true); } private void test(boolean setNull) { AddedData.load(); for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { //Clear previouse test data cleanup(); Profile saveProfile = new Profile(); //ESI saveProfile.getEsiOwners().add(ConverterTestUtil.getEsiOwner(true, setNull, false, options)); //Write saveProfile.save(); //Read ProfileManager loadProfileManager = new ProfileManager(); Profile loadProfile = new Profile(); loadProfile.load(); loadProfileManager.setActiveProfile(loadProfile); //Update dynamic data ProfileData profileData = new ProfileData(loadProfileManager); profileData.updateEventLists(); //ESI assertEquals(1, loadProfile.getEsiOwners().size()); EsiOwner esiOwner = loadProfile.getEsiOwners().get(0); ConverterTestUtil.testOwner(esiOwner, setNull, options); } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/local/SettingsTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import ch.qos.logback.classic.Level; import java.io.File; import java.net.URISyntaxException; import java.net.URL; import java.util.List; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.Settings.SettingFlag; import net.nikr.eve.jeveasset.data.settings.Settings.SettingsFactory; import net.nikr.eve.jeveasset.io.local.BackwardCompatibilitySettings.Function; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import org.junit.AfterClass; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.BeforeClass; import org.junit.Test; public class SettingsTest extends TestUtil { @BeforeClass public static void setUpClass() throws Exception { setLoggingLevel(Level.OFF); } @AfterClass public static void tearDownClass() throws Exception { setLoggingLevel(Level.INFO); } private void test(BackwardCompatibilitySettings settings, Function function) { assertTrue(settings.getName() + " failed test for " + function.name(), settings.test(function)); } private void test(BackwardCompatibilitySettings settings) { List test = settings.test(); assertEquals(settings.getName() + " is missing tests for: " + test.toString(), 0, test.size()); String filename = settings.getPathSettings(); File file = new File(filename.substring(0, filename.lastIndexOf(".")) + "_" + Program.PROGRAM_VERSION.replaceAll(" ", "_") + "_backup.zip"); assertTrue(file.delete()); } @Test public void flagsTest() throws URISyntaxException { Settings settings = new TestSettings(); for (SettingFlag settingFlag : SettingFlag.values()) { assertTrue(settingFlag.name() + " is missing from default settings", settings.getFlags().containsKey(settingFlag)); } } @Test public void backwardCompatibility100() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-0-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings); } @Test public void backwardCompatibility110() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-1-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings); } @Test public void backwardCompatibility120() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-2-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility121() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-2-1"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility122() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-2-2"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility123() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-2-3"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility130() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-3-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility140() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-4-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility141() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-4-1"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility150() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-5-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility160() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-6-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility161() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-6-1"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility162() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-6-2"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility163() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-6-3"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility164() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-6-4"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility170() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-7-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility171() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-7-1"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility172() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-7-2"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility173() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-7-3"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility180() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-8-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility181() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-8-1"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility190() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-9-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_STOCKPILES); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility191() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-9-1"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_STOCKPILES); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility192() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-1-9-2"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_STOCKPILES); test(settings, Function.GET_TABLE_FILTERS_KEY); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility200() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-2-0-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_STOCKPILES); test(settings, Function.GET_TABLE_COLUMNS); test(settings, Function.GET_TABLE_FILTERS); test(settings, Function.GET_TABLE_FORMULAS); test(settings, Function.GET_TABLE_JUMPS); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility210() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-2-1-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_STOCKPILES); test(settings, Function.GET_TABLE_COLUMNS); test(settings, Function.GET_TABLE_FILTERS); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility211() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-2-1-1"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_STOCKPILES); test(settings, Function.GET_TABLE_COLUMNS); test(settings, Function.GET_TABLE_FILTERS); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility212() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-2-1-2"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_STOCKPILES); test(settings, Function.GET_TABLE_COLUMNS); test(settings, Function.GET_TABLE_FILTERS); test(settings, Function.GET_TABLE_FORMULAS); test(settings, Function.GET_TABLE_JUMPS); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility220() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-2-2-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_STOCKPILES); test(settings, Function.GET_TABLE_COLUMNS); test(settings, Function.GET_TABLE_FILTERS); test(settings, Function.GET_TABLE_RESIZE); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility230() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-2-3-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_STOCKPILES); test(settings, Function.GET_TABLE_COLUMNS); test(settings, Function.GET_TABLE_FILTERS); test(settings, Function.GET_TABLE_RESIZE); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings); } @Test public void backwardCompatibility240() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-2-4-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_STOCKPILES); test(settings, Function.GET_TABLE_COLUMNS); test(settings, Function.GET_TABLE_COLUMNS_WIDTH); test(settings, Function.GET_TABLE_FILTERS); test(settings, Function.GET_TABLE_RESIZE); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_MAXIMUM_PURCHASE_AGE); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings, Function.SET_TRANSACTION_PROFIT_PRICE); test(settings, Function.SET_TRANSACTION_PROFIT_MARGIN); test(settings); } @Test public void backwardCompatibility250() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-2-5-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_ASSET_ADDED); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_OWNERS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_STOCKPILES); test(settings, Function.GET_TABLE_COLUMNS); test(settings, Function.GET_TABLE_COLUMNS_WIDTH); test(settings, Function.GET_TABLE_FILTERS); test(settings, Function.GET_TABLE_RESIZE); test(settings, Function.GET_TRACKER_DATA); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_MAXIMUM_PURCHASE_AGE); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings, Function.SET_TRANSACTION_PROFIT_PRICE); test(settings, Function.SET_TRANSACTION_PROFIT_MARGIN); test(settings); } @Test public void backwardCompatibility260() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-2-6-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_ASSET_ADDED); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_OWNERS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_STOCKPILES); test(settings, Function.GET_TABLE_COLUMNS); test(settings, Function.GET_TABLE_COLUMNS_WIDTH); test(settings, Function.GET_TABLE_FILTERS); test(settings, Function.GET_TABLE_RESIZE); test(settings, Function.GET_TRACKER_DATA); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_MAXIMUM_PURCHASE_AGE); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings, Function.SET_TRANSACTION_PROFIT_PRICE); test(settings, Function.SET_TRANSACTION_PROFIT_MARGIN); test(settings); } @Test public void backwardCompatibility270() throws URISyntaxException { BackwardCompatibilitySettings settings = new BackwardCompatibilitySettings("data-2-7-0"); SettingsReader.load(settings, settings.getPathSettings()); test(settings, Function.GET_ASSET_ADDED); test(settings, Function.GET_EXPORT_SETTINGS); test(settings, Function.GET_FLAGS); test(settings, Function.GET_OVERVIEW_GROUPS); test(settings, Function.GET_OWNERS); test(settings, Function.GET_PRICE_DATA_SETTINGS); test(settings, Function.GET_STOCKPILES); test(settings, Function.GET_TABLE_COLUMNS); test(settings, Function.GET_TABLE_COLUMNS_WIDTH); test(settings, Function.GET_TABLE_FILTERS); test(settings, Function.GET_TABLE_RESIZE); test(settings, Function.GET_TABLE_VIEWS); test(settings, Function.GET_TAGS); test(settings, Function.GET_TAGS_ID); test(settings, Function.GET_TRACKER_DATA); test(settings, Function.GET_USER_ITEM_NAMES); test(settings, Function.GET_USER_PRICES); test(settings, Function.SET_MAXIMUM_PURCHASE_AGE); test(settings, Function.SET_PRICE_DATA_SETTINGS); test(settings, Function.SET_PROXY_DATA); test(settings, Function.SET_REPROCESS_SETTINGS); test(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); test(settings, Function.SET_WINDOW_AUTO_SAVE); test(settings, Function.SET_WINDOW_LOCATION); test(settings, Function.SET_WINDOW_MAXIMIZED); test(settings, Function.SET_WINDOW_SIZE); test(settings, Function.SET_TRANSACTION_PROFIT_PRICE); test(settings, Function.SET_TRANSACTION_PROFIT_MARGIN); test(settings); } private void testFail(BackwardCompatibilitySettings settings, Function function) { assertFalse("failTest failed test for " + function.name(), settings.test(function)); } @Test public void failTest() throws URISyntaxException { SettingsFactoryError factoryError = new SettingsFactoryError(); URL resource = BackwardCompatibilitySettings.class.getResource("/data-fail/settings.xml"); File file = new File(resource.toURI()); BackwardCompatibilitySettings settings = (BackwardCompatibilitySettings) SettingsReader.load(factoryError, file.getAbsolutePath()); assertThat(settings.isSettingsLoadError(), equalTo(true)); testFail(settings, Function.GET_EXPORT_SETTINGS); testFail(settings, Function.GET_FLAGS); testFail(settings, Function.GET_OVERVIEW_GROUPS); testFail(settings, Function.GET_OWNERS); testFail(settings, Function.GET_PRICE_DATA_SETTINGS); testFail(settings, Function.GET_STOCKPILES); testFail(settings, Function.GET_TABLE_COLUMNS); testFail(settings, Function.GET_TABLE_COLUMNS_WIDTH); testFail(settings, Function.GET_TABLE_FILTERS); testFail(settings, Function.GET_TABLE_RESIZE); testFail(settings, Function.GET_TABLE_VIEWS); testFail(settings, Function.GET_TAGS); testFail(settings, Function.GET_TAGS_ID); testFail(settings, Function.GET_USER_ITEM_NAMES); testFail(settings, Function.GET_USER_PRICES); testFail(settings, Function.SET_MAXIMUM_PURCHASE_AGE); testFail(settings, Function.SET_PRICE_DATA_SETTINGS); testFail(settings, Function.SET_PROXY_DATA); testFail(settings, Function.SET_REPROCESS_SETTINGS); testFail(settings, Function.SET_WINDOW_ALWAYS_ON_TOP); testFail(settings, Function.SET_WINDOW_AUTO_SAVE); testFail(settings, Function.SET_WINDOW_LOCATION); testFail(settings, Function.SET_WINDOW_MAXIMIZED); testFail(settings, Function.SET_WINDOW_SIZE); } private static class TestSettings extends Settings { public TestSettings() { super(); } } private class SettingsFactoryError implements SettingsFactory { @Override public Settings create() { return new BackwardCompatibilitySettings(); } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/local/StockpileDataReadWriteTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.File; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileContainer; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile.StockpileFilter.StockpileFlag; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Test; public class StockpileDataReadWriteTest extends TestUtil { @Test public void testText() { System.out.println("testText"); testIO(new SaveLoad() { @Override public List saveAndLoad(List stockpiles) { String data = StockpileWriter.save(stockpiles); System.out.println(data); return StockpileReader.load(data); } }); } @Test public void testXml() { System.out.println("testXml"); testIO(new SaveLoad() { int i = 0; @Override public List saveAndLoad(List stockpiles) { String filename = "stockpile_test_" + i + ".xml"; i++; SettingsWriter.saveStockpiles(stockpiles, filename); List rStockpile = SettingsReader.loadStockpile(filename); File file = new File(filename); assertTrue(file.exists()); assertTrue(file.delete()); return rStockpile; } }); } @Test public void testText740() { System.out.println("testText740"); final String[] data = new String[12]; data[0] = "eNpNj0EOgyAQRe_y16SxiiZwiG66JC4EMcGKNEVXxrs72lZkM483ZPijFoyQeE7BvN5usI_GWzB4yOqWMRjfQE6f2TLEDlItoHvXDJGE1iZxwnjBC-uQdEI9JZvQ_v_sT9W3AyTfK0Ur6fXZcS1kkdG585wCHyENFcRZR1rFme-0lf38GC6dY8haM-zb5awgonRKlLwquRD13nIkCDYsblqG"; data[1] = "eNpNj7sOgzAMRf_lzlFFISAlH9GlI2IgIUhpeVRNmBD_jkMfJotPji3rul4xQeMeZ_t8-cHd2tFBYISuLpmAHVvo-F6cQOih6xX079shkDDGMjOGE57YzKwZTWTL6P70YOoGaJkqZStp_JfLd9BFRu8qcwp8hLRUEBYT6BRvP5Ob-PppPnWO7VsjkK7LRUFE6WpVyqqUSjWp5UkQ7CyBWoY="; data[2] = "eNpNj0EOgyAQRe_y16SxiibOIbrp0rgQxIQWtCm6Mt7dwTYim3n8T8ibZsUIwnOe9PtjnXl03kDAg6pbJqB9B5q_ixEIA6hZcd6V0qChcyFywnDBC6spxQnVnNKE5qRXot6BZJysVvLzs7E9qMj43GXOwoek5oGwqMCrWP0z3sQ_H6dLc3yytQJxu1wUTKzX1KWsSlnXbawsBww7L19ahg=="; data[3] = "eNpNj8EOgyAQRP9lzqSxiibwEb30aDwAYkIr0hQ8Gf-9q21FLvt2huzOtgsmSNxTMM-XG-1NeQsGD9lcCgbjFWR6z5YhDpDtAuoHNUYStDaZM8YTnliHLIf_TJ2ymNEe9MjUj5B8qxStpu-H43rIqqB35SUF3kMaKoizjnSKM99tK_vpUzg5-5C1Y9iuK1lFROlaUfOm5kJ0m-VIIPgALU9ahg=="; data[4] = "eNpNj8EOgyAQRP9lzqSxCibwEb30aDwIYkKL0hQ9Gf_dxTYil33MbHZnmxUTFJ5zMO-P8_bRjRYMI1R9KxjM2EHN38UyxAGqWUH_ofORBK1N5ozxghfW4RwUsjjn3oz2pFem3kPxVCmaoPbTcT1UVdC785ICHyENFcRFRzrFmd_ijf31KVycY8jWMqTrSlYRUbxGCl4LLmWbLEcCwQ4trVqG"; data[5] = "eNpNjzEOgzAMRe_y56iiEJCSQ3TpGDGQEKRQQqoGJsTdMbQlePHzt2V_qwUjJJ5TMK-3G-yj8RYMHrK6ZQzGN5DTZ7YMsYNUC6jumiGSoLVJnDBe8MI6JDmhnpKa0J7U_6_37QDJ90zWSpo-R1wLWWQUd56T4cOkoYQ460ivOPPdsbKfPoZL51iy1gz7dzkriMidEiWvSi5EvbccCQQbLD1ahg=="; data[6] = "eNpNj8EOgyAQRP9lzqSxiibwEb30aDwAYkKL2hQ8Gf_d1TYgl307Q3Zn2xUTJJ5xNu-P8_ahRguGEbK5FQxmVJDxu1iGMEC2K6gflA8kaG0yZwwXvLCes5xRxzQ-JtEmemXqPSQ_KkWr6XtyXA9ZFfTuvKTAZ0hDBWHRgU5x5rdiY399mi_OOWTrGI7rSlYRUbpW1LypuRDdYTkSCHYs_VqG"; data[7] = "eNpNj0EOgyAQRe_y16SxCiZwiG66NC4AMaFVaQqujHfvaFuRzTzekOFPs2CCwj0F-3z5wd306MAwQtWXgsGOGiq9Z8cQe6hmAd17PUQSxtjMGeMJT2xC1hlNyjb9f3KHe2TqBii-VYom6PXR8R1UVdC58pIC7yEtFcTZRFrF2-_clf38FE6dfcjaMmzblawionSNFLwWXMp2a3kSBB8smlqG"; data[8] = "eNpNj80OgyAQhN9lzqSxiibyEL30aDwIYkLrT1PwZHx3F2NYuezHzEBmmw0zFN5hMd-fG-2rmywEJqjqkQmYqYMK_9UK-AGq2UD3oRs9CVobZkZv0gt_CywcYNSBVUab6MPUj1AyTqpWUjw5rocqMjpPmVPhs6ShAb9qT6u4q88uLn1ebs75yd4KxO1yURBRvaYuZVXKum6j5UggOAAudFqG"; data[9] = "eNpNj7EOgzAMRP_l5qiiEJCSj-jSETGQEKS0BKoGJsS_16EI48Uvd3Z0rleM0HjOk31__OAebXAQCNDVLROwoYWev4sTiD10vYLefTtEEoyxzIzxgon_22ZildHMrDK6k15M3QAtU6doJY2fju-gi4zqLnMKvIe01BAXE-kUf2TYxKGP08XZP9kagXRdLgoiilerUlalVKpJlieB4Act-lqG"; data[10] = "eNpNj7sOgzAMRf_lzlFFISCRj-jSETGQEKS0PKomTIh_x0EoJotPji3rutkwQ-EdFvP9udG-uslCYIKqHpmAmTqo8F-tgB-gmg30H7rRk9DaMJs0xtLfWC-sGXVgy2gTfZj6EUrGStFKGk8d10MVGb2nzCnwGdJQgV-1p1PcFW0Xl5-XW-dcsrcC8bpcFEQUr6lLWZWyrtvYciQIDi7GWoY="; data[11] = "eNpNj8sOgyAQRf_lrkljFU2cj-imS-MCEBNaH03BlfHfOxgrspnDuYTcaVZMIDzDbN4fN9iHGi0ERlB1ywTMqEDhu1gB34OaFXzv1eBZaG3-WaTD-gteWM9JJ9Qh2YT2pFeibgDJOLlayc_PxHWgIuNzlzkX3ksaHvCL9ryKO1pu4vDTfEn2T7ZWIG6Xi4KJ6zV1KatS1nUbI8eC4QcvB1qG"; boolean[] b = new boolean[12]; for (int i = 0; i < b.length; i++) { b[i] = false; } int last = -1; for (int i = 0; i < b.length; i++) { b[i] = true; System.out.println("Testing index: " + i); if (last > -1) { b[last] = false; } last = i; final int index = i; testIO(true, new SaveLoad() { @Override public List saveAndLoad(List stockpiles) { return StockpileReader.load(data[index]); } }, b); } } @Test public void testXml740() { System.out.println("testXml740"); boolean[] b = new boolean[12]; for (int i = 0; i < b.length; i++) { b[i] = false; } int last = -1; for (int i = 0; i < b.length; i++) { b[i] = true; System.out.println("Testing index: " + i); if (last > -1) { b[last] = false; } last = i; final int index = i; testIO(true, new SaveLoad() { @Override public List saveAndLoad(List stockpiles) { String filename; try { filename = new File(StockpileDataReadWriteTest.class.getResource("/740/" + "stockpile_test_" + index + ".xml").toURI()).getAbsolutePath(); } catch (URISyntaxException ex) { throw new RuntimeException(ex); } return SettingsReader.loadStockpile(filename); } }, b); } } @Test public void testXml750() { System.out.println("testXml750"); boolean[] b = new boolean[12]; for (int i = 0; i < b.length; i++) { b[i] = false; } int last = -1; for (int i = 0; i < b.length; i++) { b[i] = true; System.out.println("Testing index: " + i); if (last > -1) { b[last] = false; } last = i; final int index = i; testIO(false, new SaveLoad() { @Override public List saveAndLoad(List stockpiles) { String filename; try { filename = new File(StockpileDataReadWriteTest.class.getResource("/750/" + "stockpile_test_" + index + ".xml").toURI()).getAbsolutePath(); } catch (URISyntaxException ex) { throw new RuntimeException(ex); } return SettingsReader.loadStockpile(filename); } }, b); } } @Test public void testText750() { System.out.println("testText750"); final String[] data = new String[12]; data[0] = "eNpdj8EOgyAMht_lP5PFKZrIQ-yyo_EgiAlOdBl4Mr77qm7CxqUfX0tpqwUjBO5-Uo-nGfStsRoMFqK4JAzKNhD-NWsG10FUC-jeNYMjIaUKHNBFGLGcgg4ofbAB9ffP_lR9O0DwLdJoOVWfGdNCZAmdK09p4H1IRQFulo5WMerotrKPH6coszdZa4Zju45C-vtmU9lfMS1QlTkvcl6W9SYMCYI3gotlwQ=="; data[1] = "eNpdj8sOgjAQRf_lrhuDUEjaj3DjkrCgpU2qPIyFFeHfHUAdtJs5PZ1p7pQzemhcx8HeH6F1l7pzEOigi1MiYLsaenxOTiB66HIG3X3dRhLGWGbGeMADm4E1oxnZMrov3ZiaFlqulbLl1P7JFRroLKFzlikF3kJaKoiTibRKsHvnIt6-Hw4v2-9LJbBv56mkvzOryv6aaYFS5bLIpVLVKgIJgheCnmXB"; data[2] = "eNpdj80OgyAQhN9lzqSxiibuQ_TSo_EgiAmtP03Bk_Hdu2gjtlzmY3YhM9WCEYS7n_TzZXtzawYDgQFUXBIBPTQg_56NgOtA1YLjrpQGdU3vAkd0JzyxmqIdUfnoRjQHPSK1PUgG5Wg5rx8T24KyhM9Vphx4C6lZ4GbluIrVe-JVfP1xOk22T9ZaYG_XsaS_b4KV_S1zg6rMZZHLsqyDYdlg-ACFfGXB"; data[3] = "eNpdj8EOgyAMht_lP5PFKZrAQ-yyo_EgCAmbyjL0ZHx3q27ixqUfX0tpywk9JO6D18-Xa82t7gwYOsjikjDoroYc3qNhCBaynEB3W7eBhFI6csRwwhMrH7X_9lRDlBHNQY9ITQvJ10ij5VR-ZFwDmSV0rjylgbchNQWEUQVaxen9t5l9fO9Pma3JXDHs21kK6e-bVWV_xbRAKXJe5FyIahWOBMECg2xlwQ=="; data[4] = "eNpdj8EOgyAQRP9lzqSxiibyEb30aDwIYkIL0hQ8Gf-9qzZiy2Ufs8Oy08wYIXCPXj1fxupb5zQYHER1yRiU6yDie9IMYYBoZtB96GwgQUqVOGE44YmlPwb5JMbkTagPeiTqLQRfK61Wkv3omB6iyOhceU4Lb0sqKgiTDBTFqP3jhX310Z8625ClZdjTDVTy3zerVPyZKUFTl7wqeV23q2BIIPgAg8plwQ=="; data[5] = "eNpdj8EOgyAMht_lP5PFKZrIQ-yyo_EgiAlOdBl4Mr77qm7CxqUfH21pqwUjBO5-Uo-nGfStsRoMFqK4JAzKNhD-NWsG10FUC-jeNYMjIaUKHNBFGLGcgg4ofbAB9Un99_e-HSD4Fmm0nLLPFNNCZAmdK09p4H1IRQFulo5WMerosbKPH6foZW-y1gzHdh2F9LdmU9lfMi1QlTkvcl6W9SYMCYI3glplwQ=="; data[6] = "eNpdj00OgyAQRu_yrUljFU3kEN10aVwIQkLrT1NwZbx7B23Als083gzDTLNigsDdz-r5soO-daMGwwhRXTIGNXYQ_r1oBmcgmhV0N93gSEipEid0JzyxnJNOKH1s76PUkR6J-gGCh0ijlVQeM7aHKDI6V57TwPuQigLcIh2tYtXxxca-fppPmb3J1jIc2xkK-e-boIq_YlqgqUtelbyu2yAsCYIPgxplwQ=="; data[7] = "eNpdj8EOgyAMht_lP5PFKZrIQ-yyo_EgiAkb6DLwZHx3q27ixqUfX0tpqwk9BO5hUM-XsfrWOA0GB1FcEgblGojwHjWD7yCqCXTvGutJSKkiR_QnPLEcoo4oQ7Th-5M-3CNSayH4Gmm0nKqPjGkhsoTOlac08DakogA_Sk-rGLX3ndnH98MpszWZa4Z9u45C-vtmVdlfMS1QlTkvcl6W9SoMCYIFgrdlwQ=="; data[8] = "eNpdj70OgzAMhN_l5qiiEJCSh-jSETGQEKS0_FQNTIh3r6Eops3iL-ezdS4XDNC4T6N9vnznbnXvINBDF5dEwPY19PSenUBoocsF9G_rLpBgjGVmDDZOhJNhZAOjmVhldJEeTE0HLbdK0XKyx45voLOE3lWmFHgPaakgzCbQKf7Is4pDH8ZTZ1-yVgLf61oq6e_MJmV_ZrqgVLkscqlUtQmeBIIPhJFlwQ=="; data[9] = "eNpdj8sOgyAQRf_lrkljFU3kI7rp0rgQxITWR1N0Zfx3BzWOLZs5nGHInWJGD4XnOJj3x7X2UXUWAh1UdosETFdBjd_JCvgGqphB96ZqPQmtDTOjv2DgfVoPbBn1yJbRnvRiqlsoGSpFS-n52XE1VBLRucuYAm8hDRX4SXtaxR0ZFnH4frh0tk-WUmDfrqES_84Elfw9pg2KPJVZKvO8DMKRIFgBhBdlwQ=="; data[10] = "eNpdj8sOgyAQRf_lrkljFU3gI7rp0rgQxITWR1N0Zfz3jtYwtmzmcGYgd8oFAzTu02ifL9-5W907CPTQxSURsH0NPb1nJxBa6HIB3du6CySMscw2jrEMJzYja0YzsWV0kR5MTQctt0rRchqPHd9AZwmdq0wp8B7SUkGYTaBV_BFtFYcfxlNn_2StBL7btVTS3zebyv6GaYNS5bLIpVLVJjwJgg-E42XB"; data[11] = "eNpdj8sOgyAQRf_lrkljFU3gI7rp0rgQhITWR1N0Zfx3B2vFls0czgzkTjmjh8R9HPTz5VpzqzsDhg6yuCQMuqshx_dkGLyFLGfQ3datJ6GU_vYC7daf8MRqiDqiGqONaA56RGpaSB4qRctp_Oi4BjJL6Fx5SoG3kJoK_KQ8reL2lAvbfT-cOtsnS8Xw2c5SSX_fBJX9DdMGpch5kXMhqiAcCYIVhSRlwQ=="; boolean[] b = new boolean[12]; for (int i = 0; i < b.length; i++) { b[i] = false; } int last = -1; for (int i = 0; i < b.length; i++) { b[i] = true; System.out.println("Testing index: " + i); if (last > -1) { b[last] = false; } last = i; final int index = i; testIO(false, new SaveLoad() { @Override public List saveAndLoad(List stockpiles) { return StockpileReader.load(data[index]); } }, b); } } private void testIO(SaveLoad saveLoad) { testIO(false, saveLoad); } private void testIO(boolean flagNoSubs, SaveLoad saveLoad) { boolean[] b = new boolean[12]; for (int i = 0; i < b.length; i++) { b[i] = false; } int last = -1; for (int i = 0; i < b.length; i++) { b[i] = true; System.out.println("Testing index: " + i); if (last > -1) { b[last] = false; } last = i; testIO(flagNoSubs, saveLoad, b); } } private void testIO(boolean flagNoSubs, SaveLoad saveLoad, boolean[] b) { //Boolean boolean exclude = b[0]; Boolean singleton = b[1]; boolean assets = b[2]; boolean sellOrders = b[3]; boolean buyOrders = b[4]; boolean jobs = b[5]; boolean buyTransactions = b[6]; boolean sellTransactions = b[7]; boolean sellingContracts = b[8]; boolean soldContracts = b[9]; boolean buyingContracts = b[10]; boolean boughtContracts = b[11]; //Int Integer jobsDaysLess = 4; Integer jobsDaysMore = 5; //Location (Jita) MyLocation location = ApiIdConverter.getLocation(30000142); //Owners Long ownerID = 95465499L; List ownerIDs = new ArrayList<>(); ownerIDs.add(ownerID); //CCP Bartender //Flags List flags = new ArrayList<>(); flags.add(new StockpileFlag(2, true)); //Office +subs flags.add(new StockpileFlag(3, flagNoSubs)); //Wardrobe !subs //Containers List containers = new ArrayList<>(); String containerSubs = "subs"; String containerNoSubs = "nosubs"; containers.add(new StockpileContainer(containerSubs, true)); containers.add(new StockpileContainer(containerNoSubs, false)); List filters = new ArrayList<>(); filters.add(new StockpileFilter(location, exclude, flags, containers, ownerIDs, jobsDaysLess, jobsDaysMore, singleton, assets, sellOrders, buyOrders, jobs, buyTransactions, sellTransactions, sellingContracts, soldContracts, buyingContracts, boughtContracts)); List stockpiles = new ArrayList<>(); String stockpileName = "StockpileName"; double multiplier = 6.0; boolean matchAll = true; stockpiles.add(new Stockpile(stockpileName, 1L, filters, multiplier, matchAll)); //Save and Load List rStockpiles = saveLoad.saveAndLoad(stockpiles); //Stockpiles assertEquals(1, rStockpiles.size()); //Stockpile Stockpile rStockpile = rStockpiles.get(0); assertEquals(stockpileName, rStockpile.getName()); assertEquals(multiplier, rStockpile.getMultiplier(), 0.001); assertEquals(matchAll, rStockpile.isMatchAll()); //Filters assertEquals(1, rStockpile.getFilters().size()); //Filter StockpileFilter rFilter = rStockpile.getFilters().get(0); //Boolean assertEquals(exclude, rFilter.isExclude()); assertEquals(singleton, rFilter.isSingleton()); assertEquals(assets, rFilter.isAssets()); assertEquals(sellOrders, rFilter.isSellOrders()); assertEquals(buyOrders, rFilter.isBuyOrders()); assertEquals(jobs, rFilter.isJobs()); assertEquals(buyTransactions, rFilter.isBuyTransactions()); assertEquals(sellTransactions, rFilter.isSellTransactions()); assertEquals(sellingContracts, rFilter.isSellingContracts()); assertEquals(soldContracts, rFilter.isSoldContracts()); assertEquals(buyingContracts, rFilter.isBuyingContracts()); assertEquals(boughtContracts, rFilter.isBoughtContracts()); //Int assertEquals(jobsDaysLess, rFilter.getJobsDaysLess()); assertEquals(jobsDaysMore, rFilter.getJobsDaysMore()); //Location (Jita) assertEquals(location, rFilter.getLocation()); //Owners assertEquals(1, rFilter.getOwnerIDs().size()); assertEquals(ownerID, rFilter.getOwnerIDs().get(0)); //Flags assertEquals(2, rFilter.getFlags().size()); for (StockpileFlag flag : rFilter.getFlags()) { if (flag.getFlagID() == 2) { assertEquals(true, flag.isIncludeSubs()); } else { assertEquals(flagNoSubs, flag.isIncludeSubs()); } } //Containers assertEquals(2, rFilter.getContainers().size()); for (StockpileContainer rContainer : rFilter.getContainers()) { if (rContainer.getContainer().equals(containerSubs)) { assertEquals(true, rContainer.isIncludeSubs()); } else { assertEquals(false, rContainer.isIncludeSubs()); } } } private static interface SaveLoad { public List saveAndLoad(List stockpiles); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/local/TrackerDataTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local; import java.io.File; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import java.util.TreeMap; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.gui.tabs.values.AssetValue; import net.nikr.eve.jeveasset.gui.tabs.values.Value; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import org.junit.Test; public class TrackerDataTest extends TestUtil { private final String filename = "tracker.json"; private final Date date = new Date(1552492124589L); @Test public void testEmpty() throws URISyntaxException { Map> out = new TreeMap<>(); testWriteRead(out); testRead(out, "tracker_empty.json"); } @Test public void testFilters() throws URISyntaxException { Map> out = new TreeMap<>(); List values = new ArrayList<>(); out.put("TEST-NAME", values); Value value = new Value(date); value.setContractCollateral(3); value.setContractValue(4); value.setEscrows(5); value.setEscrowsToCover(6); value.setManufacturing(7); value.setSellOrders(8); value.addAssets(AssetValue.create("location", "flag", 1000L), 9.0); value.addBalance("balence-id", 10); value.setSkillPoints(11); values.add(value); testWriteRead(out); testRead(out, "tracker_filters.json"); } @Test public void testTotal() throws URISyntaxException { Map> out = new TreeMap<>(); List values = new ArrayList<>(); out.put("TEST-NAME", values); Value value = new Value(date); value.setAssetsTotal(1); value.setBalanceTotal(2); value.setContractCollateral(3); value.setContractValue(4); value.setEscrows(5); value.setEscrowsToCover(6); value.setManufacturing(7); value.setSellOrders(8); value.setSkillPoints(11); values.add(value); testWriteRead(out); testRead(out, "tracker_total.json"); } private void testRead(final Map> out, String filename) { try { read(out, new File(TrackerDataTest.class.getResource("/" + filename).toURI()).getAbsolutePath()); } catch (URISyntaxException ex) { throw new RuntimeException(ex); } } private void testWriteRead(final Map> out) { TrackerWriter.save(filename, out, false); read(out, filename); File file = new File(filename); file.delete(); } private void read(final Map> out, String filename) { final Map> in = TrackerReader.load(filename, false); assertThat(in.keySet(), equalTo(out.keySet())); for (String key : in.keySet()) { List outValues = out.get(key); List inValues = in.get(key); assertThat(inValues.getClass(), equalTo(outValues.getClass())); assertThat(inValues.size(), equalTo(outValues.size())); for (int i = 0; i < inValues.size(); i++) { Value outValue = outValues.get(i); Value inValue = inValues.get(i); //assertThat(inValue.hashCode(), equalTo(outValue.hashCode())); assertThat(inValue.getAssetsFilter(), equalTo(outValue.getAssetsFilter())); assertThat(inValue.getAssetsTotal(), equalTo(outValue.getAssetsTotal())); assertThat(inValue.getBalanceFilter(), equalTo(outValue.getBalanceFilter())); assertThat(inValue.getBalanceTotal(), equalTo(outValue.getBalanceTotal())); assertThat(inValue.getBestAssetValue(), equalTo(outValue.getBestAssetValue())); assertThat(inValue.getBestModuleValue(), equalTo(outValue.getBestModuleValue())); assertThat(inValue.getBestShipFittedValue(), equalTo(outValue.getBestShipFittedValue())); assertThat(inValue.getBestShipValue(), equalTo(outValue.getBestShipValue())); assertThat(inValue.getContractCollateral(), equalTo(outValue.getContractCollateral())); assertThat(inValue.getContractValue(), equalTo(outValue.getContractValue())); assertThat(inValue.getSkillPointValue(), equalTo(outValue.getSkillPointValue())); assertThat(inValue.getDate(), equalTo(outValue.getDate())); assertThat(inValue.getBestAssetName(), equalTo(outValue.getBestAssetName())); assertThat(inValue.getBestModuleName(), equalTo(outValue.getBestModuleName())); assertThat(inValue.getBestShipFittedName(), equalTo(outValue.getBestShipFittedName())); assertThat(inValue.getBestShipName(), equalTo(outValue.getBestShipName())); assertThat(inValue.getName(), equalTo(outValue.getName())); assertThat(inValue, equalTo(outValue)); } } assertThat(in, equalTo(out)); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/local/text/ImportEftTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.text; import java.util.Map; import net.nikr.eve.jeveasset.TestUtil; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import org.junit.Test; public class ImportEftTest extends TestUtil { private final ImportEft importEft = new ImportEft(); @Test public void testCargo() { String text = "[Dominix, Cargo Test]\n" + "\n" + "Large Armor Repairer II\n" + "Large Armor Repairer II\n" + "Kinetic Armor Hardener II\n" + "Explosive Armor Hardener II\n" + "Explosive Armor Hardener II\n" + "Explosive Armor Hardener II\n" + "Capacitor Power Relay II\n" + "\n" + "100MN Afterburner II\n" + "Cap Recharger II\n" + "Cap Recharger II\n" + "Cap Recharger II\n" + "Cap Recharger II\n" + "\n" + "Dual 250mm Prototype Gauss Gun\n" + "Dual 250mm Prototype Gauss Gun\n" + "Dual 250mm Prototype Gauss Gun\n" + "Dual 250mm Prototype Gauss Gun\n" + "Drone Link Augmentor I\n" + "Drone Link Augmentor I\n" + "\n" + "Large Capacitor Control Circuit I\n" + "Large Capacitor Control Circuit I\n" + "Large Capacitor Control Circuit I\n" + "\n" + "\n" + "Hammerhead II x10\n" + "Ogre II x5\n" + "Warden II x5\n" + "Hobgoblin II x5\n" + "\n" + "\n" + "Iron Charge L x3260\n" + "Antimatter Charge L x4704"; Map data = test(text, 16); assertEquals(3260, data.get("Iron Charge L"), 0.1); } @Test public void testDomi() { /* [Dominix, My Domi] Large Armor Repairer II Large Armor Repairer II Kinetic Armor Hardener II Explosive Armor Hardener II Explosive Armor Hardener II Explosive Armor Hardener II Capacitor Power Relay II 100MN Afterburner II Cap Recharger II Cap Recharger II Cap Recharger II Cap Recharger II Dual 250mm Prototype Gauss Gun Dual 250mm Prototype Gauss Gun Dual 250mm Prototype Gauss Gun Dual 250mm Prototype Gauss Gun [Empty High slot] [Empty High slot] Large Capacitor Control Circuit I Large Capacitor Control Circuit I Large Capacitor Control Circuit I Hammerhead II x10 Ogre II x5 Hobgoblin II x5 Warden II x5 */ String text = "[Dominix, My Domi]\n" + "\n" + "Large Armor Repairer II\n" + "Large Armor Repairer II\n" + "Kinetic Armor Hardener II\n" + "Explosive Armor Hardener II\n" + "Explosive Armor Hardener II\n" + "Explosive Armor Hardener II\n" + "Capacitor Power Relay II\n" + "\n" + "100MN Afterburner II\n" + "Cap Recharger II\n" + "Cap Recharger II\n" + "Cap Recharger II\n" + "Cap Recharger II\n" + "\n" + "Dual 250mm Prototype Gauss Gun\n" + "Dual 250mm Prototype Gauss Gun\n" + "Dual 250mm Prototype Gauss Gun\n" + "Dual 250mm Prototype Gauss Gun\n" + "[Empty High slot]\n" + "[Empty High slot]\n" + "\n" + "Large Capacitor Control Circuit I\n" + "Large Capacitor Control Circuit I\n" + "Large Capacitor Control Circuit I\n" + "\n" + "\n" + "Hammerhead II x10\n" + "Ogre II x5\n" + "Hobgoblin II x5\n" + "Warden II x5"; Map data = test(text, 13); assertEquals(10, data.get("Hammerhead II"), 0.1); } @Test public void testCharge() { /* Large Ancillary Armor Repairer, Nanite Repair Paste = 64 Remote Sensor Booster II, Scan Resolution Script = 1 'Shady' Sensor Booster, Targeting Range Script = 1 Guidance Disruptor II, Missile Range Disruption Script = 1 Small Ancillary Shield Booster, Navy Cap Booster 25 = 9 Dual Light Beam Laser I, True Sanshas Xray S = 1 350mm Railgun II, Federation Navy Iron Charge L = 80 Rapid Heavy Missile Launcher II, Nova Fury Heavy Missile = 25 Large Ancillary Remote Shield Booster, Navy Cap Booster 200 = 7 Large Ancillary Remote Armor Repairer, Nanite Repair Paste = 64 Festival Launcher, Copper Firework CXIV = 50 */ String text = "[Abaddon, Abaddon fit]\n" + "\n" + "Large Ancillary Armor Repairer, Nanite Repair Paste\n" + //64 "[Empty Low slot]\n" + "[Empty Low slot]\n" + "[Empty Low slot]\n" + "[Empty Low slot]\n" + "[Empty Low slot]\n" + "[Empty Low slot]\n" + "\n" + "Remote Sensor Booster II, Scan Resolution Script\n" + // 1 "'Shady' Sensor Booster, Targeting Range Script\n" + //1 "Guidance Disruptor II, Missile Range Disruption Script\n" + //1 "Small Ancillary Shield Booster, Navy Cap Booster 25\n" + "\n" + "Dual Light Beam Laser I, True Sanshas Xray S\n" + //1 "350mm Railgun II, Federation Navy Iron Charge L\n" + //80 "Rapid Heavy Missile Launcher II, Nova Fury Heavy Missile\n" + //25 "Large Ancillary Remote Shield Booster, Navy Cap Booster 200\n" + //7 "Small Tractor Beam II\n" + "Large Ancillary Remote Armor Repairer, Nanite Repair Paste\n" + //64 "Festival Launcher, Copper Firework CXIV\n" + //50 "[Empty High slot]\n" + "\n" + "[Empty Rig slot]\n" + "[Empty Rig slot]\n" + "[Empty Rig slot]\n" + "\n" + "\n" + "'Augmented' Vespa x1\n" + "Berserker II x1\n" + "Gecko x1\n" + "Heavy Hull Maintenance Bot II x1\n" + "Hornet EC-300 x1\n" + "Hornet I x1\n" + "Imperial Navy Curator x1\n" + "\n" + "\n" + "Blood Dagger Firework x1\n" + "Ace of Podhunters Firework x1\n" + //Formerly known as "Easter Firework" "Sodium Firework x1\n" + "Yoiul Festival Firework x1\n" + "Armor EM Resistance Script x1\n" + "Armor Explosive Resistance Script x1\n" + "Janitor x1\n" + "Armor Kinetic Resistance Script x1\n" + "Armor Thermal Resistance Script x1\n" + "Shield Kinetic Resistance Script x1\n" + "Shield Thermal Resistance Script x1\n" + "Missile Precision Script x1\n" + "Scan Resolution Dampening Script x1\n" + "Targeting Range Dampening Script x1\n" + "Tracking Speed Disruption Script x1\n" + "Tracking Speed Script x1\n" + "Heavy Armor Maintenance Bot I x1\n" + "Medium Shield Maintenance Bot II x1\n" + "Exotic Dancers, Male x5, Nanite Repair Paste\r\n" + "Exotic Dancers, Male, Navy Cap Booster 200"; Map data = test(text, 49); assertEquals(6, data.get("Exotic Dancers, Male"), 0.1); assertEquals(128, data.get("Nanite Repair Paste"), 0.1); assertEquals(7, data.get("Navy Cap Booster 200"), 0.1); assertEquals(1, data.get("Scan Resolution Script"), 0.1); assertEquals(1, data.get("Targeting Range Script"), 0.1); assertEquals(1, data.get("Missile Range Disruption Script"), 0.1); assertEquals(9, data.get("Navy Cap Booster 25"), 0.1); assertEquals(1, data.get("True Sanshas Xray S"), 0.1); assertEquals(80, data.get("Federation Navy Iron Charge L"), 0.1); assertEquals(25, data.get("Nova Fury Heavy Missile"), 0.1); assertEquals(50, data.get("Copper Firework CXIV"), 0.1); } private Map test(String text, int size) { Map data = importEft.doImport(text); assertNotNull(data); assertEquals(size, data.size()); assertEquals(data.size(), importEft.importText(text).size()); return data; } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/local/text/ImportEveMultibuyTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.text; import java.util.Map; import net.nikr.eve.jeveasset.TestUtil; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import org.junit.Test; public class ImportEveMultibuyTest extends TestUtil { private final ImportEveMultibuy importEveMultibuy = new ImportEveMultibuy(); @Test public void testSomeMethod() { /* 100MN Afterburner II 1 - - Dominix 1 - - Capacitor Power Relay II 1 - - Hammerhead II 10 1.189.997,05 11.899.970,50 Drone Link Augmentor I 2 - - Ogre II 5 - - Dual 250mm Prototype Gauss Gun 4 - - Cap Recharger II 4 - - Warden II 5 - - Large Capacitor Control Circuit I 3 - - Large Armor Repairer II 2 - - Hobgoblin II 5 499.997,32 2.499.986,60 Kinetic Armor Hardener II 1 - - Explosive Armor Hardener II 3 - - Total: 14.399.957,10 */ String text = "100MN Afterburner II 1 - -\n" + "Dominix 1 - -\n" + "Capacitor Power Relay II 1 - -\n" + "Hammerhead II 10 1.189.997,05 11.899.970,50\n" + "Drone Link Augmentor I 2 - -\n" + "Ogre II 5 - -\n" + "Dual 250mm Prototype Gauss Gun 4 - -\n" + "Cap Recharger II 4 - -\n" + "Warden II 5 - -\n" + "Large Capacitor Control Circuit I 3 - -\n" + "Large Armor Repairer II 2 - -\n" + "Hobgoblin II 5 499.997,32 2.499.986,60\n" + "Kinetic Armor Hardener II 1 - -\n" + "Explosive Armor Hardener II 3 - -\n" + "Total: 14.399.957,10"; Map data = test(text, 14); assertEquals(10, data.get("Hammerhead II"), 0.1); } @Test public void testXNotation() { String text = "Veldspar x10"; Map data = importEveMultibuy.doImport(text); assertNotNull(data); assertEquals(1, data.size()); assertEquals(10, data.get("Veldspar"), 0.1); } @Test public void testSimpleNotation() { String text = "Capacitor Power Relay II 10"; Map data = importEveMultibuy.doImport(text); assertNotNull(data); assertEquals(1, data.size()); assertEquals(10, data.get("Capacitor Power Relay II"), 0.1); } @Test public void testItemCountInFront() { String text = "10 Capacitor Power Relay II\n" + "50 Veldspar\n" + "x3 Dominix\n" + "x100 Tritanium"; Map data = importEveMultibuy.doImport(text); assertNotNull(data); assertEquals(4, data.size()); assertEquals(10, data.get("Capacitor Power Relay II"), 0.1); assertEquals(50, data.get("Veldspar"), 0.1); assertEquals(3, data.get("Dominix"), 0.1); assertEquals(100, data.get("Tritanium"), 0.1); } private Map test(String text, int size) { Map data = importEveMultibuy.doImport(text); assertNotNull(data); assertEquals(size, data.size()); assertEquals(data.size(), importEveMultibuy.importText(text).size()); return data; } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/local/text/ImportIskPerHourTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.text; import java.util.Map; import net.nikr.eve.jeveasset.TestUtil; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import org.junit.Test; public class ImportIskPerHourTest extends TestUtil { private final ImportIskPerHour importIskPerHour = new ImportIskPerHour(); private Map test(String text, int size) { return test(text, size, true); } private Map test(String text, int size, boolean tritanium) { Map data = importIskPerHour.doImport(text); assertNotNull(data); assertEquals(size, data.size()); if (tritanium) { assertEquals(2932280, data.get("Tritanium"), 0.1); } assertEquals(data.size(), importIskPerHour.importText(text).size()); return data; } @Test public void testCopyEveList() { String eveListFormat = "Tritanium 2932280\n" + "Pyerite 915005\n" + "Mexallon 190244\n" + "Crystalline Carbonide 144316\n" + "Isogen 63721\n" + "Sylramic Fibers 24033\n" + "Phenolic Composites 12474\n" + "Nocxium 8837\n" + "Photonic Metamaterials 4940\n" + "Nanotransistors 4683\n" + "Fullerides 4532\n" + "Zydrine 3364\n" + "Crystalline Carbonide Armor Plate 2058\n" + "Photon Microprocessor 2058\n" + "Megacyte 1618\n" + "Oscillator Capacitor Unit 412\n" + "Hypersynaptic Fibers 310\n" + "Construction Blocks 206\n" + "Ferrogel 197\n" + "Pulse Shield Emitter 155\n" + "Magnetometric Sensor Cluster 155\n" + "Morphite 148\n" + "Datacore - Gallentean Starship Engineering 72\n" + "Datacore - Laser Physics 72\n" + "Fermionic Condensates 64\n" + "Ion Thruster 42\n" + "Fusion Reactor Unit 32\n" + "R.A.M.- Starship Tech 9\n" + "Procurer 1"; test(eveListFormat, 29); } @Test public void testCopyDefault() { String plainFormat = "Shopping List for: \n" + "Material - Quantity\n" + "10000MN Afterburner I (ME: 0, NumBPs: 1) - 1\n" + "Location: Jita IV - Moon 4 - Caldari Navy Assembly Plant\n" + "Algos (ME: 0, NumBPs: 1) - 1\n" + "Location: Jita IV - Moon 4 - Caldari Navy Assembly Plant\n" + "Skiff (ME: 2, NumBPs: 1) - 1\n" + "Location: Jita IV - Moon 4 - Caldari Navy Assembly Plant\n" + "Skiff (ME: 2, NumBPs: 2) - 2\n" + "Location: Jita IV - Moon 4 - Caldari Navy Assembly Plant\n" + "\n" + "Estimated Invention Materials: \n" + "Material - Quantity\n" + "Datacore - Gallentean Starship Engineering - 72\n" + "Datacore - Laser Physics - 72\n" + "\n" + "Total Volume of Materials: 14.40 m3\n" + "Total Cost of Materials: 6,049,975.68 ISK\n" + "\n" + "Build Items List: \n" + "Material - Quantity\n" + "Photon Microprocessor (ME: 0, NumBPs: 1) - 2,058\n" + "Crystalline Carbonide Armor Plate (ME: 0, NumBPs: 1) - 2,058\n" + "Oscillator Capacitor Unit (ME: 0, NumBPs: 1) - 412\n" + "Magnetometric Sensor Cluster (ME: 0, NumBPs: 1) - 155\n" + "Pulse Shield Emitter (ME: 0, NumBPs: 1) - 155\n" + "Ion Thruster (ME: 0, NumBPs: 1) - 42\n" + "Fusion Reactor Unit (ME: 0, NumBPs: 1) - 32\n" + "R.A.M.- Starship Tech (ME: 0, NumBPs: 1) - 9\n" + "Procurer (ME: 0, NumBPs: 1) - 1\n" + "\n" + "Buy Materials List: \n" + "Material - Quantity\n" + "Tritanium - 2,932,280\n" + "Pyerite - 915,005\n" + "Mexallon - 190,244\n" + "Crystalline Carbonide - 144,316\n" + "Isogen - 63,721\n" + "Sylramic Fibers - 24,033\n" + "Phenolic Composites - 12,474\n" + "Nocxium - 8,837\n" + "Photonic Metamaterials - 4,940\n" + "Nanotransistors - 4,683\n" + "Fullerides - 4,532\n" + "Zydrine - 3,364\n" + "Crystalline Carbonide Armor Plate - 2,058\n" + "Photon Microprocessor - 2,058\n" + "Megacyte - 1,618\n" + "Oscillator Capacitor Unit - 412\n" + "Hypersynaptic Fibers - 310\n" + "Construction Blocks - 206\n" + "Ferrogel - 197\n" + "Pulse Shield Emitter - 155\n" + "Magnetometric Sensor Cluster - 155\n" + "Morphite - 148\n" + "Fermionic Condensates - 64\n" + "Ion Thruster - 42\n" + "Fusion Reactor Unit - 32\n" + "R.A.M.- Starship Tech - 9\n" + "Procurer - 1\n" + "\n" + "Total Volume of Materials: 62,519.89 m3\n" + "Total Cost of Materials: 273,043,780.28 ISK\n" + "Total Volume of Built Item(s): 359,000.00 m3"; test(plainFormat, 32); } @Test public void testFileDefault() { String plainFormat = "Buy List\n" + "Material|Quantity|Cost Per Item|Min Sell|Max Buy|Buy Type|Total m3|Isk/m3|TotalCost\n" + "Tritanium|2932280.00|0.00|0.00|0.00|Unknown|29322.80|0.00|0.00\n" + "Pyerite|915005.00|0.00|0.00|0.00|Unknown|9150.05|0.00|0.00\n" + "Mexallon|190244.00|0.00|0.00|0.00|Unknown|1902.44|0.00|0.00\n" + "Crystalline Carbonide|144316.00|0.00|0.00|0.00|Unknown|1443.16|0.00|0.00\n" + "Isogen|63721.00|0.00|0.00|0.00|Unknown|637.21|0.00|0.00\n" + "Sylramic Fibers|24033.00|0.00|0.00|0.00|Unknown|1201.65|0.00|0.00\n" + "Phenolic Composites|12474.00|0.00|0.00|0.00|Unknown|2494.80|0.00|0.00\n" + "Nocxium|8837.00|0.00|0.00|0.00|Unknown|88.37|0.00|0.00\n" + "Photonic Metamaterials|4940.00|0.00|0.00|0.00|Unknown|4940.00|0.00|0.00\n" + "Nanotransistors|4683.00|0.00|0.00|0.00|Unknown|1170.75|0.00|0.00\n" + "Fullerides|4532.00|0.00|0.00|0.00|Unknown|679.80|0.00|0.00\n" + "Zydrine|3364.00|0.00|0.00|0.00|Unknown|33.64|0.00|0.00\n" + "Crystalline Carbonide Armor Plate|2058.00|0.00|0.00|0.00|Unknown|2058.00|0.00|0.00\n" + "Photon Microprocessor|2058.00|0.00|0.00|0.00|Unknown|2058.00|0.00|0.00\n" + "Megacyte|1618.00|0.00|0.00|0.00|Unknown|16.18|0.00|0.00\n" + "Oscillator Capacitor Unit|412.00|0.00|0.00|0.00|Unknown|412.00|0.00|0.00\n" + "Hypersynaptic Fibers|310.00|0.00|0.00|0.00|Unknown|186.00|0.00|0.00\n" + "Construction Blocks|206.00|0.00|0.00|0.00|Unknown|309.00|0.00|0.00\n" + "Ferrogel|197.00|0.00|0.00|0.00|Unknown|197.00|0.00|0.00\n" + "Pulse Shield Emitter|155.00|0.00|0.00|0.00|Unknown|155.00|0.00|0.00\n" + "Magnetometric Sensor Cluster|155.00|0.00|0.00|0.00|Unknown|155.00|0.00|0.00\n" + "Morphite|148.00|0.00|0.00|0.00|Unknown|1.48|0.00|0.00\n" + "Datacore - Gallentean Starship Engineering|72.00|0.00|0.00|0.00|Unknown|7.20|0.00|0.00\n" + "Datacore - Laser Physics|72.00|0.00|0.00|0.00|Unknown|7.20|0.00|0.00\n" + "Fermionic Condensates|64.00|0.00|0.00|0.00|Unknown|83.20|0.00|0.00\n" + "Ion Thruster|42.00|0.00|0.00|0.00|Unknown|42.00|0.00|0.00\n" + "Fusion Reactor Unit|32.00|0.00|0.00|0.00|Unknown|32.00|0.00|0.00\n" + "R.A.M.- Starship Tech|9.00|0.00|0.00|0.00|Unknown|0.36|0.00|0.00\n" + "Procurer|1.00|0.00|0.00|0.00|Unknown|3750.00|0.00|0.00\n" + "\n" + "Build List\n" + "Build Item|Quantity|ME|TE|Facility Location|Facility Type|IncludeActivityCost|IncludeActivityTime|IncludeUsageCost\n" + "Photon Microprocessor|2058.00|0|0|Jita IV - Moon 4 - Caldari Navy Assembly Plant|Station|False|False|True\n" + "Crystalline Carbonide Armor Plate|2058.00|0|0|Jita IV - Moon 4 - Caldari Navy Assembly Plant|Station|False|False|True\n" + "Oscillator Capacitor Unit|412.00|0|0|Jita IV - Moon 4 - Caldari Navy Assembly Plant|Station|False|False|True\n" + "Magnetometric Sensor Cluster|155.00|0|0|Jita IV - Moon 4 - Caldari Navy Assembly Plant|Station|False|False|True\n" + "Pulse Shield Emitter|155.00|0|0|Jita IV - Moon 4 - Caldari Navy Assembly Plant|Station|False|False|True\n" + "Ion Thruster|42.00|0|0|Jita IV - Moon 4 - Caldari Navy Assembly Plant|Station|False|False|True\n" + "Fusion Reactor Unit|32.00|0|0|Jita IV - Moon 4 - Caldari Navy Assembly Plant|Station|False|False|True\n" + "R.A.M.- Starship Tech|9.00|0|0|Jita IV - Moon 4 - Caldari Navy Assembly Plant|Station|False|False|True\n" + "Procurer|1.00|0|0|Jita IV - Moon 4 - Caldari Navy Assembly Plant|Station|False|False|True\n" + "\n" + "Item List\n" + "Item|Quantity|ME|NumBps|Build Type|Decryptor|Relic|Facility Type|Location|IgnoredInvention|IgnoredMinerals|IgnoredT1BaseItem|IncludeActivityCost|IncludeActivityTime|IncludeUsageCost\n" + "10000MN Afterburner I|1.00|0|1|Raw Mats|||Station|Jita IV - Moon 4 - Caldari Navy Assembly Plant|0|0|0|0|0|0\n" + "Algos|1.00|0|1|Raw Mats|||Station|Jita IV - Moon 4 - Caldari Navy Assembly Plant|0|0|0|0|0|0\n" + "Skiff|1.00|2|1|Raw Mats|None||Station|Jita IV - Moon 4 - Caldari Navy Assembly Plant|0|0|0|0|0|0\n" + "Skiff|2.00|2|2|Components|None||Station|Jita IV - Moon 4 - Caldari Navy Assembly Plant|0|0|0|0|0|0"; test(plainFormat, 32); } @Test public void testCopyCsv() { String csvFormat = "Shopping List for: \n" + "Material, Quantity, ME, NumBPs, Decryptor/Relic, Cost Per Item, Total Cost, Location\n" + "10000MN Afterburner I, 1, 0, 1, None, 29789997.31, 29789997.31, Jita IV - Moon 4 - Caldari Navy Assembly Plant\n" + "Algos, 1, 0, 1, None, 1305999.39, 1305999.39, Jita IV - Moon 4 - Caldari Navy Assembly Plant\n" + "Skiff, 1, 2, 1, None, 168493998.99, 168493998.99, Jita IV - Moon 4 - Caldari Navy Assembly Plant\n" + "Skiff, 2, 2, 2, None, 168493998.99, 336987997.98, Jita IV - Moon 4 - Caldari Navy Assembly Plant\n" + "\n" + "Estimated Invention Materials: \n" + "Material, Quantity, Cost Per Item, Total Cost, Location\n" + "Datacore - Gallentean Starship Engineering, 72, 43008.93, 3096642.96\n" + "Datacore - Laser Physics, 72, 41018.51, 2953332.72\n" + "\n" + "Total Volume of Materials:,14.4,m3\n" + "Total Cost of Materials:,6049975.68,ISK\n" + "\n" + "Build Items List: \n" + "Material, Quantity, ME, NumBPs, Cost Per Item, Total Cost, Location\n" + "Photon Microprocessor, 2058, 0, 1, 43749.11, 90035668.38\n" + "Crystalline Carbonide Armor Plate, 2058, 0, 1, 11497.94, 23662760.52\n" + "Oscillator Capacitor Unit, 412, 0, 1, 44884.19, 18492286.28\n" + "Magnetometric Sensor Cluster, 155, 0, 1, 28997, 4494535\n" + "Pulse Shield Emitter, 155, 0, 1, 46997.76, 7284652.8\n" + "Ion Thruster, 42, 0, 1, 47899.58, 2011782.36\n" + "Fusion Reactor Unit, 32, 0, 1, 161498.09, 5167938.88\n" + "R.A.M.- Starship Tech, 9, 0, 1, 299.99, 2699.91\n" + "Procurer, 1, 0, 1, 18494999, 18494999\n" + "\n" + "Buy Materials List: \n" + "Material, Quantity, Cost Per Item, Total Cost, Location\n" + "Tritanium, 2932280, 2, 5864560\n" + "Pyerite, 915005, 4, 3660020\n" + "Mexallon, 190244, 37.01, 7040930.44\n" + "Crystalline Carbonide, 144316, 106.09, 15310484.44\n" + "Isogen, 63721, 40, 2548840\n" + "Sylramic Fibers, 24033, 199.14, 4785931.62\n" + "Phenolic Composites, 12474, 1117.39, 13938322.86\n" + "Nocxium, 8837, 247.14, 2183976.18\n" + "Photonic Metamaterials, 4940, 6000.01, 29640049.4\n" + "Nanotransistors, 4683, 1260.78, 5904232.74\n" + "Fullerides, 4532, 350.52, 1588556.64\n" + "Zydrine, 3364, 521.91, 1755705.24\n" + "Crystalline Carbonide Armor Plate, 2058, 11497.94, 23662760.52\n" + "Photon Microprocessor, 2058, 43749.11, 90035668.38\n" + "Megacyte, 1618, 136.02, 220080.36\n" + "Oscillator Capacitor Unit, 412, 44884.19, 18492286.28\n" + "Hypersynaptic Fibers, 310, 4000, 1240000\n" + "Construction Blocks, 206, 8104.33, 1669491.98\n" + "Ferrogel, 197, 16881.57, 3325669.29\n" + "Pulse Shield Emitter, 155, 46997.76, 7284652.8\n" + "Magnetometric Sensor Cluster, 155, 28997, 4494535\n" + "Morphite, 148, 6700.01, 991601.48\n" + "Fermionic Condensates, 64, 27000.07, 1728004.48\n" + "Ion Thruster, 42, 47899.58, 2011782.36\n" + "Fusion Reactor Unit, 32, 161498.09, 5167938.88\n" + "R.A.M.- Starship Tech, 9, 299.99, 2699.91\n" + "Procurer, 1, 18494999, 18494999\n" + "\n" + "Total Volume of Materials:,62519.89,m3\n" + "Total Cost of Materials:,273043780.28,ISK\n" + "Total Volume of Built Item(s):,359000,m3"; test(csvFormat, 32); } @Test public void testFileCsv() { String csvFormat = "Buy List\n" + "Material,Quantity,Cost Per Item,Min Sell,Max Buy,Buy Type,Total m3,Isk/m3,TotalCost\n" + "Tritanium,2932280.00,0.00,0.00,0.00,Unknown,29322.80,0.00,0.00\n" + "Pyerite,915005.00,0.00,0.00,0.00,Unknown,9150.05,0.00,0.00\n" + "Mexallon,190244.00,0.00,0.00,0.00,Unknown,1902.44,0.00,0.00\n" + "Crystalline Carbonide,144316.00,0.00,0.00,0.00,Unknown,1443.16,0.00,0.00\n" + "Isogen,63721.00,0.00,0.00,0.00,Unknown,637.21,0.00,0.00\n" + "Sylramic Fibers,24033.00,0.00,0.00,0.00,Unknown,1201.65,0.00,0.00\n" + "Phenolic Composites,12474.00,0.00,0.00,0.00,Unknown,2494.80,0.00,0.00\n" + "Nocxium,8837.00,0.00,0.00,0.00,Unknown,88.37,0.00,0.00\n" + "Photonic Metamaterials,4940.00,0.00,0.00,0.00,Unknown,4940.00,0.00,0.00\n" + "Nanotransistors,4683.00,0.00,0.00,0.00,Unknown,1170.75,0.00,0.00\n" + "Fullerides,4532.00,0.00,0.00,0.00,Unknown,679.80,0.00,0.00\n" + "Zydrine,3364.00,0.00,0.00,0.00,Unknown,33.64,0.00,0.00\n" + "Crystalline Carbonide Armor Plate,2058.00,0.00,0.00,0.00,Unknown,2058.00,0.00,0.00\n" + "Photon Microprocessor,2058.00,0.00,0.00,0.00,Unknown,2058.00,0.00,0.00\n" + "Megacyte,1618.00,0.00,0.00,0.00,Unknown,16.18,0.00,0.00\n" + "Oscillator Capacitor Unit,412.00,0.00,0.00,0.00,Unknown,412.00,0.00,0.00\n" + "Hypersynaptic Fibers,310.00,0.00,0.00,0.00,Unknown,186.00,0.00,0.00\n" + "Construction Blocks,206.00,0.00,0.00,0.00,Unknown,309.00,0.00,0.00\n" + "Ferrogel,197.00,0.00,0.00,0.00,Unknown,197.00,0.00,0.00\n" + "Pulse Shield Emitter,155.00,0.00,0.00,0.00,Unknown,155.00,0.00,0.00\n" + "Magnetometric Sensor Cluster,155.00,0.00,0.00,0.00,Unknown,155.00,0.00,0.00\n" + "Morphite,148.00,0.00,0.00,0.00,Unknown,1.48,0.00,0.00\n" + "Datacore - Gallentean Starship Engineering,72.00,0.00,0.00,0.00,Unknown,7.20,0.00,0.00\n" + "Datacore - Laser Physics,72.00,0.00,0.00,0.00,Unknown,7.20,0.00,0.00\n" + "Fermionic Condensates,64.00,0.00,0.00,0.00,Unknown,83.20,0.00,0.00\n" + "Ion Thruster,42.00,0.00,0.00,0.00,Unknown,42.00,0.00,0.00\n" + "Fusion Reactor Unit,32.00,0.00,0.00,0.00,Unknown,32.00,0.00,0.00\n" + "R.A.M.- Starship Tech,9.00,0.00,0.00,0.00,Unknown,0.36,0.00,0.00\n" + "Procurer,1.00,0.00,0.00,0.00,Unknown,3750.00,0.00,0.00\n" + "\n" + "Build List\n" + "Build Item,Quantity,ME,TE,Facility Location,Facility Type,IncludeActivityCost,IncludeActivityTime,IncludeUsageCost\n" + "Photon Microprocessor,2058.00,0,0,Jita IV - Moon 4 - Caldari Navy Assembly Plant,Station,False,False,True\n" + "Crystalline Carbonide Armor Plate,2058.00,0,0,Jita IV - Moon 4 - Caldari Navy Assembly Plant,Station,False,False,True\n" + "Oscillator Capacitor Unit,412.00,0,0,Jita IV - Moon 4 - Caldari Navy Assembly Plant,Station,False,False,True\n" + "Magnetometric Sensor Cluster,155.00,0,0,Jita IV - Moon 4 - Caldari Navy Assembly Plant,Station,False,False,True\n" + "Pulse Shield Emitter,155.00,0,0,Jita IV - Moon 4 - Caldari Navy Assembly Plant,Station,False,False,True\n" + "Ion Thruster,42.00,0,0,Jita IV - Moon 4 - Caldari Navy Assembly Plant,Station,False,False,True\n" + "Fusion Reactor Unit,32.00,0,0,Jita IV - Moon 4 - Caldari Navy Assembly Plant,Station,False,False,True\n" + "R.A.M.- Starship Tech,9.00,0,0,Jita IV - Moon 4 - Caldari Navy Assembly Plant,Station,False,False,True\n" + "Procurer,1.00,0,0,Jita IV - Moon 4 - Caldari Navy Assembly Plant,Station,False,False,True\n" + "\n" + "Item List\n" + "Item,Quantity,ME,NumBps,Build Type,Decryptor,Relic,Facility Type,Location,IgnoredInvention,IgnoredMinerals,IgnoredT1BaseItem,IncludeActivityCost,IncludeActivityTime,IncludeUsageCost\n" + "10000MN Afterburner I,1.00,0,1,Raw Mats,,,Station,Jita IV - Moon 4 - Caldari Navy Assembly Plant,0,0,0,0,0,0\n" + "Algos,1.00,0,1,Raw Mats,,,Station,Jita IV - Moon 4 - Caldari Navy Assembly Plant,0,0,0,0,0,0\n" + "Skiff,1.00,2,1,Raw Mats,None,,Station,Jita IV - Moon 4 - Caldari Navy Assembly Plant,0,0,0,0,0,0\n" + "Skiff,2.00,2,2,Components,None,,Station,Jita IV - Moon 4 - Caldari Navy Assembly Plant,0,0,0,0,0,0"; test(csvFormat, 32); } @Test public void testCopySSV() { String ssvFormat = "Shopping List for: \n" + "Material; Quantity; ME; NumBPs; Decryptor/Relic; Cost Per Item; Total Cost; Location\n" + "10000MN Afterburner I; 1; 0; 1; None; 29789997,31; 29789997,31; Jita IV - Moon 4 - Caldari Navy Assembly Plant\n" + "Algos; 1; 0; 1; None; 1305999,39; 1305999,39; Jita IV - Moon 4 - Caldari Navy Assembly Plant\n" + "Skiff; 1; 2; 1; None; 168493998,99; 168493998,99; Jita IV - Moon 4 - Caldari Navy Assembly Plant\n" + "Skiff; 2; 2; 2; None; 168493998,99; 336987997,98; Jita IV - Moon 4 - Caldari Navy Assembly Plant\n" + "\n" + "Estimated Invention Materials: \n" + "Material; Quantity; Cost Per Item; Total Cost; Location\n" + "Datacore - Gallentean Starship Engineering; 72; 43008,93; 3096642,96\n" + "Datacore - Laser Physics; 72; 41018,51; 2953332,72\n" + "\n" + "Total Volume of Materials:;14,4;m3\n" + "Total Cost of Materials:;6049975,68;ISK\n" + "\n" + "Build Items List: \n" + "Material; Quantity; ME; NumBPs; Cost Per Item; Total Cost; Location\n" + "Photon Microprocessor; 2058; 0; 1; 43749,11; 90035668,38\n" + "Crystalline Carbonide Armor Plate; 2058; 0; 1; 11497,94; 23662760,52\n" + "Oscillator Capacitor Unit; 412; 0; 1; 44884,19; 18492286,28\n" + "Magnetometric Sensor Cluster; 155; 0; 1; 28997; 4494535\n" + "Pulse Shield Emitter; 155; 0; 1; 46997,76; 7284652,8\n" + "Ion Thruster; 42; 0; 1; 47899,58; 2011782,36\n" + "Fusion Reactor Unit; 32; 0; 1; 161498,09; 5167938,88\n" + "R.A.M.- Starship Tech; 9; 0; 1; 299,99; 2699,91\n" + "Procurer; 1; 0; 1; 18494999; 18494999\n" + "\n" + "Buy Materials List: \n" + "Material; Quantity; Cost Per Item; Total Cost; Location\n" + "Tritanium; 2932280; 2; 5864560\n" + "Pyerite; 915005; 4; 3660020\n" + "Mexallon; 190244; 37,01; 7040930,44\n" + "Crystalline Carbonide; 144316; 106,09; 15310484,44\n" + "Isogen; 63721; 40; 2548840\n" + "Sylramic Fibers; 24033; 199,14; 4785931,62\n" + "Phenolic Composites; 12474; 1117,39; 13938322,86\n" + "Nocxium; 8837; 247,14; 2183976,18\n" + "Photonic Metamaterials; 4940; 6000,01; 29640049,4\n" + "Nanotransistors; 4683; 1260,78; 5904232,74\n" + "Fullerides; 4532; 350,52; 1588556,64\n" + "Zydrine; 3364; 521,91; 1755705,24\n" + "Crystalline Carbonide Armor Plate; 2058; 11497,94; 23662760,52\n" + "Photon Microprocessor; 2058; 43749,11; 90035668,38\n" + "Megacyte; 1618; 136,02; 220080,36\n" + "Oscillator Capacitor Unit; 412; 44884,19; 18492286,28\n" + "Hypersynaptic Fibers; 310; 4000; 1240000\n" + "Construction Blocks; 206; 8104,33; 1669491,98\n" + "Ferrogel; 197; 16881,57; 3325669,29\n" + "Pulse Shield Emitter; 155; 46997,76; 7284652,8\n" + "Magnetometric Sensor Cluster; 155; 28997; 4494535\n" + "Morphite; 148; 6700,01; 991601,48\n" + "Fermionic Condensates; 64; 27000,07; 1728004,48\n" + "Ion Thruster; 42; 47899,58; 2011782,36\n" + "Fusion Reactor Unit; 32; 161498,09; 5167938,88\n" + "R.A.M.- Starship Tech; 9; 299,99; 2699,91\n" + "Procurer; 1; 18494999; 18494999\n" + "\n" + "Total Volume of Materials:;62519,89;m3\n" + "Total Cost of Materials:;273043780,28;ISK\n" + "Total Volume of Built Item(s):;359000;m3"; test(ssvFormat, 32); } @Test public void testFileSSV() { String ssvFormat = "Buy List\n" + "Material;Quantity;Cost Per Item;Min Sell;Max Buy;Buy Type;Total m3;Isk/m3;TotalCost\n" + "Tritanium;2.932.280;0,00;0,00;0,00;Unknown;29.322,80;0,00;0,00\n" + "Pyerite;915.005;0,00;0,00;0,00;Unknown;9.150,05;0,00;0,00\n" + "Mexallon;190.244;0,00;0,00;0,00;Unknown;1.902,44;0,00;0,00\n" + "Crystalline Carbonide;144.316;0,00;0,00;0,00;Unknown;1.443,16;0,00;0,00\n" + "Isogen;63.721;0,00;0,00;0,00;Unknown;637,21;0,00;0,00\n" + "Sylramic Fibers;24.033;0,00;0,00;0,00;Unknown;1.201,65;0,00;0,00\n" + "Phenolic Composites;12.474;0,00;0,00;0,00;Unknown;2.494,80;0,00;0,00\n" + "Nocxium;8.837;0,00;0,00;0,00;Unknown;88,37;0,00;0,00\n" + "Photonic Metamaterials;4.940;0,00;0,00;0,00;Unknown;4.940,00;0,00;0,00\n" + "Nanotransistors;4.683;0,00;0,00;0,00;Unknown;1.170,75;0,00;0,00\n" + "Fullerides;4.532;0,00;0,00;0,00;Unknown;679,80;0,00;0,00\n" + "Zydrine;3.364;0,00;0,00;0,00;Unknown;33,64;0,00;0,00\n" + "Crystalline Carbonide Armor Plate;2.058;0,00;0,00;0,00;Unknown;2.058,00;0,00;0,00\n" + "Photon Microprocessor;2.058;0,00;0,00;0,00;Unknown;2.058,00;0,00;0,00\n" + "Megacyte;1.618;0,00;0,00;0,00;Unknown;16,18;0,00;0,00\n" + "Oscillator Capacitor Unit;412;0,00;0,00;0,00;Unknown;412,00;0,00;0,00\n" + "Hypersynaptic Fibers;310;0,00;0,00;0,00;Unknown;186,00;0,00;0,00\n" + "Construction Blocks;206;0,00;0,00;0,00;Unknown;309,00;0,00;0,00\n" + "Ferrogel;197;0,00;0,00;0,00;Unknown;197,00;0,00;0,00\n" + "Pulse Shield Emitter;155;0,00;0,00;0,00;Unknown;155,00;0,00;0,00\n" + "Magnetometric Sensor Cluster;155;0,00;0,00;0,00;Unknown;155,00;0,00;0,00\n" + "Morphite;148;0,00;0,00;0,00;Unknown;1,48;0,00;0,00\n" + "Datacore - Gallentean Starship Engineering;72;0,00;0,00;0,00;Unknown;7,20;0,00;0,00\n" + "Datacore - Laser Physics;72;0,00;0,00;0,00;Unknown;7,20;0,00;0,00\n" + "Fermionic Condensates;64;0,00;0,00;0,00;Unknown;83,20;0,00;0,00\n" + "Ion Thruster;42;0,00;0,00;0,00;Unknown;42,00;0,00;0,00\n" + "Fusion Reactor Unit;32;0,00;0,00;0,00;Unknown;32,00;0,00;0,00\n" + "R.A.M.- Starship Tech;9;0,00;0,00;0,00;Unknown;0,36;0,00;0,00\n" + "Procurer;1;0,00;0,00;0,00;Unknown;3.750,00;0,00;0,00\n" + "\n" + "Build List\n" + "Build Item;Quantity;ME;TE;Facility Location; Facility Type;IncludeActivityCost;IncludeActivityTime;IncludeUsageCost\n" + "Photon Microprocessor;2.058;0;0;Jita IV - Moon 4 - Caldari Navy Assembly Plant;Station;False;False;True\n" + "Crystalline Carbonide Armor Plate;2.058;0;0;Jita IV - Moon 4 - Caldari Navy Assembly Plant;Station;False;False;True\n" + "Oscillator Capacitor Unit;412;0;0;Jita IV - Moon 4 - Caldari Navy Assembly Plant;Station;False;False;True\n" + "Magnetometric Sensor Cluster;155;0;0;Jita IV - Moon 4 - Caldari Navy Assembly Plant;Station;False;False;True\n" + "Pulse Shield Emitter;155;0;0;Jita IV - Moon 4 - Caldari Navy Assembly Plant;Station;False;False;True\n" + "Ion Thruster;42;0;0;Jita IV - Moon 4 - Caldari Navy Assembly Plant;Station;False;False;True\n" + "Fusion Reactor Unit;32;0;0;Jita IV - Moon 4 - Caldari Navy Assembly Plant;Station;False;False;True\n" + "R.A.M.- Starship Tech;9;0;0;Jita IV - Moon 4 - Caldari Navy Assembly Plant;Station;False;False;True\n" + "Procurer;1;0;0;Jita IV - Moon 4 - Caldari Navy Assembly Plant;Station;False;False;True\n" + "\n" + "Item List\n" + "Item;Quantity;ME;NumBps;Build Type;Decryptor;Relic;Facility Type;Location;IgnoredInvention;IgnoredMinerals;IgnoredT1BaseItem;IncludeActivityCost;IncludeActivityTime;IncludeUsageCost\n" + "10000MN Afterburner I;1;0;1;Raw Mats;;;Station;Jita IV - Moon 4 - Caldari Navy Assembly Plant;0;0;0;0;0;0\n" + "Algos;1;0;1;Raw Mats;;;Station;Jita IV - Moon 4 - Caldari Navy Assembly Plant;0;0;0;0;0;0\n" + "Skiff;1;2;1;Raw Mats;None;;Station;Jita IV - Moon 4 - Caldari Navy Assembly Plant;0;0;0;0;0;0\n" + "Skiff;2;2;2;Components;None;;Station;Jita IV - Moon 4 - Caldari Navy Assembly Plant;0;0;0;0;0;0"; test(ssvFormat, 32); } @Test public void testUserInput() { String ssvFormat = "Buy Materials List:\n" + "Material, Quantity, Cost Per Item, Total Cost\n" + "Drone Transceiver, 1520, 270001.07, 410401626.4\n" + "Telemetry Processor, 1520, 25010, 38015200\n" + "Micro Circuit, 1520, 8201.02, 12465550.4\n" + "Trigger Unit, 1520, 200603.29, 304917000.8\n" + "Current Pump, 1520, 32004, 48646080\n" + "Lorentz Fluid, 600, 103941.74, 62365044\n" + "Power Conduit, 600, 663535.68, 398121408\n" + "Nanite Compound, 32, 341239, 10919648\n" + "Single-crystal Superalloy I-beam, 32, 112135.02, 3588320.64\n" + "Intact Armor Plates, 4, 3041000.02, 12164000.08\n" + "R.A.M.- Ammunition Tech, 2, 193.89, 387.78"; Map data = test(ssvFormat, 11, false); assertEquals(1520, data.get("Drone Transceiver"), 0.1); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/local/text/ImportShoppingListTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.local.text; import java.util.Map; import net.nikr.eve.jeveasset.TestUtil; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import org.junit.Test; public class ImportShoppingListTest extends TestUtil { private final ImportShoppingList importShoppingList = new ImportShoppingList(); @Test public void testDomi() { /* My Domi 1x 100MN Afterburner II 1x Dominix 1x Capacitor Power Relay II 10x Hammerhead II 5x Ogre II 4x Dual 250mm Prototype Gauss Gun 4x Cap Recharger II 5x Warden II 2x Large Armor Repairer II 5x Hobgoblin II 1x Armor Kinetic Hardener II 3x Large Capacitor Control Circuit I 3x Armor Explosive Hardener II Total m3 to be hauled: 50.665,00 Estimated market value: 225.404.694,17 isk */ String text = "My Domi\n" + "\n" + "1x 100MN Afterburner II\n" + "1x Dominix\n" + "1x Capacitor Power Relay II\n" + "10x Hammerhead II\n" + "5x Ogre II\n" + "4x Dual 250mm Prototype Gauss Gun\n" + "4x Cap Recharger II\n" + "5x Warden II\n" + "2x Large Armor Repairer II\n" + "5x Hobgoblin II\n" + "1x Kinetic Armor Hardener II\n" + "3x Large Capacitor Control Circuit I\n" + "3x Explosive Armor Hardener II\n" + "\n" + "Total m3 to be hauled: 50.665,00\n" + "Estimated market value: 225.404.694,17 isk"; Map data = test(text, 13); assertEquals(10, data.get("Hammerhead II"), 0.1); } private Map test(String text, int size) { Map data = importShoppingList.doImport(text); assertNotNull(data); assertEquals(size, data.size()); assertEquals(data.size(), importShoppingList.importText(text).size()); return data; } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/online/EveRefGetterOnlineTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.online; import ch.qos.logback.classic.Level; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; import java.util.TreeSet; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.sde.IndustryMaterial; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.ReprocessedMaterial; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.io.esi.EsiItemsGetter; import net.nikr.eve.jeveasset.io.online.EveRefGetter.EveRefActivity; import net.nikr.eve.jeveasset.io.online.EveRefGetter.EveRefBlueprint; import net.nikr.eve.jeveasset.io.online.EveRefGetter.EveRefType; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import net.nikr.eve.jeveasset.io.shared.ThreadWoker; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.Matchers.closeTo; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; import org.junit.rules.ErrorCollector; public class EveRefGetterOnlineTest extends TestUtil { private static final long MAX_RUNS = 500; private static final double DELTA = 0.0000001; @BeforeClass public static void setUpClass() { setLoggingLevel(Level.ERROR); } @AfterClass public static void tearDownClass() { setLoggingLevel(Level.INFO); } @ClassRule public static ErrorCollector collector = new ErrorCollector(); /** * Download test * @param args * @throws java.lang.InterruptedException */ public static void main(final String[] args) throws InterruptedException { initLog(); setUpClass(); EveRefGetterOnlineTest test = new EveRefGetterOnlineTest(); test.testDownloadItemsThreads(); System.exit(0); } @Test public void testDownloadItemsThreads() throws InterruptedException { List updates = new ArrayList<>(); Set typeIDs = new TreeSet<>(); List all = new ArrayList<>(StaticData.get().getItems().keySet()); if (MAX_RUNS > 0) { Collections.shuffle(all); //Randomize typeIDs.addAll(all.subList(0, (int)Math.min(MAX_RUNS, all.size()))); } else { typeIDs.addAll(all); } //Wrong data in SDE 2024-10-30 typeIDs.remove(81144); //PriceBase typeIDs.remove(84271); //Tech: Limited Time typeIDs.remove(84272); //Tech: Limited Time typeIDs.remove(84273); //Tech: Limited Time for (int i = 84297; i <= 84328; i++) { typeIDs.remove(i); //Tech: Limited Time } typeIDs.remove(85062); //Tech: Faction/ReprocessedMaterial typeIDs.remove(85229); //Tech: Faction/ReprocessedMaterial typeIDs.remove(85236); //Tech: Faction/ReprocessedMaterial typeIDs.remove(85279); //Tech: Limited Time typeIDs.remove(85747); //ReprocessedMaterial typeIDs.remove(85748); //BlueprintTypeIDs/ReprocessedMaterial typeIDs.remove(85749); //ProductTypeID typeIDs.remove(85750); //ProductTypeID/Faction/ReprocessedMaterial typeIDs.remove(85751); //ProductTypeID/Faction typeIDs.remove(85890); //Tech: Premium typeIDs.remove(85891); //Tech: Premium typeIDs.remove(85892); //Tech: Premium typeIDs.remove(85893); //Tech: Premium typeIDs.remove(85894); //Tech: Premium typeIDs.remove(85895); //Tech: Premium typeIDs.remove(85896); //Tech: Premium typeIDs.remove(85897); //Tech: Premium typeIDs.remove(85929); //Tech: Premium typeIDs.remove(85930); //Tech: Premium typeIDs.remove(85931); //Tech: Premium typeIDs.remove(85932); //Tech: Premium typeIDs.remove(86149); //Tech: Premium typeIDs.remove(86150); //Tech: Premium typeIDs.remove(86151); //Tech: Premium typeIDs.remove(86152); //Tech: Premium typeIDs.remove(86153); //Tech: Premium typeIDs.remove(86154); //Tech: Premium typeIDs.remove(86155); //Tech: Premium typeIDs.remove(86156); //Tech: Premium for (int typeID : typeIDs) { updates.add(new Download(typeID)); } //Download ThreadWoker.start(null, updates, false); //Test for (Download download : updates) { download.test(); } } private static class Download implements Runnable { private final int typeID; private final Item itemSDE; private Item itemEveRef; public Download(int typeID) { this.typeID = typeID; this.itemSDE = ApiIdConverter.getItem(typeID); } @Override public void run() { EsiItemsGetter esiItemsGetter = new EsiItemsGetter(typeID); esiItemsGetter.run(); itemEveRef = esiItemsGetter.getItem(); } public void test() { testItem(itemSDE, itemEveRef); } } @Test public void testMultiBlueprints() { test(22925); test(37161); } public void test(final int typeID) { Item itemSDE = ApiIdConverter.getItem(typeID); EsiItemsGetter esiItemsGetter = new EsiItemsGetter(typeID); esiItemsGetter.run(); Item itemEveRef = esiItemsGetter.getItem(); testItem(itemSDE, itemEveRef); } private static void testItem(Item itemSDE, Item itemEveRef) { String msg = "TypeID: " + itemSDE.getTypeID(); assertNotNull(msg + " itemSDE is null", itemSDE); assertNotNull(msg + " itemEveRef is null", itemEveRef); assertEquals(msg + " TypeID", itemSDE.getTypeID(), itemEveRef.getTypeID()); if (itemEveRef.getPriceBase() != 0 && itemEveRef.getPriceBase() != -1) { assertEquals(msg + " PriceBase", itemSDE.getPriceBase(), itemEveRef.getPriceBase(), DELTA); } assertEquals(msg + " Volume", itemSDE.getVolume(), itemEveRef.getVolume(), DELTA); assertEquals(msg + " VolumePackaged", itemSDE.getVolumePackaged(), itemEveRef.getVolumePackaged(), DELTA); assertEquals(msg + " Capacity", itemSDE.getCapacity(), itemEveRef.getCapacity(), DELTA); assertEquals(msg + " Meta", itemSDE.getMeta(), itemEveRef.getMeta()); assertEquals(msg + " MarketGroup", itemSDE.isMarketGroup(), itemEveRef.isMarketGroup()); assertEquals(msg + " PiMaterial", itemSDE.isPiMaterial(), itemEveRef.isPiMaterial()); assertEquals(msg + " Portion", itemSDE.getPortion(), itemEveRef.getPortion()); assertEquals(msg + " ProductTypeID", itemSDE.getProductTypeID(), itemEveRef.getProductTypeID()); testLists(msg + " BlueprintTypeIDs size", itemSDE.getBlueprintTypeIDs(), itemEveRef.getBlueprintTypeIDs(), new Tester() { @Override public void test(Integer sde, Integer eveRef) { assertEquals(msg + " BlueprintTypeIDs", sde, eveRef); } }); assertEquals(msg + " ProductQuantity", itemSDE.getProductQuantity(), itemEveRef.getProductQuantity()); assertEquals(msg + " Blueprint", itemSDE.isBlueprint(), itemEveRef.isBlueprint()); assertEquals(msg + " Formula", itemSDE.isFormula(), itemEveRef.isFormula()); /* //Don't test dynamic values assertEquals(msg, itemSDE.getPriceReprocessed(), itemEveRef.getPriceReprocessed(), DELTA); assertEquals(msg, itemSDE.getPriceReprocessedMax(), itemEveRef.getPriceReprocessedMax(), DELTA); assertEquals(msg, itemSDE.getPriceManufacturing(), itemEveRef.getPriceManufacturing(), DELTA); */ if (itemSDE.getTypeName().endsWith(".type")) { System.out.println("Ignorering: " + itemSDE.getTypeName()); } else { assertEquals(msg + " TypeName", itemSDE.getTypeName(), itemEveRef.getTypeName()); } assertEquals(msg + " Group", itemSDE.getGroup(), itemEveRef.getGroup()); assertEquals(msg + " Category", itemSDE.getCategory(), itemEveRef.getCategory()); assertEquals(msg + " Tech", itemSDE.getTech(), itemEveRef.getTech()); assertEquals(msg + " itemSDE Version", null, itemSDE.getVersion()); assertEquals(msg + " itemEveRef Version", itemEveRef.getVersion(), EsiItemsGetter.ESI_ITEM_VERSION); assertEquals(msg + " Slot", itemSDE.getSlot(), itemEveRef.getSlot()); assertEquals(msg + " ChargeSize", itemSDE.getChargeSize(), itemEveRef.getChargeSize()); testLists(msg + " ReprocessedMaterial", itemSDE.getReprocessedMaterial(), itemEveRef.getReprocessedMaterial(), new Comparator() { @Override public int compare(ReprocessedMaterial o1, ReprocessedMaterial o2) { return Integer.compare(o1.getTypeID(), o2.getTypeID()); } } , new Tester() { @Override public void test(ReprocessedMaterial sde, ReprocessedMaterial eveRef) { assertEquals(msg + " ReprocessedMaterial TypeID", sde.getTypeID(), eveRef.getTypeID()); assertEquals(msg + " ReprocessedMaterial Quantity", sde.getQuantity(), eveRef.getQuantity()); assertEquals(msg + " ReprocessedMaterial PortionSize", sde.getPortionSize(), eveRef.getPortionSize()); } }); testLists(msg, itemSDE.getManufacturingMaterials(), itemEveRef.getManufacturingMaterials(), new Comparator() { @Override public int compare(IndustryMaterial o1, IndustryMaterial o2) { return Integer.compare(o1.getTypeID(), o2.getTypeID()); } } , new Tester() { @Override public void test(IndustryMaterial sde, IndustryMaterial eveRef) { assertEquals(msg + " ManufacturingMaterials TypeID", sde.getTypeID(), eveRef.getTypeID()); assertEquals(msg + " ManufacturingMaterials Quantity", sde.getQuantity(), eveRef.getQuantity()); } }); testLists(msg, itemSDE.getReactionMaterials(), itemEveRef.getReactionMaterials(), new Comparator() { @Override public int compare(IndustryMaterial o1, IndustryMaterial o2) { return Integer.compare(o1.getTypeID(), o2.getTypeID()); } } , new Tester() { @Override public void test(IndustryMaterial sde, IndustryMaterial eveRef) { assertEquals(msg + " ReactionMaterials TypeID", sde.getTypeID(), eveRef.getTypeID()); assertEquals(msg + " ReactionMaterials Quantity", sde.getQuantity(), eveRef.getQuantity()); } }); } public static void assertNotNull(String message, Object object) { collector.checkThat(message, object, notNullValue()); } public static void assertNotNull(Object object) { collector.checkThat(object, notNullValue()); } public static void assertEquals(String message, Object expected, Object actual) { collector.checkThat(message, expected, equalTo(actual)); } public static void assertEquals(Object expected, Object actual) { collector.checkThat(expected, equalTo(actual)); } public static void assertEquals(String message, double expected, double actual, double delta) { collector.checkThat(message, expected, closeTo(actual, delta)); } public static void assertEquals(double expected, double actual, double delta) { collector.checkThat(expected, closeTo(actual, delta)); } private static void testLists(String msg, List sde, List eveRef, Comparator comparator, Tester tester) { Collections.sort(eveRef, comparator); Collections.sort(sde, comparator); testSortedLists(msg, sde, eveRef, tester); } private static > void testLists(String msg, Collection sde, Collection eveRef, Tester tester) { testLists(msg, new ArrayList<>(sde), new ArrayList<>(eveRef), tester); } private static > void testLists(String msg, List sde, List eveRef, Tester tester) { Collections.sort(eveRef); Collections.sort(sde); testSortedLists(msg, sde, eveRef, tester); } private static void testSortedLists(String msg, List sde, List eveRef, Tester tester) { assertEquals(msg, sde.size(), eveRef.size()); for (int i = 0; i < sde.size() && i < eveRef.size(); i++) { tester.test(sde.get(i), eveRef.get(i)); } } private static interface Tester { public void test(T sde, T eveRef); } @Test public void testGetBlueprint() { EveRefBlueprint blueprint = EveRefGetter.getBlueprint(999); assertEquals((Long)10L, blueprint.getMaxProductionLimit()); assertEquals((Long)999L, blueprint.getBlueprintTypeID()); EveRefActivity copying = blueprint.getCopying(); assertEquals((Long)14400L, copying.getTime()); EveRefActivity invention = blueprint.getInvention(); assertEquals(2, invention.getMaterials().size()); assertEquals((Integer)32, invention.getMaterials().get("20410").getQuantity()); assertEquals((Integer)20410, invention.getMaterials().get("20410").getTypeID()); assertEquals(1, invention.getProducts().size()); assertEquals(0.22, invention.getProducts().get("22431").getProbability(), 0.0001); assertEquals((Integer)1, invention.getProducts().get("22431").getQuantity()); assertEquals((Integer)22431, invention.getProducts().get("22431").getTypeID()); assertEquals((Long)192000L, invention.getTime()); assertEquals((Long)1L, invention.getRequiredSkills().get("11450")); assertEquals((Long)1L, invention.getRequiredSkills().get("11452")); assertEquals((Long)1L, invention.getRequiredSkills().get("23121")); EveRefActivity manufacturing = blueprint.getManufacturing(); assertEquals(10, manufacturing.getMaterials().size()); assertEquals((Integer)8000000, manufacturing.getMaterials().get("34").getQuantity()); assertEquals((Integer)34, manufacturing.getMaterials().get("34").getTypeID()); assertEquals(1, manufacturing.getProducts().size()); assertEquals((Integer)1, manufacturing.getProducts().get("645").getQuantity()); assertEquals((Integer)645, manufacturing.getProducts().get("645").getTypeID()); assertEquals((Long)18000L, manufacturing.getTime()); assertEquals((Long)1L, manufacturing.getRequiredSkills().get("3380")); EveRefActivity me = blueprint.getResearchMaterial(); assertEquals((Long)6300L, me.getTime()); EveRefActivity te = blueprint.getResearchTime(); assertEquals((Long)6300L, te.getTime()); } @Test public void testGetType() { EveRefType type = EveRefGetter.getType(645); assertEquals((Long)645L, type.getTypeID()); assertEquals((Double)153900000.0, type.getBasePrice()); assertEquals((Double)750.0, type.getCapacity()); assertEquals(8, type.getDescription().size()); assertNotNull(type.getDescription().get("en")); assertNotNull(type.getDogmaAttributes()); assertEquals(92, type.getDogmaAttributes().size()); assertNotNull(type.getDogmaAttributes().get("3")); assertEquals((Long)3L, type.getDogmaAttributes().get("3").getAttributeID()); assertEquals((Double)0.0, type.getDogmaAttributes().get("3").getValue(), DELTA); assertNotNull(type.getDogmaEffects()); assertEquals(5, type.getDogmaEffects().size()); assertNotNull(type.getDogmaEffects().get("2186")); assertEquals((Long)2186L, type.getDogmaEffects().get("2186").getEffectID()); assertEquals(false, type.getDogmaEffects().get("2186").isDefault()); assertEquals((Long)500004L, type.getFactionID()); assertEquals((Long)318L, type.getGraphicID()); assertEquals((Long)27L, type.getGroupID()); //assertEquals(LONG_VALUE, type.getIconID()); assertEquals((Long)81L, type.getMarketGroupID()); assertEquals((Double)100250000.0, type.getMass()); assertEquals(5, type.getMasteries().size()); assertEquals(6, type.getMasteries().get("0").size()); assertEquals((Long)96L, type.getMasteries().get("0").get(0)); assertEquals((Integer)1, type.getMetaGroupID()); assertEquals(8, type.getName().size()); assertEquals("Dominix", type.getName().get("en")); assertEquals((Double)50000.0, type.getPackagedVolume()); assertEquals((Integer)1, type.getPortionSize()); assertEquals(true, type.isPublished()); assertEquals((Long)8L, type.getRaceID()); assertEquals((Double)250.0, type.getRadius()); assertEquals("gallentebase", type.getSofFactionName()); //assertEquals((Long)0L, type.getSofMaterialSetID()); assertEquals((Long)20072L, type.getSoundID()); assertNotNull(type.getTraits()); assertNotNull(type.getTraits().getMiscBonuses()); assertEquals(0, type.getTraits().getMiscBonuses().size()); /* assertNotNull(type.getTraits().getMiscBonuses().get(MAP_VALUE)); assertEquals(DOUBLE_VALUE, type.getTraits().getMiscBonuses().get(MAP_VALUE).getBonus(), DELTA); assertNotNull(type.getTraits().getMiscBonuses().get(MAP_VALUE).getBonusText()); assertEquals(STRING_VALUE, type.getTraits().getMiscBonuses().get(MAP_VALUE).getBonusText().get(MAP_VALUE)); assertEquals(LONG_VALUE, type.getTraits().getMiscBonuses().get(MAP_VALUE).getImportance()); assertEquals(LONG_VALUE, type.getTraits().getMiscBonuses().get(MAP_VALUE).getUnitID()); assertEquals(BOOLEAN_VALUE, type.getTraits().getMiscBonuses().get(MAP_VALUE).isPositive()); */ assertEquals(3, type.getTraits().getRoleBonuses().size()); assertNotNull(type.getTraits().getRoleBonuses().get("1")); assertEquals((Double)100.0, type.getTraits().getRoleBonuses().get("1").getBonus(), DELTA); assertNotNull(type.getTraits().getRoleBonuses().get("1").getBonusText()); assertNotNull(type.getTraits().getRoleBonuses().get("1").getBonusText().get("en")); assertEquals((Long)1L, type.getTraits().getRoleBonuses().get("1").getImportance()); assertEquals((Long)105L, type.getTraits().getRoleBonuses().get("1").getUnitID()); //assertEquals(BOOLEAN_VALUE, type.getTraits().getRoleBonuses().get("1").isPositive()); assertNotNull(type.getTraits().getTypes()); //Map 1 assertEquals(1, type.getTraits().getTypes().size()); assertNotNull(type.getTraits().getTypes().get("3336")); //Map 2 assertEquals(2, type.getTraits().getTypes().get("3336").size()); assertNotNull(type.getTraits().getTypes().get("3336").get("1")); //RoleBonus assertNotNull(type.getTraits().getTypes().get("3336").get("1").getBonus()); assertEquals((Double)10.0, type.getTraits().getTypes().get("3336").get("1").getBonus(), DELTA); assertNotNull(type.getTraits().getTypes().get("3336").get("1").getBonusText()); assertNotNull(type.getTraits().getTypes().get("3336").get("1").getBonusText().get("en")); assertEquals((Long)1L, type.getTraits().getTypes().get("3336").get("1").getImportance()); assertEquals((Long)105L, type.getTraits().getTypes().get("3336").get("1").getUnitID()); //assertEquals(BOOLEAN_VALUE, type.getTraits().getTypes().get("3336").get("1").isPositive()); //assertEquals(LONG_VALUE, type.getVariationParentTypeID()); assertEquals((Double)454500.0, type.getVolume()); assertNotNull(type.getRequiredSkills()); assertEquals(1, type.getRequiredSkills().size()); assertEquals((Long)1L, type.getRequiredSkills().get("3336")); //assertEquals(ARRAY_LENGTH, type.getApplicableMutaplasmidTypeIDS().size()); //assertEquals(LONG_VALUE, type.getApplicableMutaplasmidTypeIDS().get(0)); //assertEquals(ARRAY_LENGTH, type.getCreatingMutaplasmidTypeIDS().size()); //assertEquals(LONG_VALUE, type.getCreatingMutaplasmidTypeIDS().get(0)); assertNotNull(type.getTypeVariations()); assertEquals(3, type.getTypeVariations().size()); assertEquals(1, type.getTypeVariations().get("1").size()); assertEquals((Long)645L, type.getTypeVariations().get("1").get(0)); /* assertNotNull(type.getOreVariations()); assertEquals(MAP_LENGTH, type.getOreVariations().size()); assertEquals(ARRAY_LENGTH, type.getOreVariations().get(MAP_VALUE).size()); assertEquals(LONG_VALUE, type.getOreVariations().get(MAP_VALUE).get(0)); */ //assertEquals(BOOLEAN_VALUE, type.isOre()); assertNotNull(type.getProducedByBlueprints()); assertEquals(1, type.getProducedByBlueprints().size()); assertNotNull(type.getProducedByBlueprints().get("999")); assertEquals("manufacturing", type.getProducedByBlueprints().get("999").getBlueprintActivity()); assertEquals((Integer)999, type.getProducedByBlueprints().get("999").getBlueprintTypeID()); assertNotNull(type.getTypeMaterials()); assertEquals(7, type.getTypeMaterials().size()); assertNotNull(type.getTypeMaterials().get("34")); assertEquals((Integer)34, type.getTypeMaterials().get("34").getMaterialTypeID()); assertEquals((Integer)8000000, type.getTypeMaterials().get("34").getQuantity()); //assertEquals(ARRAY_LENGTH, type.getCanFitTypes().size()); //assertEquals(LONG_VALUE, type.getCanFitTypes().get(0)); //assertEquals(ARRAY_LENGTH, type.getCanBeFittedWithTypes().size()); //assertEquals(LONG_VALUE, type.getCanBeFittedWithTypes().get(0)); //assertEquals(BOOLEAN_VALUE, type.isSkill()); //assertEquals(BOOLEAN_VALUE, type.isMutaplasmid()); //assertEquals(BOOLEAN_VALUE, type.isDynamicItem()); //assertEquals(BOOLEAN_VALUE, type.isBlueprint()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/online/EveRefGetterTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.online; import ch.qos.logback.classic.Level; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.lang.reflect.Field; import java.net.URISyntaxException; import java.net.URL; import net.nikr.eve.jeveasset.TestUtil; import static net.nikr.eve.jeveasset.TestUtil.initLog; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.io.online.EveRefGetter.EveRefActivity; import net.nikr.eve.jeveasset.io.online.EveRefGetter.EveRefBlueprint; import net.nikr.eve.jeveasset.io.online.EveRefGetter.EveRefType; import org.junit.AfterClass; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.junit.Test; import org.junit.BeforeClass; public class EveRefGetterTest extends TestUtil { private static final Gson GSON = new GsonBuilder().create(); private static final Long LONG_VALUE = 10L; private static final Integer INTEGER_VALUE = 10; private static final Double DOUBLE_VALUE = 10.0; private static final String STRING_VALUE = "string"; private static final boolean BOOLEAN_VALUE = true; private static final String MAP_VALUE = "additionalProp1"; private static final int MAP_LENGTH = 3; private static final int ARRAY_LENGTH = 1; private static final double DELTA = 0.0000001; @BeforeClass public static void setUpClass() { setLoggingLevel(Level.ERROR); } @AfterClass public static void tearDownClass() { setLoggingLevel(Level.INFO); } @Test public void testBlueprintModel() throws URISyntaxException, FileNotFoundException { URL resource = EveRefGetterTest.class.getResource("/everefblueprint.json"); File file = new File(resource.toURI()); FileReader input = new FileReader(file); EveRefBlueprint blueprint = GSON.fromJson(input, new TypeToken() {}.getType()); assertEquals(LONG_VALUE, blueprint.getMaxProductionLimit()); assertEquals(LONG_VALUE, blueprint.getBlueprintTypeID()); EveRefActivity activity = blueprint.getActivities().get(MAP_VALUE); assertEquals(LONG_VALUE, activity.getTime()); assertEquals(MAP_LENGTH, activity.getMaterials().size()); assertEquals(INTEGER_VALUE, activity.getMaterials().get(MAP_VALUE).getQuantity()); assertEquals(INTEGER_VALUE, activity.getMaterials().get(MAP_VALUE).getTypeID()); assertEquals(MAP_LENGTH, activity.getProducts().size()); assertEquals(DOUBLE_VALUE, activity.getProducts().get(MAP_VALUE).getProbability(), DELTA); assertEquals(INTEGER_VALUE, activity.getProducts().get(MAP_VALUE).getQuantity()); assertEquals(INTEGER_VALUE, activity.getProducts().get(MAP_VALUE).getTypeID()); assertEquals(LONG_VALUE, activity.getRequiredSkills().get(MAP_VALUE)); } @Test public void testItemModel() throws FileNotFoundException, URISyntaxException { URL resource = EveRefGetterTest.class.getResource("/evereftype.json"); File file = new File(resource.toURI()); FileReader input = new FileReader(file); EveRefType type = GSON.fromJson(input, new TypeToken() {}.getType()); assertEquals(LONG_VALUE, type.getTypeID()); assertEquals(DOUBLE_VALUE, type.getBasePrice()); assertEquals(DOUBLE_VALUE, type.getCapacity()); assertEquals(MAP_LENGTH, type.getDescription().size()); assertEquals(STRING_VALUE, type.getDescription().get(MAP_VALUE)); assertNotNull(type.getDogmaAttributes()); assertEquals(MAP_LENGTH, type.getDogmaAttributes().size()); assertNotNull(type.getDogmaAttributes().get(MAP_VALUE)); assertEquals(LONG_VALUE, type.getDogmaAttributes().get(MAP_VALUE).getAttributeID()); assertEquals(DOUBLE_VALUE, type.getDogmaAttributes().get(MAP_VALUE).getValue(), DELTA); assertNotNull(type.getDogmaEffects()); assertEquals(MAP_LENGTH, type.getDogmaEffects().size()); assertNotNull(type.getDogmaEffects().get(MAP_VALUE)); assertEquals(LONG_VALUE, type.getDogmaEffects().get(MAP_VALUE).getEffectID()); assertEquals(BOOLEAN_VALUE, type.getDogmaEffects().get(MAP_VALUE).isDefault()); assertEquals(LONG_VALUE, type.getFactionID()); assertEquals(LONG_VALUE, type.getGraphicID()); assertEquals(LONG_VALUE, type.getGroupID()); assertEquals(LONG_VALUE, type.getIconID()); assertEquals(LONG_VALUE, type.getMarketGroupID()); assertEquals(DOUBLE_VALUE, type.getMass()); assertEquals(MAP_LENGTH, type.getMasteries().size()); assertEquals(ARRAY_LENGTH, type.getMasteries().get(MAP_VALUE).size()); assertEquals(LONG_VALUE, type.getMasteries().get(MAP_VALUE).get(0)); assertEquals(INTEGER_VALUE, type.getMetaGroupID()); assertEquals(MAP_LENGTH, type.getName().size()); assertEquals(STRING_VALUE, type.getName().get(MAP_VALUE)); assertEquals(DOUBLE_VALUE, type.getPackagedVolume()); assertEquals(INTEGER_VALUE, type.getPortionSize()); assertEquals(BOOLEAN_VALUE, type.isPublished()); assertEquals(LONG_VALUE, type.getRaceID()); assertEquals(DOUBLE_VALUE, type.getRadius()); assertEquals(STRING_VALUE, type.getSofFactionName()); assertEquals(LONG_VALUE, type.getSofMaterialSetID()); assertEquals(LONG_VALUE, type.getSoundID()); assertNotNull(type.getTraits()); assertNotNull(type.getTraits().getMiscBonuses()); assertEquals(MAP_LENGTH, type.getTraits().getMiscBonuses().size()); assertNotNull(type.getTraits().getMiscBonuses().get(MAP_VALUE)); assertEquals(DOUBLE_VALUE, type.getTraits().getMiscBonuses().get(MAP_VALUE).getBonus(), DELTA); assertNotNull(type.getTraits().getMiscBonuses().get(MAP_VALUE).getBonusText()); assertEquals(STRING_VALUE, type.getTraits().getMiscBonuses().get(MAP_VALUE).getBonusText().get(MAP_VALUE)); assertEquals(LONG_VALUE, type.getTraits().getMiscBonuses().get(MAP_VALUE).getImportance()); assertEquals(LONG_VALUE, type.getTraits().getMiscBonuses().get(MAP_VALUE).getUnitID()); assertEquals(BOOLEAN_VALUE, type.getTraits().getMiscBonuses().get(MAP_VALUE).isPositive()); assertEquals(MAP_LENGTH, type.getTraits().getRoleBonuses().size()); assertNotNull(type.getTraits().getRoleBonuses().get(MAP_VALUE)); assertEquals(DOUBLE_VALUE, type.getTraits().getRoleBonuses().get(MAP_VALUE).getBonus(), DELTA); assertNotNull(type.getTraits().getRoleBonuses().get(MAP_VALUE).getBonusText()); assertEquals(STRING_VALUE, type.getTraits().getRoleBonuses().get(MAP_VALUE).getBonusText().get(MAP_VALUE)); assertEquals(LONG_VALUE, type.getTraits().getRoleBonuses().get(MAP_VALUE).getImportance()); assertEquals(LONG_VALUE, type.getTraits().getRoleBonuses().get(MAP_VALUE).getUnitID()); assertEquals(BOOLEAN_VALUE, type.getTraits().getRoleBonuses().get(MAP_VALUE).isPositive()); assertNotNull(type.getTraits().getTypes()); //Map 1 assertEquals(MAP_LENGTH, type.getTraits().getTypes().size()); assertNotNull(type.getTraits().getTypes().get(MAP_VALUE)); //Map 2 assertEquals(MAP_LENGTH, type.getTraits().getTypes().get(MAP_VALUE).size()); assertNotNull(type.getTraits().getTypes().get(MAP_VALUE).get(MAP_VALUE)); //RoleBonus assertNotNull(type.getTraits().getTypes().get(MAP_VALUE).get(MAP_VALUE).getBonus()); assertEquals(DOUBLE_VALUE, type.getTraits().getTypes().get(MAP_VALUE).get(MAP_VALUE).getBonus(), DELTA); assertNotNull(type.getTraits().getTypes().get(MAP_VALUE).get(MAP_VALUE).getBonusText()); assertEquals(STRING_VALUE, type.getTraits().getTypes().get(MAP_VALUE).get(MAP_VALUE).getBonusText().get(MAP_VALUE)); assertEquals(LONG_VALUE, type.getTraits().getTypes().get(MAP_VALUE).get(MAP_VALUE).getImportance()); assertEquals(LONG_VALUE, type.getTraits().getTypes().get(MAP_VALUE).get(MAP_VALUE).getUnitID()); assertEquals(BOOLEAN_VALUE, type.getTraits().getTypes().get(MAP_VALUE).get(MAP_VALUE).isPositive()); assertEquals(LONG_VALUE, type.getVariationParentTypeID()); assertEquals(DOUBLE_VALUE, type.getVolume()); assertNotNull(type.getRequiredSkills()); assertEquals(MAP_LENGTH, type.getRequiredSkills().size()); assertEquals(LONG_VALUE, type.getRequiredSkills().get(MAP_VALUE)); assertEquals(ARRAY_LENGTH, type.getApplicableMutaplasmidTypeIDS().size()); assertEquals(LONG_VALUE, type.getApplicableMutaplasmidTypeIDS().get(0)); assertEquals(ARRAY_LENGTH, type.getCreatingMutaplasmidTypeIDS().size()); assertEquals(LONG_VALUE, type.getCreatingMutaplasmidTypeIDS().get(0)); assertNotNull(type.getTypeVariations()); assertEquals(MAP_LENGTH, type.getTypeVariations().size()); assertEquals(ARRAY_LENGTH, type.getTypeVariations().get(MAP_VALUE).size()); assertEquals(LONG_VALUE, type.getTypeVariations().get(MAP_VALUE).get(0)); assertNotNull(type.getOreVariations()); assertEquals(MAP_LENGTH, type.getOreVariations().size()); assertEquals(ARRAY_LENGTH, type.getOreVariations().get(MAP_VALUE).size()); assertEquals(LONG_VALUE, type.getOreVariations().get(MAP_VALUE).get(0)); assertEquals(BOOLEAN_VALUE, type.isOre()); assertNotNull(type.getProducedByBlueprints()); assertEquals(MAP_LENGTH, type.getProducedByBlueprints().size()); assertNotNull(type.getProducedByBlueprints().get(MAP_VALUE)); assertEquals(STRING_VALUE, type.getProducedByBlueprints().get(MAP_VALUE).getBlueprintActivity()); assertEquals(INTEGER_VALUE, type.getProducedByBlueprints().get(MAP_VALUE).getBlueprintTypeID()); assertNotNull(type.getTypeMaterials()); assertEquals(MAP_LENGTH, type.getTypeMaterials().size()); assertNotNull(type.getTypeMaterials().get(MAP_VALUE)); assertEquals(INTEGER_VALUE, type.getTypeMaterials().get(MAP_VALUE).getMaterialTypeID()); assertEquals(INTEGER_VALUE, type.getTypeMaterials().get(MAP_VALUE).getQuantity()); assertEquals(ARRAY_LENGTH, type.getCanFitTypes().size()); assertEquals(LONG_VALUE, type.getCanFitTypes().get(0)); assertEquals(ARRAY_LENGTH, type.getCanBeFittedWithTypes().size()); assertEquals(LONG_VALUE, type.getCanBeFittedWithTypes().get(0)); assertEquals(BOOLEAN_VALUE, type.isSkill()); assertEquals(BOOLEAN_VALUE, type.isMutaplasmid()); assertEquals(BOOLEAN_VALUE, type.isDynamicItem()); assertEquals(BOOLEAN_VALUE, type.isBlueprint()); } /** * Null test * @param args */ public static void main(final String[] args) { initLog(); EveRefGetterTest test = new EveRefGetterTest(); test.testNullTest(); System.exit(0); } @Test public void testNullTest() { Item item = new Item(0); assertNotNull(EveRefGetter.getItem(item, null, null)); EveRefType type = new EveRefType(); assertNotNull(EveRefGetter.getItem(item, type, null)); assertNull(type.isBlueprint()); setField(type, "blueprint", true); assertTrue(type.isBlueprint()); assertNotNull(EveRefGetter.getItem(item, type, null)); EveRefBlueprint blueprint = new EveRefBlueprint(); assertNotNull(EveRefGetter.getItem(item, type, blueprint)); } private static void setField(Object cc, String field, Object value) { try { Field f1 = cc.getClass().getDeclaredField(field); f1.setAccessible(true); f1.set(cc, value); f1.setAccessible(false); } catch (NoSuchFieldException ex) { fail(ex.getMessage()); } catch (SecurityException ex) { fail(ex.getMessage()); } catch (IllegalArgumentException ex) { fail(ex.getMessage()); } catch (IllegalAccessException ex) { fail(ex.getMessage()); } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/online/PriceDataGetterOnlineTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.online; import ch.qos.logback.classic.Level; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Proxy; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.PriceData; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings.PriceSource; import net.nikr.eve.jeveasset.data.settings.PriceHistoryDatabase; import net.nikr.eve.jeveasset.gui.shared.Formatter; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import org.junit.After; import org.junit.AfterClass; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import uk.me.candle.eve.pricing.impl.Janice.JaniceLocation; import uk.me.candle.eve.pricing.options.LocationType; import uk.me.candle.eve.pricing.options.NamedPriceLocation; import uk.me.candle.eve.pricing.options.PriceLocation; import uk.me.candle.eve.pricing.options.PricingOptions; public class PriceDataGetterOnlineTest extends TestUtil { private static final String JANICE_API_KEY = "JANICE_API_KEY"; private static String JANICE_KEY; private static final long REGION_THE_FORGE = 10000002L; //The Forge (Jita region) private static final long SYSTEM_JITA = 30000142L; //Jita private static final long STATION_JITA_4_4 = 60003760L; //Jita 4 - 4 private static final long MAX_RUNS = 500; private final PriceGetter getter = new PriceGetter(); private final Set typeIDs = new HashSet<>(); public PriceDataGetterOnlineTest() { } @BeforeClass public static void setUpClass() { setLoggingLevel(Level.ERROR); JANICE_KEY = System.getenv().get(JANICE_API_KEY); PriceHistoryDatabase.load(); } @AfterClass public static void tearDownClass() { setLoggingLevel(Level.INFO); } @Before public void setUp() { Set ids = new HashSet<>(); for (Item item : StaticData.get().getItems().values()) { if (item.isMarketGroup()) { ids.add(item.getTypeID()); } } if (MAX_RUNS > 0) { List list = new ArrayList<>(ids); Collections.shuffle(list); //Randomize typeIDs.addAll(list.subList(0, (int)Math.min(MAX_RUNS, list.size()))); } else { typeIDs.addAll(ids); } } @After public void tearDown() { typeIDs.clear(); } @Test public void testAll() { long time = System.currentTimeMillis(); for (PriceSource source : PriceSource.values()) { test(source); } System.out.println("All tests completed in: " + Formatter.milliseconds(System.currentTimeMillis() - time)); } private void test(PriceSource source) { if (source.supportRegions()) { test(source, LocationType.REGION, ApiIdConverter.getLocation(REGION_THE_FORGE)); } if (source.supportSystems()) { test(source, LocationType.SYSTEM, ApiIdConverter.getLocation(SYSTEM_JITA)); } if (source.supportStations()) { if (source == PriceSource.JANICE) { for (JaniceLocation location : JaniceLocation.values()) { test(source, LocationType.STATION, location.getPriceLocation()); } } else { test(source, LocationType.STATION, ApiIdConverter.getLocation(STATION_JITA_4_4)); } } } private void test(PriceSource source, LocationType locationType, NamedPriceLocation location) { TestPricingOptions options = new TestPricingOptions(locationType, location); String msg = source.toString() + " (" + options.getLocationType().name().toLowerCase() + " - " + location.getLocation() + " - " + typeIDs.size() + " IDs)"; System.out.println(msg); if (source == PriceSource.JANICE && JANICE_KEY != null) { options.addHeader("X-ApiKey", JANICE_KEY); } long start = System.currentTimeMillis(); Map process = getter.process(options, typeIDs, source); long end = System.currentTimeMillis(); assertNotNull(msg, process); Set failed = new TreeSet<>(typeIDs); failed.removeAll(process.keySet()); Set empty = new TreeSet<>(); for (Map.Entry entry : process.entrySet()) { assertNotNull(msg, entry.getValue()); if (entry.getValue().isEmpty()) { empty.add(entry.getKey()); } } System.out.println(" " + process.size() + " of " + typeIDs.size() + " done - " + empty.size() + " empty - " + failed.size() + " failed - completed in: " + Formatter.milliseconds(end - start)); assertTrue(msg, failed.isEmpty()); assertTrue(msg, process.size() >= typeIDs.size()); } private static class PriceGetter extends PriceDataGetter { protected Map process(PricingOptions pricingOptions, Set ids, PriceSource source) { return super.processUpdate(null, true, pricingOptions, ids, source); } } private static class TestPricingOptions implements PricingOptions { private final LocationType locationType; private final PriceLocation location; public TestPricingOptions(LocationType locationType, PriceLocation location) { this.locationType = locationType; this.location = location; } @Override public long getPriceCacheTimer() { return 60*60*1000L; // 1 hour } @Override public PriceLocation getLocation() { return location; } @Override public LocationType getLocationType() { return locationType; } @Override public InputStream getCacheInputStream() throws IOException { return null; } @Override public OutputStream getCacheOutputStream() throws IOException { return null; } @Override public boolean getCacheTimersEnabled() { return false; } @Override public Proxy getProxy() { return Proxy.NO_PROXY; } @Override public int getAttemptCount() { return 1; } @Override public boolean getUseBinaryErrorSearch() { return false; } @Override public int getTimeout() { return 2000; } @Override public String getUserAgent() { return Program.PROGRAM_USER_AGENT; } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/online/ProxyTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.online; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Proxy; import java.util.HashSet; import java.util.Set; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings.PriceSource; import net.nikr.eve.jeveasset.data.settings.ProxyData; import net.nikr.eve.jeveasset.io.esi.EsiCallbackURL; import net.nikr.eve.jeveasset.io.esi.EsiOwnerGetter; import net.nikr.eve.jeveasset.io.shared.ApiIdConverter; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import uk.me.candle.eve.pricing.options.LocationType; import uk.me.candle.eve.pricing.options.PriceLocation; import uk.me.candle.eve.pricing.options.PricingOptions; public class ProxyTest extends TestUtil { private ProxyData proxyData; private static final Set TYPE_IDS = new HashSet<>(); @AfterClass public static void afterClass() { ProxyData proxyData = new ProxyData(); } @BeforeClass public static void beforeClass() { for (Item item : StaticData.get().getItems().values()) { if (TYPE_IDS.size() >= 40) { break; } if (item.isMarketGroup()) { TYPE_IDS.add(item.getTypeID()); } } } @Before public void before() { System.setProperty("jdk.http.auth.tunneling.disabledSchemes", ""); System.setProperty("jdk.http.auth.proxying.disabledSchemes", ""); } public void testHTTP() { proxyData = new ProxyData("0.0.0.0", Proxy.Type.HTTP, 808, "root", "haha"); testConnections(); } public void testSOCKS() { proxyData = new ProxyData("0.0.0.0", Proxy.Type.SOCKS, 1080, "root", "haha"); testConnections(); } public void testUpdateHTTP() { proxyData = new ProxyData("0.0.0.0", Proxy.Type.HTTP, 808, "root", "haha"); testUpdate(); } public void testUpdateSOCKS() { proxyData = new ProxyData("0.0.0.0", Proxy.Type.SOCKS, 1080, "root", "haha"); testUpdate(); } private void testConnections() { //ESI EsiOwner esiOwner = EsiOwner.create(); esiOwner.setAuth(EsiCallbackURL.LOCALHOST, null, null); EsiOwnerGetter esi = new EsiOwnerGetter(esiOwner, false); esi.start(); //Price PriceDataGetterMock price = new PriceDataGetterMock(); price.update(); } private void testUpdate() { //Update Updater updater = new Updater(); updater.update("DoNotMatch", "DoNotMatch", proxyData); } private class PriceDataGetterMock extends PriceDataGetter { protected void update() { super.processUpdate(null, true, new TestPricingOptions(), TYPE_IDS, PriceSource.FUZZWORK); } } private class TestPricingOptions implements PricingOptions { @Override public long getPriceCacheTimer() { return 60*60*1000l; // 1 hour } @Override public PriceLocation getLocation() { return ApiIdConverter.getLocation(10000002L); } @Override public LocationType getLocationType() { return LocationType.REGION; } @Override public boolean getUseBinaryErrorSearch() { return false; } @Override public InputStream getCacheInputStream() throws IOException { return null; } @Override public OutputStream getCacheOutputStream() throws IOException { return null; } @Override public boolean getCacheTimersEnabled() { return true; } @Override public Proxy getProxy() { return null; } @Override public int getAttemptCount() { return 2; } @Override public int getTimeout() { return 20000; } @Override public String getUserAgent() { return Program.PROGRAM_USER_AGENT; } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/online/ZkillboardPricesHistoryGetterOnlineTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.online; import java.util.Map; import net.nikr.eve.jeveasset.TestUtil; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import org.junit.Test; public class ZkillboardPricesHistoryGetterOnlineTest extends TestUtil { @Test public void testGetPrice() { Map priceHistory; priceHistory = ZkillboardPricesHistoryGetter.getPriceHistory(34); assertNotNull(priceHistory); priceHistory = ZkillboardPricesHistoryGetter.getPriceHistory(638); assertNotNull(priceHistory); try { Thread.sleep(1100); } catch (InterruptedException ex) { fail(ex.getMessage()); } priceHistory = ZkillboardPricesHistoryGetter.getPriceHistory(35); assertNotNull(priceHistory); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/shared/ApiIdConverterOnlineTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.StaticData; import org.junit.Test; public class ApiIdConverterOnlineTest extends TestUtil { private static final long MAX_IDS = 500; private static final long MAX_RUNS = 100; @Test public void testDownloadItemsThreads() throws InterruptedException { testDownloadItemsThreads(false); } @Test public void testUpdateItem() throws InterruptedException { testDownloadItemsThreads(true); } public void testDownloadItemsThreads(boolean updateItems) throws InterruptedException { ApiIdConverter.setUpdateItem(true); Set typeIDs = new HashSet<>(); List all = new ArrayList<>(StaticData.get().getItems().keySet()); if (MAX_IDS > 0) { Collections.shuffle(all); //Randomize typeIDs.addAll(all.subList(0, (int)Math.min(MAX_RUNS, all.size()))); } else { typeIDs.addAll(all); } List updates = new ArrayList<>(); Map removed = new HashMap<>(); for (Integer typeID : typeIDs) { removed.put(typeID, StaticData.get().getItems().remove(typeID)); } if (updateItems) { for (Integer typeID : typeIDs) { updates.add(new UpdateItem(typeID)); } } for (int i= 0; i < MAX_RUNS; i++ ) { for (Integer typeID : typeIDs) { updates.add(new Download(typeID)); } } for (Thread thread : updates) { thread.start(); } for (Thread thread : updates) { thread.join(); } for (Map.Entry entry : removed.entrySet()) { StaticData.get().getItems().put(entry.getKey(), entry.getValue()); } ApiIdConverter.setUpdateItem(false); } private static class Download extends Thread { private final int typeID; public Download(int typeID) { this.typeID = typeID; } @Override public void run() { ApiIdConverter.synchronizedDownloadItem(typeID); } } private static class UpdateItem extends Thread { private final int typeID; public UpdateItem(int typeID) { this.typeID = typeID; } @Override public void run() { ApiIdConverter.updateItem(typeID); } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/shared/ApiIdConverterTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.util.HashMap; import java.util.Map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.sde.IndustryMaterial; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingFacility; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingRigs; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings.ManufacturingSecurity; import net.nikr.eve.jeveasset.gui.shared.Formatter; import org.junit.Test; public class ApiIdConverterTest extends TestUtil { private static final double DOMINIX_BASE_PRICE = 130_856_251.94; /** * Tested against Isk Per Hour 2023-06-24 */ @Test public void testInstallationFee() { Item item = ApiIdConverter.getItem(645); //Dominix float systemIndex = 0.001f; ManufacturingSettings manufacturingSettings = new ManufacturingSettings(); manufacturingSettings.setFacility(ManufacturingFacility.STATION); manufacturingSettings.setRigs(ManufacturingRigs.NONE); manufacturingSettings.setSecurity(ManufacturingSecurity.HIGHSEC); manufacturingSettings.setTax(0.25); testInstallationFee(manufacturingSettings, item, systemIndex, 785_137.51); manufacturingSettings.setTax(0.0); manufacturingSettings.setFacility(ManufacturingFacility.ENGINEERING_COMPLEX_MEDIUM); testInstallationFee(manufacturingSettings, item, systemIndex, 454_071.91); manufacturingSettings.setFacility(ManufacturingFacility.ENGINEERING_COMPLEX_LARGE); testInstallationFee(manufacturingSettings, item, systemIndex, 452_762.63); manufacturingSettings.setFacility(ManufacturingFacility.ENGINEERING_COMPLEX_XLARGE); testInstallationFee(manufacturingSettings, item, systemIndex, 451_454.07); manufacturingSettings.setTax(0.25); manufacturingSettings.setFacility(ManufacturingFacility.ENGINEERING_COMPLEX_MEDIUM); testInstallationFee(manufacturingSettings, item, systemIndex, 781_211.82); manufacturingSettings.setFacility(ManufacturingFacility.ENGINEERING_COMPLEX_LARGE); testInstallationFee(manufacturingSettings, item, systemIndex, 779_903.26); manufacturingSettings.setFacility(ManufacturingFacility.ENGINEERING_COMPLEX_XLARGE); testInstallationFee(manufacturingSettings, item, systemIndex, 778_594.70); systemIndex = 0.2321f; manufacturingSettings.setFacility(ManufacturingFacility.STATION); testInstallationFee(manufacturingSettings, item, systemIndex, 31_026_017.35); } public void testInstallationFee(ManufacturingSettings manufacturingSettings, Item item, Float systemIndex, double expected) { double actual = ApiIdConverter.getManufacturingInstallationFee(manufacturingSettings, systemIndex, DOMINIX_BASE_PRICE, item); assertEquals(Formatter.doubleFormat(actual) + "!=" + Formatter.doubleFormat(expected), expected,actual , 1); } /** * Tested against Isk Per Hour and Fuzzwork 2025-04-03 */ @Test public void testManufacturingQuantity() { System.out.println(" --- Default ---"); int me = 0; ManufacturingFacility facility = ManufacturingFacility.ENGINEERING_COMPLEX_XLARGE; ManufacturingRigs rigs = ManufacturingRigs.NONE; ManufacturingSecurity security = ManufacturingSecurity.LOWSEC; double runs = 1; Map expected = new HashMap<>(); expected.put(34, 5_148_000.0); //Tritanium expected.put(35, 2_574_000.0); //Pyerite expected.put(36, 386_100.0); //Mexallon expected.put(37, 128_700.0); //Isogen expected.put(38, 15_444.0); //Nocxium expected.put(39, 3_861.0); //Zydrine expected.put(40, 1_931.0); //Megacyte expected.put(57478, 149.0); //Auto-Integrity Preservation Seal expected.put(57486, 75.0); //Life Support Backup Unit expected.put(57479, 1.0); //Core Temperature Regulator testManufacturingQuantity(expected, me, facility, rigs, security, runs); } /** * Tested against Isk Per Hour and Fuzzwork 2024-10-06 */ @Test public void testManufacturingQuantityMe() { System.out.println(" --- ME ---"); int me = 10; ManufacturingFacility facility = ManufacturingFacility.ENGINEERING_COMPLEX_XLARGE; ManufacturingRigs rigs = ManufacturingRigs.NONE; ManufacturingSecurity security = ManufacturingSecurity.HIGHSEC; double runs = 1; Map expected = new HashMap<>(); expected.put(34, 4_633_200.0); //Tritanium expected.put(35, 2_316_600.0); //Pyerite expected.put(36, 347_490.0); //Mexallon expected.put(37, 115_830.0); //Isogen expected.put(38, 13_900.0); //Nocxium expected.put(39, 3_475.0); //Zydrine expected.put(40, 1_738.0); //Megacyte expected.put(57478, 134.0); //Auto-Integrity Preservation Seal expected.put(57486, 67.0); //Life Support Backup Unit expected.put(57479, 1.0); //Core Temperature Regulator testManufacturingQuantity(expected, me, facility, rigs, security, runs); } /** * Tested against Isk Per Hour and Fuzzwork 2025-04-03 */ @Test public void testManufacturingQuantityRuns() { System.out.println(" --- Runs Eng---"); int me = 10; ManufacturingFacility facility = ManufacturingFacility.ENGINEERING_COMPLEX_XLARGE; ManufacturingRigs rigs = ManufacturingRigs.NONE; ManufacturingSecurity security = ManufacturingSecurity.HIGHSEC; double runs = 200; Map expected = new HashMap<>(); expected.put(34, 926_640_000.0); //Tritanium expected.put(35, 463_320_000.0); //Pyerite expected.put(36, 69_498_000.0); //Mexallon expected.put(37, 23_166_000.0); //Isogen expected.put(38, 2_779_920.0); //Nocxium expected.put(39, 694_980.0); //Zydrine expected.put(40, 347_490.0); //Megacyte expected.put(57478, 26_730.0); //Auto-Integrity Preservation Seal expected.put(57486, 13_365.0); //Life Support Backup Unit expected.put(57479, 200.0); //Core Temperature Regulator testManufacturingQuantity(expected, me, facility, rigs, security, runs); } /** * Tested against in-game values 2025-04-03 */ @Test public void testManufacturingQuantityRunsStation() { System.out.println(" --- Runs Station ---"); int me = 10; ManufacturingFacility facility = ManufacturingFacility.STATION; ManufacturingRigs rigs = ManufacturingRigs.NONE; ManufacturingSecurity security = ManufacturingSecurity.HIGHSEC; double runs = 200; Map expected = new HashMap<>(); expected.put(34, 936_000_000.0); //Tritanium expected.put(35, 468_000_000.0); //Pyerite expected.put(36, 70_200_000.0); //Mexallon expected.put(37, 23_400_000.0); //Isogen expected.put(38, 2_808_000.0); //Nocxium expected.put(39, 702_000.0); //Zydrine expected.put(40, 351_000.0); //Megacyte expected.put(57478, 27_000.0); //Auto-Integrity Preservation Seal expected.put(57486, 13_500.0); //Life Support Backup Unit expected.put(57479, 200.0); //Core Temperature Regulator testManufacturingQuantity(expected, me, facility, rigs, security, runs); } public void testManufacturingQuantity(Map expected, int me, ManufacturingFacility facility, ManufacturingRigs rigs, ManufacturingSecurity security, double runs) { Item blueprint = ApiIdConverter.getItem(999); //Dominix Blueprint for (IndustryMaterial material : blueprint.getManufacturingMaterials()) { double quantity = ApiIdConverter.getManufacturingQuantity(material.getQuantity(), me, facility, rigs, security, runs, true); System.out.println(" id=" + material.getTypeID() + " q=" + material.getQuantity() + " qmod=" + Formatter.compareFormat(quantity)); assertEquals(expected.get(material.getTypeID()), quantity, 0.001); //System.out.println("expected.put(" + material.getTypeID() + ", " + Formatter.compareFormat(quantity) + ");"); } } /** * Test of location method, of class ApiIdConverter. */ @Test public void testLocation() { for (MyLocation o1 : StaticData.get().getLocations()) { MyLocation location = ApiIdConverter.getLocation(o1.getLocationID()); assertEquals(o1.getLocation(), location.getLocation()); assertEquals(o1.getLocationID(), location.getLocationID()); if (o1.isRegion()) { assertEquals(o1.getStation(), location.getStation()); assertEquals(o1.getStationID(), location.getStationID()); assertEquals(o1.getStation(), ""); assertEquals(o1.getStationID(), 0); assertEquals(o1.getSystem(), location.getSystem()); assertEquals(o1.getSystemID(), location.getSystemID()); assertEquals(o1.getSystem(), ""); assertEquals(o1.getSystemID(), 0); assertEquals(o1.getConstellation(), location.getConstellation()); assertEquals(o1.getConstellationID(), location.getConstellationID()); assertEquals(o1.getConstellation(), ""); assertEquals(o1.getConstellationID(), 0); assertEquals(o1.getRegion(), location.getRegion()); assertEquals(o1.getRegionID(), location.getRegionID()); assertFalse(o1.getRegion().equals("")); assertFalse(o1.getRegionID() == 0); } else if (o1.isConstellation()) { assertEquals(o1.getStation(), location.getStation()); assertEquals(o1.getStationID(), location.getStationID()); assertEquals(o1.getStation(), ""); assertEquals(o1.getStationID(), 0); assertEquals(o1.getSystem(), location.getSystem()); assertEquals(o1.getSystemID(), location.getSystemID()); assertEquals(o1.getSystem(), ""); assertEquals(o1.getSystemID(), 0); assertEquals(o1.getConstellation(), location.getConstellation()); assertEquals(o1.getConstellationID(), location.getConstellationID()); assertFalse(o1.getConstellation().equals("")); assertFalse(o1.getConstellationID()== 0); assertEquals(o1.getRegion(), location.getRegion()); assertEquals(o1.getRegionID(), location.getRegionID()); assertFalse(o1.getRegion().equals("")); assertFalse(o1.getRegionID() == 0); } else if (o1.isSystem()) { assertEquals(o1.getStation(), location.getStation()); assertEquals(o1.getStationID(), location.getStationID()); assertEquals(o1.getStation(), ""); assertEquals(o1.getStationID(), 0); assertEquals(o1.getSystem(), location.getSystem()); assertEquals(o1.getSystemID(), location.getSystemID()); assertFalse(o1.getSystem().equals("")); assertFalse(o1.getSystemID() == 0); assertEquals(o1.getConstellation(), location.getConstellation()); assertEquals(o1.getConstellationID(), location.getConstellationID()); assertFalse(o1.getConstellation().equals("")); assertFalse(o1.getConstellationID()== 0); assertEquals(o1.getRegion(), location.getRegion()); assertEquals(o1.getRegionID(), location.getRegionID()); assertFalse(o1.getRegion().equals("")); assertFalse(o1.getRegionID() == 0); } else if (o1.isStation()) { //Not planet assertEquals(o1.getStation(), location.getStation()); assertEquals(o1.getStationID(), location.getStationID()); assertFalse(o1.getStation().equals("")); assertFalse(o1.getStationID() == 0); assertEquals(o1.getSystem(), location.getSystem()); assertEquals(o1.getSystemID(), location.getSystemID()); assertFalse(o1.getSystem().equals("")); assertFalse(o1.getSystemID() == 0); assertEquals(o1.getConstellation(), location.getConstellation()); assertEquals(o1.getConstellationID(), location.getConstellationID()); assertFalse(o1.getConstellation().equals("")); assertFalse(o1.getConstellationID()== 0); assertEquals(o1.getRegion(), location.getRegion()); assertEquals(o1.getRegionID(), location.getRegionID()); assertFalse(o1.getRegion().equals("")); assertFalse(o1.getRegionID() == 0); } else if (o1.isPlanet()) { assertEquals(o1.getStation(), location.getStation()); assertEquals(o1.getStationID(), location.getStationID()); assertFalse(o1.getStation().equals("")); assertFalse(o1.getStationID() == 0); assertEquals(o1.getSystem(), location.getSystem()); assertEquals(o1.getSystemID(), location.getSystemID()); assertFalse(o1.getSystem().equals("")); assertFalse(o1.getSystemID() == 0); assertEquals(o1.getConstellation(), location.getConstellation()); assertEquals(o1.getConstellationID(), location.getConstellationID()); assertFalse(o1.getConstellation().equals("")); assertFalse(o1.getConstellationID()== 0); assertEquals(o1.getRegion(), location.getRegion()); assertEquals(o1.getRegionID(), location.getRegionID()); assertFalse(o1.getRegion().equals("")); assertFalse(o1.getRegionID() == 0); } } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/shared/AssetsGetterTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import static org.junit.Assert.assertEquals; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.sde.StaticData; import org.junit.Test; public class AssetsGetterTest extends TestUtil { @Test public void testFlatListExclusions() { assertEquals(StaticData.get().getItemFlags().get(7).getFlagName(), "Skill"); assertEquals(StaticData.get().getItemFlags().get(89).getFlagName(), "Implant"); assertEquals(StaticData.get().getItemFlags().get(61).getFlagName(), "Skill In Training"); assertEquals(StaticData.get().getItemFlags().get(88).getFlagName(), "Booster"); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/shared/ConverterTestOptions.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.math.BigDecimal; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.Date; import javax.swing.JButton; import net.nikr.eve.jeveasset.data.api.my.MyBlueprint; import net.nikr.eve.jeveasset.data.api.my.MyShip; import net.nikr.eve.jeveasset.data.api.raw.RawBlueprint; import net.nikr.eve.jeveasset.data.api.raw.RawContract; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob; import net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType; import net.nikr.eve.jeveasset.data.api.raw.RawJournalRefType; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawNpcStanding; import net.nikr.eve.jeveasset.data.sde.ItemFlag; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.MarketPriceData; import net.nikr.eve.jeveasset.data.settings.PriceData; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.gui.shared.table.containers.TextIcon; import net.nikr.eve.jeveasset.gui.tabs.orders.Outbid; import net.nikr.eve.jeveasset.io.esi.EsiCallbackURL; import net.troja.eve.esi.model.CharacterAssetsResponse; import net.troja.eve.esi.model.CharacterBlueprintsResponse; import net.troja.eve.esi.model.CharacterContractsResponse; import net.troja.eve.esi.model.CharacterIndustryJobsResponse; import net.troja.eve.esi.model.CharacterOrdersHistoryResponse; import net.troja.eve.esi.model.CharacterOrdersResponse; import net.troja.eve.esi.model.CharacterWalletJournalResponse; import net.troja.eve.esi.model.CorporationAssetsResponse; import net.troja.eve.esi.model.CorporationBlueprintsResponse; import net.troja.eve.esi.model.CorporationContractsResponse; import net.troja.eve.esi.model.CorporationIndustryJobsResponse; import net.troja.eve.esi.model.CorporationOrdersHistoryResponse; import net.troja.eve.esi.model.CorporationOrdersResponse; import net.troja.eve.esi.model.CorporationWalletJournalResponse; public interface ConverterTestOptions { public Integer getInteger(); public Float getFloat(); public Boolean getBoolean(); public Long getLong(); public Double getDouble(); public Date getDate(); public String getString(); public ItemFlag getItemFlag(); public PriceData getPriceData(); public UserItem getUserPrice(); public MyShip getMyShip(); public JButton getButton(); public MyBlueprint getMyBlueprint(); public MarketPriceData getMarketPriceData(); public Tags getTags(); public RawBlueprint getRawBlueprint(); public Percent getPercent(); //LocationType public MyLocation getMyLocation(); public Long getLocationID(); public CharacterAssetsResponse.LocationTypeEnum getLocationTypeEsiCharacter(); public CorporationAssetsResponse.LocationTypeEnum getLocationTypeEsiCorporation(); //LocationFlag public CharacterBlueprintsResponse.LocationFlagEnum getLocationFlagEsiBlueprintCharacter(); public CorporationBlueprintsResponse.LocationFlagEnum getLocationFlagEsiBlueprintCorporation(); public CharacterAssetsResponse.LocationFlagEnum getLocationFlagEsiAssetsCharacter(); public CorporationAssetsResponse.LocationFlagEnum getLocationFlagEsiAssetsCorporation(); //ContractAvailability public RawContract.ContractAvailability getContractAvailabilityRaw(); public CharacterContractsResponse.AvailabilityEnum getContractAvailabilityEsiCharacter(); public CorporationContractsResponse.AvailabilityEnum getContractAvailabilityEsiCorporation(); //ContractStatus public RawContract.ContractStatus getContractStatusRaw(); public CharacterContractsResponse.StatusEnum getContractStatusEsiCharacter(); public CorporationContractsResponse.StatusEnum getContractStatusEsiCorporation(); //ContractType public RawContract.ContractType getContractTypeRaw(); public CharacterContractsResponse.TypeEnum getContractTypeEsiCharacter(); public CorporationContractsResponse.TypeEnum getContractTypeEsiCorporation(); //IndustryJobStatus public RawIndustryJob.IndustryJobStatus getIndustryJobStatusRaw(); public CharacterIndustryJobsResponse.StatusEnum getIndustryJobStatusEsiCharacter(); public CorporationIndustryJobsResponse.StatusEnum getIndustryJobStatusEsiCorporation(); //JournalContextType public ContextType getJournalContextTypeRaw(); public CharacterWalletJournalResponse.ContextIdTypeEnum getJournalContextTypeEsiCharacter(); public CorporationWalletJournalResponse.ContextIdTypeEnum getJournalContextTypeEsiCorporation(); //JournalRefType public RawJournalRefType getJournalRefTypeRaw(); public CharacterWalletJournalResponse.RefTypeEnum getJournalRefTypeEsiCharacter(); public CorporationWalletJournalResponse.RefTypeEnum getJournalRefTypeEsiCorporation(); //MarketOrderRange public RawMarketOrder.MarketOrderRange getMarketOrderRangeRaw(); public CharacterOrdersResponse.RangeEnum getMarketOrderRangeEsiCharacter(); public CharacterOrdersHistoryResponse.RangeEnum getMarketOrderRangeEsiCharacterHistory(); public CorporationOrdersResponse.RangeEnum getMarketOrderRangeEsiCorporation(); public CorporationOrdersHistoryResponse.RangeEnum getMarketOrderRangeEsiCorporationHistory(); //MarketOrderState public RawMarketOrder.MarketOrderState getMarketOrderStateRaw(); public CharacterOrdersHistoryResponse.StateEnum getMarketOrderStateEsiCharacterHistory(); public Outbid getMarketOrdersOutbid(); public CorporationOrdersHistoryResponse.StateEnum getMarketOrderStateEsiCorporationHistory(); public RawNpcStanding.FromType getNpcStandingFromType(); public TextIcon getTextIcon(); public int getIndex(); //Owner public EsiCallbackURL getEsiCallbackURL(); default OffsetDateTime getOffsetDateTime() { return getDate().toInstant().atOffset(ZoneOffset.UTC); } default Object getNull() { return null; } default BigDecimal getBigDecimal() { return new BigDecimal(getDouble()); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/shared/ConverterTestOptionsGetter.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.Icon; import javax.swing.JButton; import net.nikr.eve.jeveasset.data.api.my.MyBlueprint; import net.nikr.eve.jeveasset.data.api.my.MyShip; import net.nikr.eve.jeveasset.data.api.raw.RawBlueprint; import net.nikr.eve.jeveasset.data.api.raw.RawContract; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob; import net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType; import net.nikr.eve.jeveasset.data.api.raw.RawJournalRefType; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawNpcStanding; import net.nikr.eve.jeveasset.data.sde.ItemFlag; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.MarketPriceData; import net.nikr.eve.jeveasset.data.settings.PriceData; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.dialogs.settings.UserPriceSettingsPanel.UserPrice; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.gui.shared.table.containers.TextIcon; import net.nikr.eve.jeveasset.gui.tabs.orders.Outbid; import net.nikr.eve.jeveasset.io.esi.EsiCallbackURL; import net.troja.eve.esi.model.CharacterAssetsResponse; import net.troja.eve.esi.model.CharacterBlueprintsResponse; import net.troja.eve.esi.model.CharacterContractsResponse; import net.troja.eve.esi.model.CharacterIndustryJobsResponse; import net.troja.eve.esi.model.CharacterOrdersHistoryResponse; import net.troja.eve.esi.model.CharacterOrdersResponse; import net.troja.eve.esi.model.CharacterWalletJournalResponse; import net.troja.eve.esi.model.CorporationAssetsResponse; import net.troja.eve.esi.model.CorporationBlueprintsResponse; import net.troja.eve.esi.model.CorporationContractsResponse; import net.troja.eve.esi.model.CorporationIndustryJobsResponse; import net.troja.eve.esi.model.CorporationOrdersHistoryResponse; import net.troja.eve.esi.model.CorporationOrdersResponse; import net.troja.eve.esi.model.CorporationWalletJournalResponse; import static org.junit.Assert.fail; public class ConverterTestOptionsGetter { private static List options = null; public static synchronized List getConverterOptions() { if (options == null) { options = new ArrayList<>(); int index = 0; while (add(options, index)) { index++; } } return options; } private static boolean add(List list, int i) { IndexOptions indexOptions = new IndexOptions(i); if (indexOptions.isMaxed()) { return false; } else { list.add(indexOptions); return true; } } private static class IndexOptions implements ConverterTestOptions { //Primitive private static final Integer[] INTEGER = {5}; private static final Float[] FLOAT = {5.1f}; private static final Boolean[] BOOLEAN = {true}; private static final Long[] LONG = {5L}; private static final Double[] DOUBLE = {5.1}; private static final Date[] DATE = {new Date()}; private static final String[] STRING = {"StringValue"}; private static final Icon ICON = new Icon() { @Override public void paintIcon(Component c, Graphics g, int x, int y) { Graphics2D g2d = (Graphics2D) g; g2d.setPaint(Color.GREEN); g2d.fillRect(0, 0, getIconWidth(), getIconHeight()); } @Override public int getIconWidth() { return 16; } @Override public int getIconHeight() { return 16; } }; //Data private static final MyLocation[] MY_LOCATION = {ApiIdConverter.getLocation(60003466)}; private static final PriceData[] PRICE_DATA = {new PriceData()}; private static final MarketPriceData[] MARKET_PRICE_DATA = {new MarketPriceData()}; private static final Tags[] TAGS = {new Tags()}; private static final Percent[] PERCENT = {Percent.create(5.1)}; private static final UserPrice[] USER_ITEM = {new UserPrice(DOUBLE[0], INTEGER[0], STRING[0])}; private static final MyShip MY_SHIP = new MyShip(LONG[0], INTEGER[0], 60003466L); private static final JButton BUTTON = new JButton(); private static final MyBlueprint BLUEPRINT = new MyBlueprint(INTEGER[0], INTEGER[0], INTEGER[0]); //LocationType private static final CharacterAssetsResponse.LocationTypeEnum[] ESI_LOCATION_TYPE_CHARACTER = CharacterAssetsResponse.LocationTypeEnum.values(); private static final CorporationAssetsResponse.LocationTypeEnum[] ESI_LOCATION_TYPE_CORPORATION = CorporationAssetsResponse.LocationTypeEnum.values(); private static final Long[] LOCATION_ID = {60003466L, 30000142L, 100000000L, 10000002L}; //LocationFlag private static final List LOCATION_TYPE = createLocationTypes(); //ContractAvailability private static final RawContract.ContractAvailability[] RAW_CONTRACT_AVAILABILITY = RawContract.ContractAvailability.values(); private static final CharacterContractsResponse.AvailabilityEnum[] ESI_CONTRACTS_AVAILABILITY_CHARACTER = CharacterContractsResponse.AvailabilityEnum.values(); private static final CorporationContractsResponse.AvailabilityEnum[] ESI_CONTRACTS_AVAILABILITY_CORPORATION = CorporationContractsResponse.AvailabilityEnum.values(); //ContractStatus private static final RawContract.ContractStatus[] RAW_CONTRACT_STATUS = RawContract.ContractStatus.values(); private static final CharacterContractsResponse.StatusEnum[] ESI_CONTRACT_STATUS_CHARACTER = CharacterContractsResponse.StatusEnum.values(); private static final CorporationContractsResponse.StatusEnum[] ESI_CONTRACT_STATUS_CORPORATION = CorporationContractsResponse.StatusEnum.values(); //ContractType private static final RawContract.ContractType[] RAW_CONTRACT_TYPE = RawContract.ContractType.values(); private static final CharacterContractsResponse.TypeEnum[] ESI_CONTRACT_TYPE_CHARACTER = CharacterContractsResponse.TypeEnum.values(); private static final CorporationContractsResponse.TypeEnum[] ESI_CONTRACT_TYPE_CORPORATION = CorporationContractsResponse.TypeEnum.values(); //IndustryJobStatus private static final RawIndustryJob.IndustryJobStatus[] RAW_INDUSTRY_JOB_STATUS = RawIndustryJob.IndustryJobStatus.values(); private static final CharacterIndustryJobsResponse.StatusEnum[] ESI_INDUSTRY_JOB_STATUS_CHARACTER = CharacterIndustryJobsResponse.StatusEnum.values(); private static final CorporationIndustryJobsResponse.StatusEnum[] ESI_INDUSTRY_JOB_STATUS_CORPORATION = CorporationIndustryJobsResponse.StatusEnum.values(); //Journal RefType and ContextType private static final List JOURNAL_DATA = createJournalData(); //MarketOrderRange private static final RawMarketOrder.MarketOrderRange[] RAW_MARKET_ORDER_RANGE = RawMarketOrder.MarketOrderRange.values(); private static final CharacterOrdersResponse.RangeEnum[] ESI_MARKET_ORDER_RANGE_CHARACTER = CharacterOrdersResponse.RangeEnum.values(); private static final CharacterOrdersHistoryResponse.RangeEnum[] ESI_MARKET_ORDER_RANGE_CHARACTER_HISTORY = CharacterOrdersHistoryResponse.RangeEnum.values(); private static final CorporationOrdersResponse.RangeEnum[] ESI_MARKET_ORDER_RANGE_CORPORATION = CorporationOrdersResponse.RangeEnum.values(); private static final CorporationOrdersHistoryResponse.RangeEnum[] ESI_MARKET_ORDER_RANGE_CORPORATION_HISTORY = CorporationOrdersHistoryResponse.RangeEnum.values(); //MarketOrderState private static final RawMarketOrder.MarketOrderState[] RAW_MARKET_ORDER_STATE = { RawMarketOrder.MarketOrderState.CANCELLED, RawMarketOrder.MarketOrderState.CHARACTER_DELETED, RawMarketOrder.MarketOrderState.CLOSED, RawMarketOrder.MarketOrderState.EXPIRED, RawMarketOrder.MarketOrderState.OPEN, RawMarketOrder.MarketOrderState.PENDING, //UNKNOWN("Unknown"); //Ignored: jEveAssets value }; //MarketOrder Outbid private static final Outbid ESI_MARKET_ORDER_OUTBID = new Outbid(0.0, 0); private static final CharacterOrdersHistoryResponse.StateEnum[] ESI_MARKET_ORDER_STATE_CHARACTER_HISTORY = CharacterOrdersHistoryResponse.StateEnum.values(); private static final CorporationOrdersHistoryResponse.StateEnum[] ESI_MARKET_ORDER_STATE_CORPORATION_HISTORY = CorporationOrdersHistoryResponse.StateEnum.values(); //Owners private static final EsiCallbackURL[] ESI_CALLBACK_URL = EsiCallbackURL.values(); //NpcStanding private static final RawNpcStanding.FromType[] NPC_STANDING_FROM_TYPE = RawNpcStanding.FromType.values(); private static final TextIcon TEXT_ICON = new TextIcon(ICON, STRING[0]); //Control private static final int MAX = createMax(); //Controls private final int index; public IndexOptions(int index) { this.index = index; } private static List createLocationTypes() { Map locationFlags = new HashMap<>(); //Character Blueprints for (CharacterBlueprintsResponse.LocationFlagEnum locationFlagEnum : CharacterBlueprintsResponse.LocationFlagEnum.values()) { ItemFlag itemFlag = RawConverter.toFlag(locationFlagEnum); LocationFlag locationFlag = locationFlags.get(itemFlag.getFlagID()); if (locationFlag == null) { locationFlag = new LocationFlag(itemFlag); locationFlags.put(itemFlag.getFlagID(), locationFlag); } locationFlag.setLocationFlag(locationFlagEnum); } //Corporation Blueprints for (CorporationBlueprintsResponse.LocationFlagEnum locationFlagEnum : CorporationBlueprintsResponse.LocationFlagEnum.values()) { ItemFlag itemFlag = RawConverter.toFlag(locationFlagEnum); LocationFlag locationFlag = locationFlags.get(itemFlag.getFlagID()); if (locationFlag == null) { locationFlag = new LocationFlag(itemFlag); locationFlags.put(itemFlag.getFlagID(), locationFlag); } locationFlag.setLocationFlag(locationFlagEnum); } //Character Assets for (CharacterAssetsResponse.LocationFlagEnum locationFlagEnum : CharacterAssetsResponse.LocationFlagEnum.values()) { ItemFlag itemFlag = RawConverter.toFlag(locationFlagEnum); LocationFlag locationFlag = locationFlags.get(itemFlag.getFlagID()); if (locationFlag == null) { locationFlag = new LocationFlag(itemFlag); locationFlags.put(itemFlag.getFlagID(), locationFlag); } locationFlag.setLocationFlag(locationFlagEnum); } //Corporation Assets for (CorporationAssetsResponse.LocationFlagEnum locationFlagEnum : CorporationAssetsResponse.LocationFlagEnum.values()) { ItemFlag itemFlag = RawConverter.toFlag(locationFlagEnum); LocationFlag locationFlag = locationFlags.get(itemFlag.getFlagID()); if (locationFlag == null) { locationFlag = new LocationFlag(itemFlag); locationFlags.put(itemFlag.getFlagID(), locationFlag); } locationFlag.setLocationFlag(locationFlagEnum); } Set remove = new HashSet<>(); for (LocationFlag locationType : locationFlags.values()) { if (locationType.isEmpty()) { remove.add(locationType.getItemFlag().getFlagID()); } } for (Integer index : remove) { locationFlags.remove(index); } return new ArrayList<>(locationFlags.values()); } private static List createJournalData() { Map journalDatas = new HashMap<>(); //ESI Character for (CharacterWalletJournalResponse.RefTypeEnum refTypeEnum : CharacterWalletJournalResponse.RefTypeEnum.values()) { RawJournalRefType rawJournalRefType = RawConverter.toJournalRefType(refTypeEnum); if (rawJournalRefType == null) { fail(refTypeEnum.name() + " not found"); continue; } JournalData journalData = journalDatas.get(rawJournalRefType.getID()); if (journalData == null) { journalData = new JournalData(rawJournalRefType); journalDatas.put(rawJournalRefType.getID(), journalData); } journalData.setRefType(refTypeEnum); journalData.setContextType(RawConverter.toJournalContextType(rawJournalRefType)); } //ESI Corporation for (CorporationWalletJournalResponse.RefTypeEnum refTypeEnum : CorporationWalletJournalResponse.RefTypeEnum.values()) { RawJournalRefType rawJournalRefType = RawConverter.toJournalRefType(refTypeEnum); if (rawJournalRefType == null) { fail(refTypeEnum.name() + " not found"); continue; } JournalData journalData = journalDatas.get(rawJournalRefType.getID()); if (journalData == null) { journalData = new JournalData(rawJournalRefType); journalDatas.put(rawJournalRefType.getID(), journalData); } journalData.setRefType(refTypeEnum); journalData.setContextType(RawConverter.toJournalContextType(rawJournalRefType)); } Set remove = new HashSet<>(); for (JournalData refType : journalDatas.values()) { if (refType.isEmpty()) { remove.add(refType.getRawJournalRefType().getID()); } } for (Integer index : remove) { journalDatas.remove(index); } return new ArrayList<>(journalDatas.values()); } private static int createMax() { int tempMax = 0; tempMax = Math.max(tempMax, INTEGER.length); tempMax = Math.max(tempMax, FLOAT.length); tempMax = Math.max(tempMax, BOOLEAN.length); tempMax = Math.max(tempMax, LONG.length); tempMax = Math.max(tempMax, DOUBLE.length); tempMax = Math.max(tempMax, DATE.length); tempMax = Math.max(tempMax, STRING.length); tempMax = Math.max(tempMax, MY_LOCATION.length); tempMax = Math.max(tempMax, PRICE_DATA.length); tempMax = Math.max(tempMax, MARKET_PRICE_DATA.length); tempMax = Math.max(tempMax, TAGS.length); tempMax = Math.max(tempMax, PERCENT.length); tempMax = Math.max(tempMax, USER_ITEM.length); //LocationType tempMax = Math.max(tempMax, ESI_LOCATION_TYPE_CHARACTER.length); tempMax = Math.max(tempMax, ESI_LOCATION_TYPE_CORPORATION.length); //LocationFlag tempMax = Math.max(tempMax, LOCATION_TYPE.size()); //ContractAvailability tempMax = Math.max(tempMax, RAW_CONTRACT_AVAILABILITY.length); tempMax = Math.max(tempMax, ESI_CONTRACTS_AVAILABILITY_CHARACTER.length); tempMax = Math.max(tempMax, ESI_CONTRACTS_AVAILABILITY_CORPORATION.length); //ContractStatus tempMax = Math.max(tempMax, RAW_CONTRACT_STATUS.length); tempMax = Math.max(tempMax, ESI_CONTRACT_STATUS_CHARACTER.length); tempMax = Math.max(tempMax, ESI_CONTRACT_STATUS_CORPORATION.length); //ContractType tempMax = Math.max(tempMax, RAW_CONTRACT_TYPE.length); tempMax = Math.max(tempMax, ESI_CONTRACT_TYPE_CHARACTER.length); tempMax = Math.max(tempMax, ESI_CONTRACT_TYPE_CORPORATION.length); //IndustryJobStatus tempMax = Math.max(tempMax, RAW_INDUSTRY_JOB_STATUS.length); tempMax = Math.max(tempMax, ESI_INDUSTRY_JOB_STATUS_CHARACTER.length); tempMax = Math.max(tempMax, ESI_INDUSTRY_JOB_STATUS_CORPORATION.length); //JournalRefType tempMax = Math.max(tempMax, JOURNAL_DATA.size()); //MarketOrderRange tempMax = Math.max(tempMax, RAW_MARKET_ORDER_RANGE.length); tempMax = Math.max(tempMax, ESI_MARKET_ORDER_RANGE_CHARACTER.length); tempMax = Math.max(tempMax, ESI_MARKET_ORDER_RANGE_CORPORATION.length); //MarketOrderState tempMax = Math.max(tempMax, RAW_MARKET_ORDER_STATE.length); //Owners tempMax = Math.max(tempMax, ESI_CALLBACK_URL.length); //Npc Standing tempMax = Math.max(tempMax, NPC_STANDING_FROM_TYPE.length); return tempMax; } @Override public int getIndex() { return index; } private E get(E[] array, int index) { if (index < array.length) { return array[index]; } else { return array[0]; } } private E get(List list, Integer index) { if (index < list.size()) { return list.get(index); } else { return list.get(0); } } public boolean isMaxed() { return index >= MAX; } @Override public Integer getInteger() { return get(INTEGER, index); } @Override public Float getFloat() { return get(FLOAT, index); } @Override public Boolean getBoolean() { return get(BOOLEAN, index); } @Override public final Long getLong() { return get(LONG, index); } @Override public Double getDouble() { return get(DOUBLE, index); } @Override public Date getDate() { return get(DATE, index); } @Override public String getString() { return get(STRING, index); } @Override public MyLocation getMyLocation() { return get(MY_LOCATION, index); } @Override public PriceData getPriceData() { return get(PRICE_DATA, index); } @Override public UserItem getUserPrice() { return get(USER_ITEM, index); } @Override public MyShip getMyShip() { return MY_SHIP; } @Override public JButton getButton() { return BUTTON; } @Override public MyBlueprint getMyBlueprint() { return BLUEPRINT; } @Override public MarketPriceData getMarketPriceData() { return get(MARKET_PRICE_DATA, index); } @Override public Tags getTags() { return get(TAGS, index); } @Override public RawBlueprint getRawBlueprint() { return ConverterTestUtil.getRawBlueprint(this); } @Override public Percent getPercent() { return get(PERCENT, index); } //LocationType @Override public Long getLocationID() { return get(LOCATION_ID, index); } @Override public CharacterAssetsResponse.LocationTypeEnum getLocationTypeEsiCharacter() { return get(ESI_LOCATION_TYPE_CHARACTER, index); } @Override public CorporationAssetsResponse.LocationTypeEnum getLocationTypeEsiCorporation() { return get(ESI_LOCATION_TYPE_CORPORATION, index); } //LocationFlag @Override public CharacterBlueprintsResponse.LocationFlagEnum getLocationFlagEsiBlueprintCharacter() { return get(LOCATION_TYPE, index).getLocationFlagEsiBlueprintsCharacter(); } @Override public CorporationBlueprintsResponse.LocationFlagEnum getLocationFlagEsiBlueprintCorporation() { return get(LOCATION_TYPE, index).getLocationFlagEsiBlueprintsCorporation(); } @Override public CharacterAssetsResponse.LocationFlagEnum getLocationFlagEsiAssetsCharacter() { return get(LOCATION_TYPE, index).getLocationFlagEsiAssetsCharacter(); } @Override public CorporationAssetsResponse.LocationFlagEnum getLocationFlagEsiAssetsCorporation() { return get(LOCATION_TYPE, index).getLocationFlagEsiAssetsCorporation(); } @Override public ItemFlag getItemFlag() { return get(LOCATION_TYPE, index).getItemFlag(); } //ContractAvailability @Override public RawContract.ContractAvailability getContractAvailabilityRaw() { return get(RAW_CONTRACT_AVAILABILITY, index); } @Override public CharacterContractsResponse.AvailabilityEnum getContractAvailabilityEsiCharacter() { return get(ESI_CONTRACTS_AVAILABILITY_CHARACTER, index); } @Override public CorporationContractsResponse.AvailabilityEnum getContractAvailabilityEsiCorporation() { return get(ESI_CONTRACTS_AVAILABILITY_CORPORATION, index); } //ContractStatus @Override public RawContract.ContractStatus getContractStatusRaw() { return get(RAW_CONTRACT_STATUS, index); } @Override public CharacterContractsResponse.StatusEnum getContractStatusEsiCharacter() { return get(ESI_CONTRACT_STATUS_CHARACTER, index); } @Override public CorporationContractsResponse.StatusEnum getContractStatusEsiCorporation() { return get(ESI_CONTRACT_STATUS_CORPORATION, index); } //ContractType @Override public RawContract.ContractType getContractTypeRaw() { return get(RAW_CONTRACT_TYPE, index); } @Override public CharacterContractsResponse.TypeEnum getContractTypeEsiCharacter() { return get(ESI_CONTRACT_TYPE_CHARACTER, index); } @Override public CorporationContractsResponse.TypeEnum getContractTypeEsiCorporation() { return get(ESI_CONTRACT_TYPE_CORPORATION, index); } //IndustryJobStatus @Override public RawIndustryJob.IndustryJobStatus getIndustryJobStatusRaw() { return get(RAW_INDUSTRY_JOB_STATUS, index); } @Override public CharacterIndustryJobsResponse.StatusEnum getIndustryJobStatusEsiCharacter() { return get(ESI_INDUSTRY_JOB_STATUS_CHARACTER, index); } @Override public CorporationIndustryJobsResponse.StatusEnum getIndustryJobStatusEsiCorporation() { return get(ESI_INDUSTRY_JOB_STATUS_CORPORATION, index); } //JournalContextType @Override public ContextType getJournalContextTypeRaw() { return get(JOURNAL_DATA, index).getRawJournalContextType(); } @Override public CharacterWalletJournalResponse.ContextIdTypeEnum getJournalContextTypeEsiCharacter() { return get(JOURNAL_DATA, index).getEsiJournalContextTypeCharacter(); } @Override public CorporationWalletJournalResponse.ContextIdTypeEnum getJournalContextTypeEsiCorporation() { return get(JOURNAL_DATA, index).getEsiJournalContextTypeCorporation(); } //JournalRefType @Override public RawJournalRefType getJournalRefTypeRaw() { return get(JOURNAL_DATA, index).getRawJournalRefType(); } @Override public CharacterWalletJournalResponse.RefTypeEnum getJournalRefTypeEsiCharacter() { return get(JOURNAL_DATA, index).getEsiJournalRefTypeCharacter(); } @Override public CorporationWalletJournalResponse.RefTypeEnum getJournalRefTypeEsiCorporation() { return get(JOURNAL_DATA, index).getEsiJournalRefTypeCorporation(); } //MarketOrderRange @Override public RawMarketOrder.MarketOrderRange getMarketOrderRangeRaw() { return get(RAW_MARKET_ORDER_RANGE, index); } @Override public CharacterOrdersResponse.RangeEnum getMarketOrderRangeEsiCharacter() { return get(ESI_MARKET_ORDER_RANGE_CHARACTER, index); } @Override public CharacterOrdersHistoryResponse.RangeEnum getMarketOrderRangeEsiCharacterHistory() { return get(ESI_MARKET_ORDER_RANGE_CHARACTER_HISTORY, index); } @Override public CorporationOrdersResponse.RangeEnum getMarketOrderRangeEsiCorporation() { return get(ESI_MARKET_ORDER_RANGE_CORPORATION, index); } @Override public CorporationOrdersHistoryResponse.RangeEnum getMarketOrderRangeEsiCorporationHistory() { return get(ESI_MARKET_ORDER_RANGE_CORPORATION_HISTORY, index); } //MarketOrderState @Override public RawMarketOrder.MarketOrderState getMarketOrderStateRaw() { return get(RAW_MARKET_ORDER_STATE, index); } @Override public CharacterOrdersHistoryResponse.StateEnum getMarketOrderStateEsiCharacterHistory() { return get(ESI_MARKET_ORDER_STATE_CHARACTER_HISTORY, index); } @Override public CorporationOrdersHistoryResponse.StateEnum getMarketOrderStateEsiCorporationHistory() { return get(ESI_MARKET_ORDER_STATE_CORPORATION_HISTORY, index); } //MarketOrder Outbid @Override public Outbid getMarketOrdersOutbid() { return ESI_MARKET_ORDER_OUTBID; } //Owner @Override public EsiCallbackURL getEsiCallbackURL() { return get(ESI_CALLBACK_URL, index); } //NPC Standing @Override public RawNpcStanding.FromType getNpcStandingFromType() { return get(NPC_STANDING_FROM_TYPE, index); } @Override public TextIcon getTextIcon() { return TEXT_ICON; } } private static class LocationFlag { private CharacterBlueprintsResponse.LocationFlagEnum locationFlagEsiBlueprintsCharacter; private CorporationBlueprintsResponse.LocationFlagEnum locationFlagEsiBlueprintsCorporation; private CharacterAssetsResponse.LocationFlagEnum locationFlagEsiAssetsCharacter; private CorporationAssetsResponse.LocationFlagEnum locationFlagEsiAssetsCorporation; private final ItemFlag itemFlag; public LocationFlag(ItemFlag itemFlag) { this.itemFlag = itemFlag; } public boolean isEmpty() { return locationFlagEsiBlueprintsCharacter == null || locationFlagEsiBlueprintsCorporation == null || locationFlagEsiAssetsCharacter == null || locationFlagEsiAssetsCorporation == null; } public ItemFlag getItemFlag() { return itemFlag; } public CharacterBlueprintsResponse.LocationFlagEnum getLocationFlagEsiBlueprintsCharacter() { return locationFlagEsiBlueprintsCharacter; } public CorporationBlueprintsResponse.LocationFlagEnum getLocationFlagEsiBlueprintsCorporation() { return locationFlagEsiBlueprintsCorporation; } public CharacterAssetsResponse.LocationFlagEnum getLocationFlagEsiAssetsCharacter() { return locationFlagEsiAssetsCharacter; } public CorporationAssetsResponse.LocationFlagEnum getLocationFlagEsiAssetsCorporation() { return locationFlagEsiAssetsCorporation; } public void setLocationFlag(CharacterAssetsResponse.LocationFlagEnum locationFlagEsiAssetsCharacter) { this.locationFlagEsiAssetsCharacter = locationFlagEsiAssetsCharacter; } public void setLocationFlag(CorporationAssetsResponse.LocationFlagEnum locationFlagEsiAssetsCorporation) { this.locationFlagEsiAssetsCorporation = locationFlagEsiAssetsCorporation; } public void setLocationFlag(CorporationBlueprintsResponse.LocationFlagEnum locationFlagEsiBlueprintsCorporation) { this.locationFlagEsiBlueprintsCorporation = locationFlagEsiBlueprintsCorporation; } public void setLocationFlag(CharacterBlueprintsResponse.LocationFlagEnum locationFlagEsiBlueprintsCharacter) { this.locationFlagEsiBlueprintsCharacter = locationFlagEsiBlueprintsCharacter; } } private static class JournalData { private CharacterWalletJournalResponse.RefTypeEnum EsiJournalRefTypeCharacter; private CorporationWalletJournalResponse.RefTypeEnum EsiJournalRefTypeCorporation; private ContextType rawJournalContextType; private final RawJournalRefType rawJournalRefType; public JournalData(RawJournalRefType rawJournalRefType) { this.rawJournalRefType = rawJournalRefType; } public boolean isEmpty() { return EsiJournalRefTypeCharacter == null || EsiJournalRefTypeCorporation == null; } public RawJournalRefType getRawJournalRefType() { return rawJournalRefType; } public CharacterWalletJournalResponse.RefTypeEnum getEsiJournalRefTypeCharacter() { return EsiJournalRefTypeCharacter; } public CorporationWalletJournalResponse.RefTypeEnum getEsiJournalRefTypeCorporation() { return EsiJournalRefTypeCorporation; } public ContextType getRawJournalContextType() { return rawJournalContextType; } public CharacterWalletJournalResponse.ContextIdTypeEnum getEsiJournalContextTypeCharacter() { if (rawJournalContextType == null) { return null; } return CharacterWalletJournalResponse.ContextIdTypeEnum.valueOf(rawJournalContextType.name()); } public CorporationWalletJournalResponse.ContextIdTypeEnum getEsiJournalContextTypeCorporation() { if (rawJournalContextType == null) { return null; } return CorporationWalletJournalResponse.ContextIdTypeEnum.valueOf(rawJournalContextType.name()); } public void setRefType(CharacterWalletJournalResponse.RefTypeEnum EsiJournalRefTypeCharacter) { this.EsiJournalRefTypeCharacter = EsiJournalRefTypeCharacter; } public void setRefType(CorporationWalletJournalResponse.RefTypeEnum EsiJournalRefTypeCorporation) { this.EsiJournalRefTypeCorporation = EsiJournalRefTypeCorporation; } public void setContextType(ContextType rawJournalContextType) { this.rawJournalContextType = rawJournalContextType; } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/shared/ConverterTestUtil.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.JButton; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyAccountBalance; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyBlueprint; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyExtraction; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.api.my.MyShip; import net.nikr.eve.jeveasset.data.api.my.MySkill; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.api.raw.RawAccountBalance; import net.nikr.eve.jeveasset.data.api.raw.RawAsset; import net.nikr.eve.jeveasset.data.api.raw.RawBlueprint; import net.nikr.eve.jeveasset.data.api.raw.RawClone; import net.nikr.eve.jeveasset.data.api.raw.RawContract; import net.nikr.eve.jeveasset.data.api.raw.RawContractItem; import net.nikr.eve.jeveasset.data.api.raw.RawExtraction; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob; import net.nikr.eve.jeveasset.data.api.raw.RawJournal; import net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType; import net.nikr.eve.jeveasset.data.api.raw.RawJournalRefType; import net.nikr.eve.jeveasset.data.api.raw.RawLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.Change; import net.nikr.eve.jeveasset.data.api.raw.RawMining; import net.nikr.eve.jeveasset.data.api.raw.RawNpcStanding; import net.nikr.eve.jeveasset.data.api.raw.RawNpcStanding.FromType; import net.nikr.eve.jeveasset.data.api.raw.RawSkill; import net.nikr.eve.jeveasset.data.api.raw.RawTransaction; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.data.sde.ItemFlag; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.MarketPriceData; import net.nikr.eve.jeveasset.data.settings.PriceData; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.gui.shared.table.containers.TextIcon; import net.nikr.eve.jeveasset.gui.tabs.orders.Outbid; import net.nikr.eve.jeveasset.io.esi.EsiCallbackURL; import net.troja.eve.esi.ApiClient; import net.troja.eve.esi.api.AssetsApi; import net.troja.eve.esi.api.CharacterApi; import net.troja.eve.esi.api.ClonesApi; import net.troja.eve.esi.api.ContractsApi; import net.troja.eve.esi.api.CorporationApi; import net.troja.eve.esi.api.IndustryApi; import net.troja.eve.esi.api.LocationApi; import net.troja.eve.esi.api.LoyaltyApi; import net.troja.eve.esi.api.MarketApi; import net.troja.eve.esi.api.PlanetaryInteractionApi; import net.troja.eve.esi.api.SkillsApi; import net.troja.eve.esi.api.UniverseApi; import net.troja.eve.esi.api.UserInterfaceApi; import net.troja.eve.esi.api.WalletApi; import net.troja.eve.esi.auth.SsoScopes; import net.troja.eve.esi.model.CharacterAssetsResponse; import net.troja.eve.esi.model.CharacterBlueprintsResponse; import net.troja.eve.esi.model.CharacterContractsResponse; import net.troja.eve.esi.model.CharacterIndustryJobsResponse; import net.troja.eve.esi.model.CharacterLocationResponse; import net.troja.eve.esi.model.CharacterMiningResponse; import net.troja.eve.esi.model.CharacterOrdersHistoryResponse; import net.troja.eve.esi.model.CharacterOrdersResponse; import net.troja.eve.esi.model.CharacterRolesResponse.RolesEnum; import net.troja.eve.esi.model.CharacterShipResponse; import net.troja.eve.esi.model.CharacterWalletJournalResponse; import net.troja.eve.esi.model.CharacterWalletTransactionsResponse; import net.troja.eve.esi.model.ContractItemsResponse; import net.troja.eve.esi.model.CorporationAssetsResponse; import net.troja.eve.esi.model.CorporationBlueprintsResponse; import net.troja.eve.esi.model.CorporationContractsResponse; import net.troja.eve.esi.model.CorporationIndustryJobsResponse; import net.troja.eve.esi.model.CorporationMiningExtractionsResponse; import net.troja.eve.esi.model.CorporationOrdersHistoryResponse; import net.troja.eve.esi.model.CorporationOrdersResponse; import net.troja.eve.esi.model.CorporationWalletJournalResponse; import net.troja.eve.esi.model.CorporationWalletsResponse; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class ConverterTestUtil { public static EsiOwner getEsiOwner(ConverterTestOptions options) { return getEsiOwner(false, false, false, options); } public static EsiOwner getEsiOwner(boolean data, boolean setNull, boolean setValues, ConverterTestOptions options) { EsiOwner esiOwner = EsiOwner.create(); setValues(esiOwner, options); if (data) { setData(esiOwner, setNull, setValues, options); esiOwner.setRoles(set(RolesEnum.DIRECTOR)); esiOwner.setScopes(SsoScopes.ESI_CHARACTERS_READ_CORPORATION_ROLES_V1); } return esiOwner; } private static void setData(OwnerType owner, boolean setNull, boolean setValues, ConverterTestOptions options) { /* private Long totalSkillPoints = null; private Integer unallocatedSkillPoints = null; */ //Account Balance owner.setAccountBalances(list(getMyAccountBalance(owner, setValues, options))); //Asset owner.setAssets(getMyAssets(owner, setNull, setValues, options)); //Blueprint RawBlueprint rawBlueprint = getRawBlueprint(options); owner.setBlueprints(map(rawBlueprint.getItemID(), rawBlueprint)); //Contract MyContract saveMyContract = getMyContract(setNull, setValues, options); owner.setContracts(map(saveMyContract, list(getMyContractItem(saveMyContract, setNull, setValues, options)))); //IndustryJob owner.setIndustryJobs(set(getMyIndustryJob(owner, setNull, setValues, options))); //Journal owner.setJournal(set(getMyJournal(owner, setNull, setValues, options))); //MarketOrder owner.setMarketOrders(set(getMyMarketOrder(owner, setNull, setValues, options))); //Transaction owner.setTransactions(set(getMyTransaction(owner, setNull, setValues, options))); //Clones owner.setClones(list(getRawClone(setNull, options))); //Skills owner.setSkills(list(getMySkill(owner, setNull, setValues, options))); //Mining owner.setMining(set(getMyMining(owner, setNull, setValues, options))); //Extractions owner.setExtractions(set(getMyExtraction(owner, setNull, setValues, options))); //Loyalty Points owner.setLoyaltyPoints(set(getMyLoyaltyPoints(owner, setNull, setValues, options))); //Npc Standing owner.setNpcStanding(set(getMyNpcStanding(owner, setNull, setValues, options))); //Wallet Divisions //owner.setWalletDivisions(walletDivisions); //Asset Divisions //owner.setAssetDivisions(assetDivisions); } public static Set set(T o) { return new HashSet<>(Collections.singleton(o)); } public static Map map(K key, V value) { return new HashMap<>(Collections.singletonMap(key, value)); } public static List list(T o) { return new ArrayList<>(Collections.singletonList(o)); } private static Item getItem(ConverterTestOptions options) { return ApiIdConverter.getItem(options.getInteger()); } public static RawAccountBalance getRawAccountBalance(ConverterTestOptions options) { RawAccountBalance rawAccountBalance = RawAccountBalance.create(); setValues(rawAccountBalance, options, null); return rawAccountBalance; } public static MyAccountBalance getMyAccountBalance(OwnerType owner, boolean setValues, ConverterTestOptions options) { MyAccountBalance accountBalance = new MyAccountBalance(getRawAccountBalance(options), owner); if (setValues) { setValues(accountBalance, options, null, false); } return accountBalance; } public static RawAsset getRawAsset(boolean setNull, ConverterTestOptions options) { RawAsset rawAsset = RawAsset.create(); setValues(rawAsset, options, setNull ? CharacterAssetsResponse.class : null); return rawAsset; } public static MyAsset getMyAsset(OwnerType owner, boolean setNull, boolean setValues, ConverterTestOptions options) { MyAsset asset = new MyAsset(getRawAsset(setNull, options), getItem(options), owner, new ArrayList<>()); if (setValues) { setValues(asset, options, null, false); } return asset; } public static List getMyAssets(OwnerType owner, boolean setNull, boolean setValues, ConverterTestOptions options) { MyAsset rootAsset = getMyAsset(owner, setNull, setValues, options); if (setValues) { setValues(rootAsset, options, null, false); } rootAsset.setItemID(rootAsset.getItemID() + 1); MyAsset childAsset = getMyAsset(owner, setNull, setValues, options); if (setValues) { setValues(childAsset, options, null, false); } rootAsset.getAssets().add(childAsset); return list(rootAsset); } public static RawBlueprint getRawBlueprint(ConverterTestOptions options) { RawBlueprint rawBlueprint = RawBlueprint.create(); setValues(rawBlueprint, options, CharacterBlueprintsResponse.class); return rawBlueprint; } public static RawContract getRawContract(boolean setNull, ConverterTestOptions options) { RawContract rawContract = RawContract.create(); setValues(rawContract, options, setNull ? CharacterContractsResponse.class : null); return rawContract; } public static MyContract getMyContract(boolean setNull, boolean setValues, ConverterTestOptions options) { MyContract contract = new MyContract(getRawContract(setNull, options)); if (setValues) { setValues(contract, options, null, false); } return contract; } public static RawContractItem getRawContractItem(boolean setNull, ConverterTestOptions options) { RawContractItem rawContractItem = RawContractItem.create(); setValues(rawContractItem, options, setNull ? ContractItemsResponse.class : null); return rawContractItem; } public static MyContractItem getMyContractItem(MyContract contract, boolean setNull, boolean setValues, ConverterTestOptions options) { MyContractItem contractItem = new MyContractItem(getRawContractItem(setNull, options), contract, getItem(options)); if (setValues) { setValues(contractItem, options, null, false); } return contractItem; } public static RawIndustryJob getRawIndustryJob(boolean setNull, ConverterTestOptions options) { RawIndustryJob rawIndustryJob = RawIndustryJob.create(); setValues(rawIndustryJob, options, setNull ? CharacterIndustryJobsResponse.class : null); return rawIndustryJob; } public static MyIndustryJob getMyIndustryJob(OwnerType owner, boolean setNull, boolean setValues, ConverterTestOptions options) { RawIndustryJob rawIndustryJob = getRawIndustryJob(setNull, options); Item item = getItem(options); Item output = ApiIdConverter.getItem(rawIndustryJob.getProductTypeID()); MyIndustryJob industryJob = new MyIndustryJob(rawIndustryJob, item, output, owner); if (setValues) { setValues(industryJob, options, null, false); } return industryJob; } public static RawJournal getRawJournal(boolean setNull, ConverterTestOptions options) { RawJournal rawJournal = RawJournal.create(); setValues(rawJournal, options, setNull ? CharacterWalletJournalResponse.class : null); return rawJournal; } public static MyJournal getMyJournal(OwnerType owner, boolean setNull, boolean setValues, ConverterTestOptions options) { MyJournal journal = new MyJournal(getRawJournal(setNull, options), owner); if (setValues) { setValues(journal, options, null, false); } return journal; } public static RawMarketOrder getRawMarketOrder(boolean setNull, ConverterTestOptions options) { RawMarketOrder rawMarketOrder = RawMarketOrder.create(); setValues(rawMarketOrder, options, setNull ? CharacterOrdersResponse.class : null); return rawMarketOrder; } public static MyMarketOrder getMyMarketOrder(OwnerType owner, boolean setNull, boolean setValues, ConverterTestOptions options) { MyMarketOrder marketOrder = new MyMarketOrder(getRawMarketOrder(setNull, options), getItem(options), owner); if (setValues) { setValues(marketOrder, options, null, false); } return marketOrder; } public static RawTransaction getRawTransaction(boolean setNull, ConverterTestOptions options) { RawTransaction rawTransaction = RawTransaction.create(); setValues(rawTransaction, options, setNull ? CharacterWalletTransactionsResponse.class : null); return rawTransaction; } public static MyTransaction getMyTransaction(OwnerType owner, boolean setNull, boolean setValues, ConverterTestOptions options) { MyTransaction transaction = new MyTransaction(getRawTransaction(setNull, options), getItem(options), owner); if (setValues) { setValues(transaction, options, null, false); } return transaction; } public static RawClone getRawClone(boolean setNull, ConverterTestOptions options) { RawClone rawClone = RawClone.create(); setValues(rawClone, options, setNull ? CharacterMiningResponse.class : null); return rawClone; } public static RawSkill getRawSkill(boolean setNull, ConverterTestOptions options) { RawSkill rawSkill = RawSkill.create(); setValues(rawSkill, options, setNull ? CharacterMiningResponse.class : null); return rawSkill; } public static MySkill getMySkill(OwnerType owner, boolean setNull, boolean setValues, ConverterTestOptions options) { MySkill skill = new MySkill(getRawSkill(setNull, options), getItem(options), options.getString()); if (setValues) { setValues(skill, options, null, false); } return skill; } public static RawLoyaltyPoints getRawLoyaltyPoints(boolean setNull, ConverterTestOptions options) { RawLoyaltyPoints rawLoyaltyPoints = RawLoyaltyPoints.create(); setValues(rawLoyaltyPoints, options, setNull ? CharacterMiningResponse.class : null); return rawLoyaltyPoints; } public static MyLoyaltyPoints getMyLoyaltyPoints(OwnerType owner, boolean setNull, boolean setValues, ConverterTestOptions options) { MyLoyaltyPoints loyaltyPoints = new MyLoyaltyPoints(getRawLoyaltyPoints(setNull, options), owner); if (setValues) { setValues(loyaltyPoints, options, null, false); } return loyaltyPoints; } public static RawNpcStanding getRawNpcStanding(boolean setNull, ConverterTestOptions options) { RawNpcStanding rawNpcStanding = RawNpcStanding.create(); setValues(rawNpcStanding, options, setNull ? CharacterMiningResponse.class : null); return rawNpcStanding; } public static MyNpcStanding getMyNpcStanding(OwnerType owner, boolean setNull, boolean setValues, ConverterTestOptions options) { MyNpcStanding npcStanding = new MyNpcStanding(getRawNpcStanding(setNull, options), owner); if (setValues) { setValues(npcStanding, options, null, false); } return npcStanding; } public static RawMining getRawMining(boolean setNull, ConverterTestOptions options) { RawMining rawMining = RawMining.create(); setValues(rawMining, options, setNull ? CharacterMiningResponse.class : null); return rawMining; } public static MyMining getMyMining(OwnerType owner, boolean setNull, boolean setValues, ConverterTestOptions options) { MyMining mining = new MyMining(getRawMining(setNull, options), getItem(options), options.getMyLocation()); if (setValues) { setValues(mining, options, null, false); } return mining; } public static RawExtraction getRawExtraction(boolean setNull, ConverterTestOptions options) { RawExtraction rawExtraction = RawExtraction.create(); setValues(rawExtraction, options, setNull ? CorporationMiningExtractionsResponse.class : null); return rawExtraction; } public static MyExtraction getMyExtraction(OwnerType owner, boolean setNull, boolean setValues, ConverterTestOptions options) { MyExtraction mining = new MyExtraction(getRawExtraction(setNull, options), options.getMyLocation()); if (setValues) { setValues(mining, options, null, false); } return mining; } public static void testOwner(OwnerType esiOwner, boolean setNull, ConverterTestOptions options) { //Account Balance assertEquals(esiOwner.getAccountBalances().size(), 1); MyAccountBalance loadAccountBalance = esiOwner.getAccountBalances().get(0); testValues(loadAccountBalance, options, null, false); //Asset if (!esiOwner.getAssets().isEmpty()) { assertEquals("List empty @" + options.getIndex(), 1, esiOwner.getAssets().size()); MyAsset rootMyAsset = esiOwner.getAssets().get(0); testValues(rootMyAsset, options, setNull ? CharacterAssetsResponse.class : null, false); assertEquals("List empty @" + options.getIndex(), 1, rootMyAsset.getAssets().size()); MyAsset childMyAsset = rootMyAsset.getAssets().get(0); testValues(childMyAsset, options, setNull ? CharacterAssetsResponse.class : null, false); } else { assertEquals(esiOwner.getAssets().size(), 0); } //Blueprint assertEquals(esiOwner.getBlueprints().size(), 1); RawBlueprint loadRawBlueprint = esiOwner.getBlueprints().values().iterator().next(); testValues(loadRawBlueprint, options, setNull ? CharacterBlueprintsResponse.class : null, false); //Contract assertEquals(esiOwner.getContracts().size(), 1); Map.Entry> entry = esiOwner.getContracts().entrySet().iterator().next(); testValues(entry.getKey(), options, setNull ? CharacterContractsResponse.class : null, false); testValues(entry.getValue().iterator().next(), options, setNull ? ContractItemsResponse.class : null, false); //IndustryJobs assertEquals(esiOwner.getIndustryJobs().size(), 1); MyIndustryJob loadMyIndustryJob = esiOwner.getIndustryJobs().iterator().next(); testValues(loadMyIndustryJob, options, setNull ? CharacterIndustryJobsResponse.class : null, false); //Journal assertEquals(esiOwner.getJournal().size(), 1); MyJournal loadMyJournal = esiOwner.getJournal().iterator().next(); testValues(loadMyJournal, options, setNull ? CharacterWalletJournalResponse.class : null, false); //MarketOrder assertEquals(esiOwner.getMarketOrders().size(), 1); MyMarketOrder loadMyMarketOrder = esiOwner.getMarketOrders().iterator().next(); testValues(loadMyMarketOrder, options, setNull ? CharacterOrdersResponse.class : null, false); //Transactions assertEquals(esiOwner.getTransactions().size(), 1); MyTransaction loadMyTransaction = esiOwner.getTransactions().iterator().next(); testValues(loadMyTransaction, options, setNull ? CharacterWalletTransactionsResponse.class : null, false); } public static void setValues(Object object, ConverterTestOptions options) { setValues(object, options, null, true); } public static void setValues(Object object, ConverterTestOptions options, Class esi) { setValues(object, options, esi, true); } private static void setValues(Object object, ConverterTestOptions options, Class esi, boolean overwrite) { List fields = new ArrayList<>(); fields.addAll(Arrays.asList(object.getClass().getDeclaredFields())); if (object.getClass().getSuperclass() != null) { fields.addAll(Arrays.asList(object.getClass().getSuperclass().getDeclaredFields())); } fields.addAll(Arrays.asList(object.getClass().getDeclaredFields())); Map optional = getOptional(esi); for (Field field : fields) { Class type = field.getType(); String name = field.getName(); if (ignore(object, field, type)) { continue; } try { field.setAccessible(true); if (!overwrite && field.get(object) != null) { continue; } if ((Long.class.equals(type) || long.class.equals(type)) && ("locationID".equals(name) || "locationId".equals(name) || "stationId".equals(name) || "startLocationId".equals(name) || "endLocationId".equals(name))) { if (isOptional(optional, field)) { if (type.equals(Boolean.class) || type.equals(boolean.class)) { field.set(object, false); } else { field.set(object, options.getNull()); } } else { field.set(object, options.getLocationID()); } } field.set(object, getValue(type, isOptional(optional, field), options)); } catch (IllegalArgumentException | IllegalAccessException ex) { fail(ex.getMessage()); } } //Account Balance //ESI if (object instanceof CorporationWalletsResponse) { CorporationWalletsResponse response = (CorporationWalletsResponse) object; response.setDivision(response.getDivision() - 999); } //Assets //ESI Character if (object instanceof CharacterAssetsResponse) { CharacterAssetsResponse asset = (CharacterAssetsResponse) object; asset.setItemId(asset.getItemId() + 1); //Workaround for itemID == locationID } //ESI Corporation if (object instanceof CorporationAssetsResponse) { CorporationAssetsResponse asset = (CorporationAssetsResponse) object; asset.setItemId(asset.getItemId() + 1); //Workaround for itemID == locationID } //ESI Ship if (object instanceof CharacterShipResponse) { CharacterShipResponse asset = (CharacterShipResponse) object; asset.setShipItemId(asset.getShipItemId()+ 1); //Workaround for itemID == locationID } //ESI Location if (object instanceof CharacterLocationResponse) { CharacterLocationResponse asset = (CharacterLocationResponse) object; long locationID = options.getLocationID(); if (locationID >= 30000000 && locationID <= 32000000) { //System asset.setSolarSystemId(locationID); asset.setStationId(null); asset.setStructureId(null); } else if (locationID >= 60000000 && locationID <= 64000000) { //Station asset.setSolarSystemId(null); asset.setStationId(locationID); asset.setStructureId(null); } else { //Other asset.setSolarSystemId(null); asset.setStationId(null); asset.setStructureId(locationID); } } //Raw if (object instanceof RawAsset) { RawAsset asset = (RawAsset) object; asset.setItemID(asset.getItemID() + 1); //Workaround for itemID == locationID } //EsiOwner if (object instanceof EsiOwner) { EsiOwner esiOwner = (EsiOwner) object; esiOwner.setAuth(EsiCallbackURL.LOCALHOST, options.getString(), options.getString()); } } public static void testValues(Object object, ConverterTestOptions options) { testValues(object, options, null, true); } public static void testValues(Object object, ConverterTestOptions options, Class esi) { testValues(object, options, esi, true); } public static void testValues(Object object, ConverterTestOptions options, Class esi, boolean superClassOnly) { if (object instanceof MyAsset) { MyAsset myAsset = (MyAsset) object; if (myAsset.getAssets().isEmpty()) { myAsset.setItemID(myAsset.getItemID() - 1); //Workaround for itemID == locationID } else { myAsset.setItemID(myAsset.getItemID() - 2); //Workaround for itemID == locationID } myAsset.setLocationID(options.getLong()); myAsset.setLocationFlagString(options.getString()); myAsset.setItemFlag(options.getItemFlag()); } if (object instanceof MyContract) { MyContract myContract = (MyContract) object; if (myContract.getAvailability() == RawContract.ContractAvailability.PERSONAL && (options.getContractAvailabilityRaw() == RawContract.ContractAvailability.CORPORATION || options.getContractAvailabilityRaw() == RawContract.ContractAvailability.ALLIANCE)) { myContract.setAvailability(options.getContractAvailabilityRaw()); } if (myContract.getStatus() != null) { myContract.setStatus(options.getContractStatusRaw()); } } if (object instanceof MyContractItem) { MyContractItem myContractItem = (MyContractItem) object; myContractItem.setItemID(options.getLong()); myContractItem.setLicensedRuns(options.getInteger()); myContractItem.setME(options.getInteger()); myContractItem.setTE(options.getInteger()); } if (object instanceof MyIndustryJob) { MyIndustryJob industryJob = (MyIndustryJob) object; if (industryJob.getStatus() != null) { industryJob.setStatus(options.getIndustryJobStatusRaw()); } } if (object instanceof MyMarketOrder) { MyMarketOrder marketOrder = (MyMarketOrder) object; marketOrder.setWalletDivision(options.getInteger()); if (marketOrder.getState() != null) { marketOrder.setState(options.getMarketOrderStateRaw()); } marketOrder.setStateString(options.getString()); marketOrder.setIssuedBy(options.getInteger()); marketOrder.setChanged(options.getDate()); marketOrder.addChanges(set(new Change(new Date(), 0.0, 0))); } if (object instanceof MyJournal) { MyJournal journal = (MyJournal) object; journal.setDescription(options.getString()); } Map optional = getOptional(esi); for (Field field : getField(object, true)) { Class type = field.getType(); if (ignore(object, field, type)) { continue; } try { field.setAccessible(true); assertEquals(getString(field, object, options.getIndex()), getValue(type, isOptional(optional, field), options), field.get(object)); } catch (IllegalArgumentException | IllegalAccessException ex) { fail(ex.getMessage()); } } } private static List getField(Object object, boolean superClassOnly) { List fields = new ArrayList<>(); if (superClassOnly) { fields.addAll(Arrays.asList(object.getClass().getSuperclass().getDeclaredFields())); } else { fields.addAll(Arrays.asList(object.getClass().getSuperclass().getDeclaredFields())); fields.addAll(Arrays.asList(object.getClass().getDeclaredFields())); } return fields; } private static boolean ignore(Object object, Field field, Class type) { if (object.getClass().equals(MyMarketOrder.class) && field.getName().equals("regionId")) { return true; } if (Modifier.isStatic(field.getModifiers())) { //Ignore static fields return true; } if (type.equals(List.class)) { return true; } if (type.equals(Set.class)) { return true; } if (type.equals(Map.class)) { return true; } if (type.equals(ApiClient.class)) { return true; } if (type.equals(MarketApi.class)) { return true; } if (type.equals(IndustryApi.class)) { return true; } if (type.equals(CharacterApi.class)) { return true; } if (type.equals(AssetsApi.class)) { return true; } if (type.equals(WalletApi.class)) { return true; } if (type.equals(UniverseApi.class)) { return true; } if (type.equals(ContractsApi.class)) { return true; } if (type.equals(CorporationApi.class)) { return true; } if (type.equals(LocationApi.class)) { return true; } if (type.equals(UserInterfaceApi.class)) { return true; } if (type.equals(PlanetaryInteractionApi.class)) { return true; } if (type.equals(SkillsApi.class)) { return true; } if (type.equals(LoyaltyApi.class)) { return true; } if (type.equals(ClonesApi.class)) { return true; } return false; } private static Object getValue(Class type, boolean optional, ConverterTestOptions options) { if (options == null) { throw new RuntimeException("Option is null"); } if (optional) { if (type.equals(Boolean.class) || type.equals(boolean.class)) { return false; //Optional boolean should default to false } else { return options.getNull(); //Optional, must handle null } } else if (type.equals(Integer.class) || type.equals(int.class)) { return options.getInteger(); } else if (type.equals(Float.class) || type.equals(float.class)) { return options.getFloat(); } else if (type.equals(Boolean.class) || type.equals(boolean.class)) { return options.getBoolean(); } else if (type.equals(Long.class) || type.equals(long.class)) { return options.getLong(); } else if (type.equals(Double.class) || type.equals(double.class)) { return options.getDouble(); } else if (type.equals(String.class)) { return options.getString(); } else if (type.equals(Date.class)) { return options.getDate(); } else if (type.equals(ItemFlag.class)) { return options.getItemFlag(); } else if (type.equals(RawContract.ContractAvailability.class)) { return options.getContractAvailabilityRaw(); } else if (type.equals(RawContract.ContractStatus.class)) { return options.getContractStatusRaw(); } else if (type.equals(RawContract.ContractType.class)) { return options.getContractTypeRaw(); } else if (type.equals(RawIndustryJob.IndustryJobStatus.class)) { return options.getIndustryJobStatusRaw(); } else if (type.equals(RawJournalRefType.class)) { return options.getJournalRefTypeRaw(); } else if (type.equals(RawMarketOrder.MarketOrderRange.class)) { return options.getMarketOrderRangeRaw(); } else if (type.equals(RawMarketOrder.MarketOrderState.class)) { return options.getMarketOrderStateRaw(); } else if (type.equals(MyLocation.class)) { return options.getMyLocation(); } else if (type.equals(PriceData.class)) { return options.getPriceData(); } else if (type.equals(UserItem.class)) { return options.getUserPrice(); } else if (type.equals(MarketPriceData.class)) { return options.getMarketPriceData(); } else if (type.equals(Tags.class)) { return options.getTags(); } else if (type.equals(RawBlueprint.class)) { return options.getRawBlueprint(); } else if (type.equals(Percent.class)) { return options.getPercent(); } else if (type.equals(CharacterBlueprintsResponse.LocationFlagEnum.class)) { return options.getLocationFlagEsiBlueprintCharacter(); } else if (type.equals(CorporationBlueprintsResponse.LocationFlagEnum.class)) { return options.getLocationFlagEsiBlueprintCorporation(); } else if (type.equals(OffsetDateTime.class)) { return options.getOffsetDateTime(); } else if (type.equals(CharacterIndustryJobsResponse.StatusEnum.class)) { return options.getIndustryJobStatusEsiCharacter(); } else if (type.equals(CorporationIndustryJobsResponse.StatusEnum.class)) { return options.getIndustryJobStatusEsiCorporation(); } else if (type.equals(CharacterWalletJournalResponse.RefTypeEnum.class)) { return options.getJournalRefTypeEsiCharacter(); } else if (type.equals(CharacterWalletJournalResponse.ContextIdTypeEnum.class)) { return options.getJournalContextTypeEsiCharacter(); } else if (type.equals(CorporationWalletJournalResponse.RefTypeEnum.class)) { return options.getJournalRefTypeEsiCorporation(); } else if (type.equals(CorporationWalletJournalResponse.ContextIdTypeEnum.class)) { return options.getJournalContextTypeEsiCorporation(); } else if (type.equals(ContextType.class)) { return options.getJournalContextTypeRaw(); } else if (type.equals(CharacterContractsResponse.AvailabilityEnum.class)) { return options.getContractAvailabilityEsiCharacter(); } else if (type.equals(CorporationContractsResponse.AvailabilityEnum.class)) { return options.getContractAvailabilityEsiCorporation(); } else if (type.equals(CharacterContractsResponse.StatusEnum.class)) { return options.getContractStatusEsiCharacter(); } else if (type.equals(CorporationContractsResponse.StatusEnum.class)) { return options.getContractStatusEsiCorporation(); } else if (type.equals(CharacterContractsResponse.TypeEnum.class)) { return options.getContractTypeEsiCharacter(); } else if (type.equals(CorporationContractsResponse.TypeEnum.class)) { return options.getContractTypeEsiCorporation(); } else if (type.equals(CharacterOrdersResponse.RangeEnum.class)) { return options.getMarketOrderRangeEsiCharacter(); } else if (type.equals(CorporationOrdersResponse.RangeEnum.class)) {// return options.getMarketOrderRangeEsiCorporation(); } else if (type.equals(CharacterAssetsResponse.LocationFlagEnum.class)) { return options.getLocationFlagEsiAssetsCharacter(); } else if (type.equals(CorporationAssetsResponse.LocationFlagEnum.class)) { return options.getLocationFlagEsiAssetsCorporation(); } else if (type.equals(CharacterAssetsResponse.LocationTypeEnum.class)) { return options.getLocationTypeEsiCharacter(); } else if (type.equals(CorporationAssetsResponse.LocationTypeEnum.class)) { return options.getLocationTypeEsiCorporation(); } else if (type.equals(BigDecimal.class)) { return options.getBigDecimal(); } else if (type.equals(EsiCallbackURL.class)) { return options.getEsiCallbackURL(); } else if (type.equals(ApiClient.class)) { return new ApiClient(); } else if (type.equals(CorporationOrdersHistoryResponse.RangeEnum.class)) { return options.getMarketOrderRangeEsiCorporationHistory(); } else if (type.equals(CorporationOrdersHistoryResponse.StateEnum.class)) { return options.getMarketOrderStateEsiCorporationHistory(); } else if (type.equals(CharacterOrdersHistoryResponse.RangeEnum.class)) { return options.getMarketOrderRangeEsiCharacterHistory(); } else if (type.equals(CharacterOrdersHistoryResponse.StateEnum.class)) { return options.getMarketOrderStateEsiCharacterHistory(); } else if (type.equals(Outbid.class)) { return options.getMarketOrdersOutbid(); } else if (type.equals(MyShip.class)) { return options.getMyShip(); } else if (type.equals(JButton.class)) { return options.getButton(); } else if (type.equals(MyBlueprint.class)) { return options.getMyBlueprint(); } else if (type.equals(FromType.class)) { return options.getNpcStandingFromType(); } else if (type.equals(TextIcon.class)) { return options.getTextIcon(); } else { fail("No test value for: " + type.getSimpleName()); return null; } } private static String getString(Field field, Object object, int index) { return object.getClass().getSimpleName() + "->" + field.getName() + " @index: " + index; } private static boolean isOptional(Map optional, Field field) { Boolean isOptional = optional.get(field.getName().toLowerCase()); if (isOptional == null) { return false; } else { return isOptional; } } private static Map getOptional(Class esi) { Map optional = new HashMap<>(); if (esi == null) { return optional; } for (Method method : esi.getDeclaredMethods()) { String methodName = method.getName(); String methodId = esi.getSimpleName() + "->" + methodName; if (methodId.equals("CharacterAssetsResponse->getQuantity") //Quantity is not optional in RawAsset || methodId.equals("CorporationAssetsResponse->getQuantity") //Quantity is not optional in RawAsset //RawJournalExtraInfo is not optional in RawJournal || methodId.equals("CharacterWalletJournalResponse->getExtraInfo") || methodId.equals("CorporationWalletJournalResponse->getExtraInfo") //escrow is not optional in RawMarketOrder || methodId.equals("CharacterOrdersHistoryResponse->getEscrow") || methodId.equals("CorporationOrdersHistoryResponse->getEscrow") || methodId.equals("CharacterOrdersResponse->getEscrow") || methodId.equals("CorporationOrdersResponse->getEscrow") // issuedBy workaround for optional in CorporationOrdersHistoryResponse || methodId.equals("CorporationOrdersHistoryResponse->getIssuedBy") //isBuyOrder is not optional in RawMarketOrder || methodId.equals("CharacterOrdersHistoryResponse->getIsBuyOrder") || methodId.equals("CorporationOrdersHistoryResponse->getIsBuyOrder") || methodId.equals("CharacterOrdersResponse->getIsBuyOrder") || methodId.equals("CorporationOrdersResponse->getIsBuyOrder") //minVolume is not optional in RawMarketOrder || methodId.equals("CharacterOrdersHistoryResponse->getMinVolume") || methodId.equals("CorporationOrdersHistoryResponse->getMinVolume") || methodId.equals("CharacterOrdersResponse->getMinVolume") || methodId.equals("CorporationOrdersResponse->getMinVolume") ) { continue; } if (methodName.startsWith("get") && methodName.endsWith("String") ) { optional.put(methodName.toLowerCase().replaceFirst("get", "").replace("string", ""), false); } else if (Enum.class.isAssignableFrom(method.getReturnType())) { //All enums should be treaded as optional as they can be null for new unknown values optional.put(methodName.toLowerCase().replaceFirst("get", "") + "enum", true); } else if (methodName.startsWith("get")) { Annotation[] annotations = method.getAnnotations(); for (Annotation annotation : annotations) { if (javax.annotation.Nonnull.class.equals(annotation.annotationType())) { optional.put(methodName.toLowerCase().replaceFirst("get", ""), false); break; } if (javax.annotation.Nullable.class.equals(annotation.annotationType())) { optional.put(methodName.toLowerCase().replaceFirst("get", ""), true); break; } } } } return optional; } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/shared/DataConverterTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyAccountBalance; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyExtraction; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.api.raw.RawAsset; import net.nikr.eve.jeveasset.data.api.raw.RawContract; import net.nikr.eve.jeveasset.data.api.raw.RawJournal; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.MarketOrderState; import net.nikr.eve.jeveasset.data.api.raw.RawTransaction; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.io.local.profile.ProfileDatabase; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import org.junit.BeforeClass; import org.junit.Test; public class DataConverterTest extends TestUtil { @BeforeClass public static void setUpClass() { ProfileDatabase.setUpdateConnectionUrl(null); } @Test public void testAssetIndustryJob() { Date date = new Date(); for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { EsiOwner esiOwner = ConverterTestUtil.getEsiOwner(options); esiOwner.setAssetLastUpdate(date); MyIndustryJob industryJob = ConverterTestUtil.getMyIndustryJob(esiOwner, false, true, options); industryJob.setJobID(industryJob.getJobID() + 1); industryJob.setBlueprintID(industryJob.getBlueprintID() + 1); industryJob.setCompletedDate(new Date(date.getTime() + 1L)); List assets = DataConverter.assetIndustryJob(Collections.singletonList(industryJob), true, true); if (industryJob.isDone()) { assertTrue(assets.isEmpty()); continue; } assertFalse(assets.isEmpty()); MyAsset asset = assets.get(0); //Quantity assertEquals((Object) asset.getQuantity(), -2); asset.setQuantity(options.getInteger()); assertEquals(asset.getItemFlag().getFlagName(), General.get().industryJobFlag()); assertEquals(asset.getItemFlag().getFlagText(), General.get().industryJobFlag()); //ItemFlag asset.setItemFlag(options.getItemFlag()); ConverterTestUtil.testValues(assets.get(0), options); } } @Test public void testAssetMarketOrder() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { MyMarketOrder marketOrder = ConverterTestUtil.getMyMarketOrder(ConverterTestUtil.getEsiOwner(options), false, true, options); marketOrder.setOrderID(marketOrder.getOrderID() + 1); List assets = DataConverter.assetMarketOrder(Collections.singletonList(marketOrder), true, true); if (assets.isEmpty()) { assertFalse(marketOrder.isActive()); } else { MyAsset asset = assets.get(0); //Singleton assertEquals(asset.isSingleton(), false); asset.setSingleton(true); //ItemFlag assertEquals(asset.getItemFlag().getFlagName(), General.get().marketOrderBuyFlag()); assertEquals(asset.getItemFlag().getFlagText(), General.get().marketOrderBuyFlag()); asset.setItemFlag(options.getItemFlag()); ConverterTestUtil.testValues(asset, options); } } } @Test public void testAssetContracts() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { MyContractItem contractItem = ConverterTestUtil.getMyContractItem(ConverterTestUtil.getMyContract(false, true, options), false, true, options); contractItem.setRecordID(contractItem.getRecordID() + 1); contractItem.setItemID(contractItem.getItemID()+ 1); final Map owners = new HashMap<>(); EsiOwner owner = ConverterTestUtil.getEsiOwner(options); owners.put(owner.getOwnerID(), owner); List assets = DataConverter.assetContracts(Collections.singletonList(contractItem), owners, true, true); if (assets.isEmpty()) { assertTrue((!contractItem.getContract().isOpen()) || contractItem.getContract().isIgnoreContract()); } else { MyAsset asset = assets.get(0); assertEquals(asset.getItemFlag().getFlagName(), General.get().contractIncluded()); assertEquals(asset.getItemFlag().getFlagText(), General.get().contractIncluded()); asset.setItemFlag(options.getItemFlag()); ConverterTestUtil.testValues(asset, options); } } } @Test public void testConvertRawAccountBalance() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { List accountBalances = DataConverter.convertRawAccountBalance(Collections.singletonList(ConverterTestUtil.getRawAccountBalance(options)), ConverterTestUtil.getEsiOwner(options)); ConverterTestUtil.testValues(accountBalances.get(0), options); } } @Test public void testToMyAccountBalance() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { MyAccountBalance accountBalance = DataConverter.toMyAccountBalance(ConverterTestUtil.getRawAccountBalance(options), ConverterTestUtil.getEsiOwner(options)); ConverterTestUtil.testValues(accountBalance, options); } } @Test public void testConvertRawAssets() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { List rawAssets = new ArrayList<>(); RawAsset rootRawAsset = ConverterTestUtil.getRawAsset(false, options); rootRawAsset.setItemID(rootRawAsset.getItemID() + 1); rawAssets.add(rootRawAsset); RawAsset childRawAsset = ConverterTestUtil.getRawAsset(false, options); rawAssets.add(childRawAsset); childRawAsset.setLocationID(rootRawAsset.getItemID()); EsiOwner owner = ConverterTestUtil.getEsiOwner(options); List assets = DataConverter.convertRawAssets(rawAssets, owner); if (!assets.isEmpty()) { assertEquals("List empty @" + options.getIndex(), 1, assets.size()); ConverterTestUtil.testValues(assets.get(0), options); assertEquals("List empty @" + options.getIndex(), 1, assets.get(0).getAssets().size()); MyAsset childMyAsset = assets.get(0).getAssets().get(0); ConverterTestUtil.testValues(childMyAsset, options); } else { assertEquals(assets.size(), 0); } } } @Test public void testToMyAsset() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { RawAsset rawAsset = ConverterTestUtil.getRawAsset(false, options); EsiOwner owner = ConverterTestUtil.getEsiOwner(options); MyAsset asset = DataConverter.toMyAsset(rawAsset, owner, new ArrayList<>()); if (asset != null) { assertNotNull("Object null @" + options.getIndex(), asset); ConverterTestUtil.testValues(asset, options); } else { assertNull(asset); } } } @Test public void testConvertRawContracts() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { Map> contracts = DataConverter.convertRawContracts(Collections.singletonList(ConverterTestUtil.getRawContract(false, options)), ConverterTestUtil.getEsiOwner(options), false); ConverterTestUtil.testValues(contracts.keySet().iterator().next(), options); } } @Test public void testConvertRawContractsHistory() { List converterOptions = ConverterTestOptionsGetter.getConverterOptions(); ConverterTestOptions options = converterOptions.get(0); ConverterTestOptions options1 = converterOptions.get(1); EsiOwner esiOwner = ConverterTestUtil.getEsiOwner(options); MyContract contract = ConverterTestUtil.getMyContract(true, true, options); MyContractItem contractItem = ConverterTestUtil.getMyContractItem(contract, false, true, options); esiOwner.getContracts().put(contract, Collections.singletonList(contractItem)); List rawContracts = new ArrayList<>(); RawContract rawContract = ConverterTestUtil.getRawContract(false, options); rawContracts.add(rawContract); RawContract rawContract1 = ConverterTestUtil.getRawContract(false, options1); rawContracts.add(rawContract1); //Add old rawContract.setContractID(0); rawContract1.setContractID(1); contract.setContractID(2); Map> contracts = DataConverter.convertRawContracts(rawContracts, esiOwner, true); assertEquals(contracts.size(), 3); //Add overwrite rawContract.setContractID(0); rawContract1.setContractID(1); contract.setContractID(0); //Duplicate contract.setAssigneeID(100); //Wrong rawContract.setAssigneeID(200); //Expected contracts = DataConverter.convertRawContracts(rawContracts, esiOwner, true); assertEquals(contracts.size(), 2); boolean found = false; for (MyContract myContract : contracts.keySet()) { if (myContract.getAssigneeID() > 50) { assertEquals(myContract.getAssigneeID(), 200); found = true; } } assertTrue(found); } @Test public void testConvertRawContractItems() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { Map> contractItems = DataConverter.convertRawContractItems(Collections.singletonMap(ConverterTestUtil.getMyContract(false, true, options), Collections.singletonList(ConverterTestUtil.getRawContractItem(false, options))), ConverterTestUtil.getEsiOwner(options), false); ConverterTestUtil.testValues(contractItems.values().iterator().next().get(0), options); } } @Test public void testToMyContract() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { MyContract contract = DataConverter.toMyContract(ConverterTestUtil.getRawContract(false, options)); ConverterTestUtil.testValues(contract, options); } } @Test public void testToMyContractItem() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { MyContractItem contractItem = DataConverter.toMyContractItem(ConverterTestUtil.getRawContractItem(false, options), ConverterTestUtil.getMyContract(false, true, options)); ConverterTestUtil.testValues(contractItem, options); } } @Test public void testConvertRawIndustryJobs() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { Set industryJobs = DataConverter.convertRawIndustryJobs(Collections.singletonList(ConverterTestUtil.getRawIndustryJob(false, options)), ConverterTestUtil.getEsiOwner(options), false); ConverterTestUtil.testValues(industryJobs.iterator().next(), options); } } @Test public void testToMyIndustryJob() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { MyIndustryJob industryJob = DataConverter.toMyIndustryJob(ConverterTestUtil.getRawIndustryJob(false, options), ConverterTestUtil.getEsiOwner(options)); ConverterTestUtil.testValues(industryJob, options); } } @Test public void testConvertRawJournals() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { Set journals = DataConverter.convertRawJournals(Collections.singletonList(ConverterTestUtil.getRawJournal(false, options)), ConverterTestUtil.getEsiOwner(options), false); ConverterTestUtil.testValues(journals.iterator().next(), options); } } @Test public void testConvertRawJournalsHistory() { testConvertRawJournalsHistory(true); testConvertRawJournalsHistory(false); } public void testConvertRawJournalsHistory(boolean saveHistory) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { EsiOwner esiOwner = ConverterTestUtil.getEsiOwner(options); for (long i = 1; i <= 10; i++) { RawJournal rawJournal = ConverterTestUtil.getRawJournal(true, options); MyJournal myJournal = DataConverter.toMyJournal(rawJournal, esiOwner); myJournal.setRefID(i); esiOwner.getJournal().add(myJournal); } List rawJournals = new ArrayList<>(); for (long i = 11; i <= 20; i++) { RawJournal rawJournal = ConverterTestUtil.getRawJournal(true, options); rawJournal.setRefID(i); rawJournals.add(rawJournal); } esiOwner.setJournal(DataConverter.convertRawJournals(rawJournals, esiOwner, saveHistory)); if (saveHistory) { assertThat(esiOwner.getJournal().size(), is(20)); } else { assertThat(esiOwner.getJournal().size(), is(10)); assertTrue(esiOwner.getJournal().iterator().next().getRefID() > 10L); } } } @Test public void testToMyJournal() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { MyJournal journal = DataConverter.toMyJournal(ConverterTestUtil.getRawJournal(false, options), ConverterTestUtil.getEsiOwner(options)); ConverterTestUtil.testValues(journal, options); } } @Test public void testConvertRawMarketOrders() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { Set marketOrders = DataConverter.convertRawMarketOrders(Collections.singletonList(ConverterTestUtil.getRawMarketOrder(false, options)), ConverterTestUtil.getEsiOwner(options), false); ConverterTestUtil.testValues(marketOrders.iterator().next(), options); } } @Test public void testConvertRawMarketOrdersHistory() { testConvertRawMarketOrdersHistory(true); testConvertRawMarketOrdersHistory(false); } public void testConvertRawMarketOrdersHistory(boolean saveHistory) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { EsiOwner esiOwner = ConverterTestUtil.getEsiOwner(options); for (long i = 1; i <= 10; i++) { RawMarketOrder rawMarketOrder = ConverterTestUtil.getRawMarketOrder(true, options); MyMarketOrder myMarketOrder = DataConverter.toMyMarketOrder(rawMarketOrder, esiOwner); myMarketOrder.setOrderID(i); esiOwner.getMarketOrders().add(myMarketOrder); } List rawMarketOrders = new ArrayList<>(); for (long i = 11; i <= 20; i++) { RawMarketOrder rawMarketOrder = ConverterTestUtil.getRawMarketOrder(true, options); rawMarketOrder.setOrderID(i); rawMarketOrders.add(rawMarketOrder); } esiOwner.setMarketOrders(DataConverter.convertRawMarketOrders(rawMarketOrders, esiOwner, saveHistory)); if (saveHistory) { assertThat(esiOwner.getMarketOrders().size(), is(20)); if (options.getMarketOrderStateRaw() == RawMarketOrder.MarketOrderState.OPEN) { for (MyMarketOrder marketOrder : esiOwner.getMarketOrders()) { if (marketOrder.getOrderID() <= 10) { assertThat(marketOrder.getState(), is(MarketOrderState.UNKNOWN)); } else { assertThat(marketOrder.getState(), is(MarketOrderState.OPEN)); } } } } else { assertThat(esiOwner.getMarketOrders().size(), is(10)); assertTrue(esiOwner.getMarketOrders().iterator().next().getOrderID() > 10L); } } } @Test public void testToMyMarketOrder() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { MyMarketOrder marketOrder = DataConverter.toMyMarketOrder(ConverterTestUtil.getRawMarketOrder(false, options), ConverterTestUtil.getEsiOwner(options)); ConverterTestUtil.testValues(marketOrder, options); } } @Test public void testConvertRawTransactions() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { Set transactions = DataConverter.convertRawTransactions(Collections.singletonList(ConverterTestUtil.getRawTransaction(false, options)), ConverterTestUtil.getEsiOwner(options), false); ConverterTestUtil.testValues(transactions.iterator().next(), options); } } @Test public void testConvertRawTransactionsHistory() { testConvertRawTransactionsHistory(true); testConvertRawTransactionsHistory(false); } public void testConvertRawTransactionsHistory(boolean saveHistory) { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { EsiOwner esiOwner = ConverterTestUtil.getEsiOwner(options); for (long i = 1; i <= 10; i++) { RawTransaction rawTransaction = ConverterTestUtil.getRawTransaction(true, options); MyTransaction myTransaction = DataConverter.toMyTransaction(rawTransaction, esiOwner); myTransaction.setTransactionID(i); esiOwner.getTransactions().add(myTransaction); } List rawTransactions = new ArrayList<>(); for (long i = 11; i <= 20; i++) { RawTransaction rawTransaction = ConverterTestUtil.getRawTransaction(true, options); rawTransaction.setTransactionID(i); rawTransactions.add(rawTransaction); } esiOwner.setTransactions(DataConverter.convertRawTransactions(rawTransactions, esiOwner, saveHistory)); if (saveHistory) { assertThat(esiOwner.getTransactions().size(), is(20)); } else { assertThat(esiOwner.getTransactions().size(), is(10)); assertTrue(esiOwner.getTransactions().iterator().next().getTransactionID() > 10L); } } } @Test public void testToMyTransaction() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { MyTransaction transaction = DataConverter.toMyTransaction(ConverterTestUtil.getRawTransaction(false, options), ConverterTestUtil.getEsiOwner(options)); ConverterTestUtil.testValues(transaction, options); } } @Test public void testConvertRawMining() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { Set minings = DataConverter.convertRawMining(Collections.singletonList(ConverterTestUtil.getRawMining(false, options)), ConverterTestUtil.getEsiOwner(options), false); ConverterTestUtil.testValues(minings.iterator().next(), options); } } @Test public void testToMyMining() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { MyMining mining = DataConverter.toMyMining(ConverterTestUtil.getRawMining(false, options)); ConverterTestUtil.testValues(mining, options); } } @Test public void testConvertRawExtraction() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { Set extractions = DataConverter.convertRawExtraction(Collections.singletonList(ConverterTestUtil.getRawExtraction(false, options)), ConverterTestUtil.getEsiOwner(options), false); ConverterTestUtil.testValues(extractions.iterator().next(), options); } } @Test public void testToMyExtraction() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { MyExtraction extraction = DataConverter.toMyExtraction(ConverterTestUtil.getRawExtraction(false, options)); ConverterTestUtil.testValues(extraction, options); } } @Test public void testToMyLoyaltyPoints() { for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { MyLoyaltyPoints loyaltyPoints = DataConverter.toMyLoyaltyPoints(ConverterTestUtil.getRawLoyaltyPoints(true, options), ConverterTestUtil.getEsiOwner(options)); ConverterTestUtil.testValues(loyaltyPoints, options); } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/shared/ProfileDatabaseConverterTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import ca.odell.glazedlists.GlazedLists; import ch.qos.logback.classic.Level; import java.lang.reflect.Field; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; import net.nikr.eve.jeveasset.CliOptions; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.accounts.EsiOwner; import net.nikr.eve.jeveasset.data.api.my.MyAccountBalance; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyExtraction; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyLoyaltyPoints; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyMining; import net.nikr.eve.jeveasset.data.api.my.MyNpcStanding; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.api.raw.RawAsset; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.profile.Profile; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.data.settings.PriceData; import net.nikr.eve.jeveasset.gui.shared.table.containers.Percent; import net.nikr.eve.jeveasset.gui.shared.table.containers.Security; import net.nikr.eve.jeveasset.io.local.profile.ProfileDatabase; import org.junit.After; import org.junit.AfterClass; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.fail; import org.junit.BeforeClass; import org.junit.Test; public class ProfileDatabaseConverterTest extends TestUtil { private static final ObjectComparator COMPARATOR = new ObjectComparator(); @BeforeClass public static void setUpClass() { setLoggingLevel(Level.WARN); } @AfterClass public static void tearDownClass() { setLoggingLevel(Level.INFO); } @After public void testCleanup() { cleanup(); } @Test public void testAbstractOwner() { boolean setNull = false; for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { //Clear previouse test data cleanup(); //Old EsiOwner oldOwner = ConverterTestUtil.getEsiOwner(true, setNull, false, options); //New EsiOwner newOwner = new EsiOwner(oldOwner); testClass("", oldOwner, newOwner, false, true); } } @Test public void testLocal() { //Exiting data CliOptions.get().setPortable(false); ProfileManager manager = new ProfileManager(); manager.searchProfile(); manager.loadActiveProfile(); Profile oldProfile = manager.getActiveProfile(); CliOptions.get().setPortable(true); manager.saveProfile(); //Loaded data manager = new ProfileManager(); manager.searchProfile(); manager.loadActiveProfile(); Profile newProfile = manager.getActiveProfile(); testClass("", oldProfile, newProfile, false, true); } @Test public void testSave() { //Exiting data boolean data = true; boolean setNull = false; boolean setValues = true; for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { //Clear previouse test data cleanup(); //Generated data Profile oldProfile = new Profile(); oldProfile.getEsiOwners().add(ConverterTestUtil.getEsiOwner(data, setNull, setValues, options)); oldProfile.save(); //Loaded data Profile newProfile = new Profile(); newProfile.load(); //Test testClass("", oldProfile, newProfile, false, false); } } @Test public void testUpdate() { boolean data = false; boolean setNull = false; boolean setValues = true; for (ConverterTestOptions options : ConverterTestOptionsGetter.getConverterOptions()) { //Clear previouse test data cleanup(); //Empty data Profile oldProfile = new Profile(); ProfileDatabase.setUpdateConnectionUrl(oldProfile); EsiOwner owner = ConverterTestUtil.getEsiOwner(data, setNull, setValues, options); owner.setScopes(options.getString()); oldProfile.getEsiOwners().add(owner); oldProfile.save(); //Contract Map> contracts = DataConverter.convertRawContracts(Collections.singletonList(ConverterTestUtil.getRawContract(setNull, options)), owner, true); MyContract contract = contracts.entrySet().iterator().next().getKey(); owner.setContracts(DataConverter.convertRawContractItems(Collections.singletonMap(contract, Collections.singletonList(ConverterTestUtil.getRawContractItem(setNull, options))), owner, true)); //Industry Job owner.setIndustryJobs(DataConverter.convertRawIndustryJobs(Collections.singletonList(ConverterTestUtil.getRawIndustryJob(setNull, options)), owner, true)); //Journal owner.setJournal(DataConverter.convertRawJournals(Collections.singletonList(ConverterTestUtil.getRawJournal(setNull, options)), owner, true)); //Market Order owner.setMarketOrders(DataConverter.convertRawMarketOrders(Collections.singletonList(ConverterTestUtil.getRawMarketOrder(setNull, options)), owner, true)); //Transaction owner.setTransactions(DataConverter.convertRawTransactions(Collections.singletonList(ConverterTestUtil.getRawTransaction(setNull, options)), owner, true)); //Mining owner.setMining(DataConverter.convertRawMining(Collections.singletonList(ConverterTestUtil.getRawMining(setNull, options)), owner, true)); //Extractions owner.setExtractions(DataConverter.convertRawExtraction(Collections.singletonList(ConverterTestUtil.getRawExtraction(setNull, options)), owner, true)); ProfileDatabase.waitForUpdates(); //Loaded data Profile newProfile = new Profile(); ProfileDatabase.setUpdateConnectionUrl(newProfile); newProfile.load(); testClass("", oldProfile, newProfile, false, false); } } private void testClass(String msg, Object oldValue, Object newValue, boolean collection, boolean dynamicValuesSet) { if (oldValue == null || newValue == null) { assertEquals(msg, oldValue, newValue); return; } testClass(msg, oldValue.getClass(), newValue.getClass(), oldValue, newValue, collection, dynamicValuesSet); } private void testClass(String input, Class oldClazz, Class newClazz, Object oldValue, Object newValue, boolean collection, boolean dynamicValuesSet) { if (oldClazz == null || newClazz == null) { return; } String msg = input + oldClazz.getSimpleName() + getValue(oldValue) + getValue(newValue); if (oldValue == null || newValue == null || Enum.class.isAssignableFrom(oldValue.getClass())) { assertEquals(msg, oldValue, newValue); } else if (List.class.isAssignableFrom(oldValue.getClass()) && List.class.isAssignableFrom(newValue.getClass())) { List oldList = (List) oldValue; List newList = (List) newValue; assertEquals(msg, oldList.size(), newList.size()); Collections.sort(oldList, COMPARATOR); Collections.sort(newList, COMPARATOR); Iterator oldIterator = oldList.iterator(); Iterator newIterator = newList.iterator(); while (oldIterator.hasNext() && newIterator.hasNext()) { Object oldObject = oldIterator.next(); Object newObject = newIterator.next(); testClass(msg + "[List]>", oldObject, newObject, true, dynamicValuesSet); } assertFalse(msg, oldIterator.hasNext()); assertFalse(msg, newIterator.hasNext()); } else if (Collection.class.isAssignableFrom(oldValue.getClass()) && Collection.class.isAssignableFrom(newValue.getClass())) { Collection oldCollection = (Collection) oldValue; Collection newCollection = (Collection) newValue; assertEquals(msg, oldCollection.size(), newCollection.size()); Iterator oldIterator = oldCollection.iterator(); Iterator newIterator = newCollection.iterator(); while (oldIterator.hasNext() && newIterator.hasNext()) { Object oldObject = oldIterator.next(); Object newObject = newIterator.next(); testClass(msg + "[Collection]>", oldObject, newObject, true, dynamicValuesSet); } assertFalse(msg, oldIterator.hasNext()); assertFalse(msg, newIterator.hasNext()); } else if (Map.class.isAssignableFrom(oldValue.getClass()) && Map.class.isAssignableFrom(newValue.getClass())) { Map oldMap = new TreeMap<>((Map) oldValue); Map newMap = new TreeMap<>((Map) newValue); assertEquals(msg, oldMap.size(), newMap.size()); Iterator oldIterator = oldMap.entrySet().iterator(); Iterator newIterator = newMap.entrySet().iterator(); while (oldIterator.hasNext() && newIterator.hasNext()) { Object oldObject = oldIterator.next(); Object newObject = newIterator.next(); if (oldObject instanceof Map.Entry && newObject instanceof Map.Entry) { Map.Entry oldEntry = (Map.Entry) oldObject; Map.Entry newEntry = (Map.Entry) newObject; testClass(msg + "[Map>Key]>", oldEntry.getKey(), newEntry.getKey(), true, dynamicValuesSet); testClass(msg + "[Map>Value]>", oldEntry.getValue(), newEntry.getValue(), true, dynamicValuesSet); } else { testClass(msg, oldObject, newObject, false, dynamicValuesSet); } } assertFalse(msg, oldIterator.hasNext()); assertFalse(msg, newIterator.hasNext()); } else if (oldClazz.getName().startsWith("net.nikr.eve.jeveasset") || (Object.class.equals(oldClazz) && collection)){ if (!dynamicValuesSet && RawAsset.class.equals(oldClazz)) { //SHOULD BE REMOVED!!! return; } for (Field oldField : oldClazz.getDeclaredFields()) { try { final String fieldName = oldField.getName(); if ("LOG".equals(fieldName) || "$jacocoData".equals(fieldName) || (EsiOwner.class.equals(oldClazz) && ("apiClient".equals(fieldName) || "marketApi".equals(fieldName) || "industryApi".equals(fieldName) || "characterApi".equals(fieldName) || "clonesApi".equals(fieldName) || "assetsApi".equals(fieldName) || "walletApi".equals(fieldName) || "universeApi".equals(fieldName) || "contractsApi".equals(fieldName) || "corporationApi".equals(fieldName) || "locationApi".equals(fieldName) || "planetaryInteractionApi".equals(fieldName) || "userInterfaceApi".equals(fieldName) || "loyaltyApi".equals(fieldName) || "skillsApi".equals(fieldName))) || (MyAsset.class.equals(oldClazz) && ("owner".equals(fieldName) || "parents".equals(fieldName))) || (MyAccountBalance.class.equals(oldClazz) && "owner".equals(fieldName)) || (MyJournal.class.equals(oldClazz) && "owner".equals(fieldName)) || (MyTransaction.class.equals(oldClazz) && "owner".equals(fieldName)) || (MyIndustryJob.class.equals(oldClazz) && "owner".equals(fieldName)) || (MyLoyaltyPoints.class.equals(oldClazz) && "owner".equals(fieldName)) || (MyNpcStanding.class.equals(oldClazz) && "owner".equals(fieldName)) || (MyMarketOrder.class.equals(oldClazz) && ("owner".equals(fieldName) || "jButton".equals(fieldName))) || (Profile.class.equals(oldClazz) && "stockpileIDs".equals(fieldName)) || (MyContractItem.class.equals(oldClazz) && "contract".equals(fieldName)) || (MyLocation.class.equals(oldClazz) && "CACHE".equals(fieldName)) || (Security.class.equals(oldClazz) && "CACHE".equals(fieldName)) || (Percent.class.equals(oldClazz) && "CACHE".equals(fieldName)) || (PriceData.class.equals(oldClazz) && "EMPTY".equals(fieldName)) ) { continue; } if (!dynamicValuesSet && ( (MyTransaction.class.equals(oldClazz) && ("location".equals(fieldName) || "transactionProfitPercent".equals(fieldName) || "tax".equals(fieldName) || "added".equals(fieldName) || "tags".equals(fieldName) || "clientName".equals(fieldName))) || (MyMarketOrder.class.equals(oldClazz) && ("location".equals(fieldName) || "transactionProfitPercent".equals(fieldName) || "brokersFee".equals(fieldName) || "outbid".equals(fieldName))) || (MyJournal.class.equals(oldClazz) && ("added".equals(fieldName) || "tags".equals(fieldName) || "context".equals(fieldName))) || (MyIndustryJob.class.equals(oldClazz) && ("blueprint".equals(fieldName) || "owned".equals(fieldName) || "location".equals(fieldName))) || (MyAsset.class.equals(oldClazz) && ("itemName".equals(fieldName) || "marketPriceData".equals(fieldName) || "added".equals(fieldName) || "tags".equals(fieldName) || "blueprint".equals(fieldName) || "location".equals(fieldName) || "userPrice".equals(fieldName))) || (MyMining.class.equals(oldClazz) && ("location".equals(fieldName) || "characterName".equals(fieldName))) || (MyExtraction.class.equals(oldClazz) && ("moon".equals(fieldName) || "location".equals(fieldName))) || (RawMarketOrder.class.equals(oldClazz) && ("changed".equals(fieldName) || "regionId".equals(fieldName))) || (MyContract.class.equals(oldClazz) && ("endLocation".equals(fieldName) || "startLocation".equals(fieldName))) || (MyLoyaltyPoints.class.equals(oldClazz) && "textIcon".equals(fieldName)) || (MyNpcStanding.class.equals(oldClazz) && ("factionName".equals(fieldName) || "corporationName".equals(fieldName) || "ownerTextIcon".equals(fieldName) || "agentName".equals(fieldName) || "factionTextIcon".equals(fieldName) || "corporationTextIcon".equals(fieldName) || "agentTextIcon".equals(fieldName) )) )) { continue; } Field newField = newClazz.getDeclaredField(fieldName); oldField.setAccessible(true); newField.setAccessible(true); Object oldObject = oldField.get(oldValue); Object newObject = newField.get(newValue); testClass(msg + "." + fieldName + ">", oldObject, newObject, false, dynamicValuesSet); } catch (NoSuchFieldException ex) { fail(ex.getMessage()); } catch (SecurityException ex) { fail(ex.getMessage()); } catch (IllegalArgumentException ex) { fail(ex.getMessage()); } catch (IllegalAccessException ex) { fail(ex.getMessage()); } } testClass(input + "=>", oldClazz.getSuperclass(), newClazz.getSuperclass(), oldValue, newValue, collection, dynamicValuesSet); } else { assertEquals(msg, oldValue, newValue); } } private String getValue(Object object) { if (object == null) { return ""; } else if (object instanceof EsiOwner) { return "(" + ((EsiOwner) object).getOwnerName() + ")"; } else if (object instanceof MyContract) { return "(" + ((MyContract) object).getTitle() + ")"; } else if (object instanceof MyContractItem) { return "(" + ((MyContractItem) object).getContract().getTitle() + ")"; } return ""; } private static class ObjectComparator implements Comparator { @Override public int compare(Object o1, Object o2) { if (o1 instanceof MyAsset && o2 instanceof MyAsset) { return Long.compare(((MyAsset)o1).getItemID(), ((MyAsset)o2).getItemID()); } if (o1 instanceof RawAsset && o2 instanceof RawAsset) { return Long.compare(((RawAsset)o1).getItemID(), ((RawAsset)o2).getItemID()); } if (o1 instanceof Comparable && o2 instanceof Comparable) { return GlazedLists.comparableComparator().compare((Comparable) o1, (Comparable) o2); } return 0; } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/io/shared/RawConverterTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.io.shared; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.Date; import java.util.EnumMap; import java.util.HashMap; import java.util.Map; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.data.api.raw.RawContract; import net.nikr.eve.jeveasset.data.api.raw.RawIndustryJob; import net.nikr.eve.jeveasset.data.api.raw.RawJournal.ContextType; import net.nikr.eve.jeveasset.data.api.raw.RawJournalRefType; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder; import net.nikr.eve.jeveasset.data.sde.ItemFlag; import net.nikr.eve.jeveasset.data.sde.StaticData; import net.nikr.eve.jeveasset.io.shared.RawConverter.LocationFlag; import net.troja.eve.esi.model.CharacterContractsResponse; import net.troja.eve.esi.model.CharacterIndustryJobsResponse; import net.troja.eve.esi.model.CharacterOrdersHistoryResponse; import net.troja.eve.esi.model.CharacterOrdersResponse; import net.troja.eve.esi.model.CharacterWalletJournalResponse; import net.troja.eve.esi.model.CorporationContractsResponse; import net.troja.eve.esi.model.CorporationIndustryJobsResponse; import net.troja.eve.esi.model.CorporationOrdersHistoryResponse; import net.troja.eve.esi.model.CorporationOrdersResponse; import net.troja.eve.esi.model.CorporationWalletJournalResponse; import net.troja.eve.esi.model.MarketRegionOrdersResponse; import net.troja.eve.esi.model.MarketStructureResponse; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import org.junit.Test; public class RawConverterTest extends TestUtil { @Test public void testToDate() { Date from = new Date(); OffsetDateTime offsetDateTime = from.toInstant().atOffset(ZoneOffset.UTC); Date to = RawConverter.toDate(offsetDateTime); assertEquals(from, to); } @Test public void testToFlag_CharacterAssetsResponseLocationFlagEnum() { for (net.troja.eve.esi.model.CharacterAssetsResponse.LocationFlagEnum locationFlagEnum : net.troja.eve.esi.model.CharacterAssetsResponse.LocationFlagEnum.values()) { ItemFlag itemFlag = RawConverter.toFlag(locationFlagEnum); assertNotNull(itemFlag); assertTrue(locationFlagEnum.name() + " (" + locationFlagEnum.toString() + ") != " + itemFlag.getFlagName(), itemFlag.getFlagID() == 0 || locationFlagEnum.toString().toLowerCase().equals(itemFlag.getFlagText().toLowerCase().replace(" ", "")) || locationFlagEnum.toString().toLowerCase().equals(itemFlag.getFlagName().toLowerCase()) || (locationFlagEnum.toString().equals("CorpseBay") && itemFlag.getFlagName().equals("CrateLoot")) || (locationFlagEnum.toString().equals("Module") && itemFlag.getFlagName().equals("Skill")) || (locationFlagEnum.toString().equals("SpecializedOreHold") && itemFlag.getFlagName().equals("SpecializedAsteroidHold")) || (locationFlagEnum.toString().equals("CorporationGoalDeliveries") && itemFlag.getFlagName().equals("CorpProjectsHangar")) || (locationFlagEnum.toString().equals("MobileDepotHold") && itemFlag.getFlagName().equals("MobileDepot")) || (locationFlagEnum.toString().equals("InfrastructureHangar") && itemFlag.getFlagName().equals("ColonyResourcesHold")) ); } } @Test public void testToFlag_CorporationAssetsResponseLocationFlagEnum() { for (net.troja.eve.esi.model.CorporationAssetsResponse.LocationFlagEnum locationFlagEnum : net.troja.eve.esi.model.CorporationAssetsResponse.LocationFlagEnum.values()) { ItemFlag itemFlag = RawConverter.toFlag(locationFlagEnum); assertNotNull(itemFlag); assertTrue(locationFlagEnum.name() + " (" + locationFlagEnum.toString() + ") != " + itemFlag.getFlagName(), itemFlag.getFlagID() == 0 || locationFlagEnum.toString().toLowerCase().equals(itemFlag.getFlagText().toLowerCase().replace(" ", "")) || locationFlagEnum.toString().toLowerCase().equals(itemFlag.getFlagName().toLowerCase()) || (locationFlagEnum.toString().equals("CorpDeliveries") && itemFlag.getFlagName().equals("CorpMarket")) || (locationFlagEnum.toString().equals("Impounded") && itemFlag.getFlagName().equals("OfficeImpound")) || (locationFlagEnum.toString().equals("ServiceSlot0") && itemFlag.getFlagName().equals("StructureServiceSlot0")) || (locationFlagEnum.toString().equals("ServiceSlot1") && itemFlag.getFlagName().equals("StructureServiceSlot1")) || (locationFlagEnum.toString().equals("ServiceSlot2") && itemFlag.getFlagName().equals("StructureServiceSlot2")) || (locationFlagEnum.toString().equals("ServiceSlot3") && itemFlag.getFlagName().equals("StructureServiceSlot3")) || (locationFlagEnum.toString().equals("ServiceSlot4") && itemFlag.getFlagName().equals("StructureServiceSlot4")) || (locationFlagEnum.toString().equals("ServiceSlot5") && itemFlag.getFlagName().equals("StructureServiceSlot5")) || (locationFlagEnum.toString().equals("ServiceSlot6") && itemFlag.getFlagName().equals("StructureServiceSlot6")) || (locationFlagEnum.toString().equals("ServiceSlot7") && itemFlag.getFlagName().equals("StructureServiceSlot7")) || (locationFlagEnum.toString().equals("DustBattle") && itemFlag.getFlagName().equals("DustCharacterBattle")) || (locationFlagEnum.toString().equals("DustDatabank") && itemFlag.getFlagName().equals("DustCharacterDatabank")) || (locationFlagEnum.toString().equals("HiddenModifers") && itemFlag.getFlagName().equals("HiddenModifiers")) || (locationFlagEnum.toString().equals("QuantumCoreRoom") && itemFlag.getFlagName().equals("StructureDeedBay")) || (locationFlagEnum.toString().equals("SpecializedOreHold") && itemFlag.getFlagName().equals("SpecializedAsteroidHold")) || (locationFlagEnum.toString().equals("CorporationGoalDeliveries") && itemFlag.getFlagName().equals("CorpProjectsHangar")) || (locationFlagEnum.toString().equals("MobileDepotHold") && itemFlag.getFlagName().equals("MobileDepot")) || (locationFlagEnum.toString().equals("InfrastructureHangar") && itemFlag.getFlagName().equals("ColonyResourcesHold")) ); } } @Test public void testToFlag_CharacterBlueprintsResponseLocationFlagEnum() { for (net.troja.eve.esi.model.CharacterBlueprintsResponse.LocationFlagEnum locationFlagEnum : net.troja.eve.esi.model.CharacterBlueprintsResponse.LocationFlagEnum.values()) { ItemFlag itemFlag = RawConverter.toFlag(locationFlagEnum); assertNotNull(itemFlag); assertTrue(locationFlagEnum.name() + " (" + locationFlagEnum.toString() + ") != " + itemFlag.getFlagName(), itemFlag.getFlagID() == 0 || locationFlagEnum.toString().toLowerCase().equals(itemFlag.getFlagText().toLowerCase().replace(" ", "")) || locationFlagEnum.toString().toLowerCase().equals(itemFlag.getFlagName().toLowerCase()) || (locationFlagEnum.toString().equals("CorpseBay") && itemFlag.getFlagName().equals("CrateLoot")) || (locationFlagEnum.toString().equals("Module") && itemFlag.getFlagName().equals("Skill")) || (locationFlagEnum.toString().equals("SpecializedOreHold") && itemFlag.getFlagName().equals("SpecializedAsteroidHold")) ); } } @Test public void testToFlag_CorporationBlueprintsResponseLocationFlagEnum() { for (net.troja.eve.esi.model.CorporationBlueprintsResponse.LocationFlagEnum locationFlagEnum : net.troja.eve.esi.model.CorporationBlueprintsResponse.LocationFlagEnum.values()) { ItemFlag itemFlag = RawConverter.toFlag(locationFlagEnum); assertNotNull(itemFlag); assertTrue(locationFlagEnum.name() + " (" + locationFlagEnum.toString() + ") != " + itemFlag.getFlagName(), itemFlag.getFlagID() == 0 || locationFlagEnum.toString().toLowerCase().equals(itemFlag.getFlagText().toLowerCase().replace(" ", "")) || locationFlagEnum.toString().toLowerCase().equals(itemFlag.getFlagName().toLowerCase()) || (locationFlagEnum.toString().equals("CorpDeliveries") && itemFlag.getFlagName().equals("CorpMarket")) || (locationFlagEnum.toString().equals("Impounded") && itemFlag.getFlagName().equals("OfficeImpound")) || (locationFlagEnum.toString().equals("ServiceSlot0") && itemFlag.getFlagName().equals("StructureServiceSlot0")) || (locationFlagEnum.toString().equals("ServiceSlot1") && itemFlag.getFlagName().equals("StructureServiceSlot1")) || (locationFlagEnum.toString().equals("ServiceSlot2") && itemFlag.getFlagName().equals("StructureServiceSlot2")) || (locationFlagEnum.toString().equals("ServiceSlot3") && itemFlag.getFlagName().equals("StructureServiceSlot3")) || (locationFlagEnum.toString().equals("ServiceSlot4") && itemFlag.getFlagName().equals("StructureServiceSlot4")) || (locationFlagEnum.toString().equals("ServiceSlot5") && itemFlag.getFlagName().equals("StructureServiceSlot5")) || (locationFlagEnum.toString().equals("ServiceSlot6") && itemFlag.getFlagName().equals("StructureServiceSlot6")) || (locationFlagEnum.toString().equals("ServiceSlot7") && itemFlag.getFlagName().equals("StructureServiceSlot7")) || (locationFlagEnum.toString().equals("DustBattle") && itemFlag.getFlagName().equals("DustCharacterBattle")) || (locationFlagEnum.toString().equals("DustDatabank") && itemFlag.getFlagName().equals("DustCharacterDatabank")) || (locationFlagEnum.toString().equals("HiddenModifers") && itemFlag.getFlagName().equals("HiddenModifiers")) || (locationFlagEnum.toString().equals("CorporationGoalDeliveries") && itemFlag.getFlagName().equals("CorpProjectsHangar")) || (locationFlagEnum.toString().equals("QuantumCoreRoom") && itemFlag.getFlagName().equals("StructureDeedBay")) || (locationFlagEnum.toString().equals("SpecializedOreHold") && itemFlag.getFlagName().equals("SpecializedAsteroidHold")) || (locationFlagEnum.toString().equals("MobileDepotHold") && itemFlag.getFlagName().equals("MobileDepot")) || (locationFlagEnum.toString().equals("InfrastructureHangar") && itemFlag.getFlagName().equals("ColonyResourcesHold")) ); } } @Test public void testToContractAvailability_String_String() { //Enum for (RawContract.ContractAvailability value : RawContract.ContractAvailability.values()) { assertEquals(value, RawConverter.toContractAvailability(value.name(), null)); } //String for (RawContract.ContractAvailability value : RawContract.ContractAvailability.values()) { assertEquals(value, RawConverter.toContractAvailability(null, value.getValue())); } //EveAPI Map map = new HashMap<>(); map.put("public", RawContract.ContractAvailability.PUBLIC); map.put("private", RawContract.ContractAvailability.PERSONAL); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), RawConverter.toContractAvailability(entry.getKey(), null)); } } @Test public void testToContractAvailability_CharacterContractsResponseAvailabilityEnum() { //Enum for (CharacterContractsResponse.AvailabilityEnum value : CharacterContractsResponse.AvailabilityEnum.values()) { assertEquals(value.name(), RawConverter.toContractAvailability(value).name()); } } @Test public void testToContractAvailability_CorporationContractsResponseAvailabilityEnum() { //Enum for (CorporationContractsResponse.AvailabilityEnum value : CorporationContractsResponse.AvailabilityEnum.values()) { assertEquals(value.name(), RawConverter.toContractAvailability(value).name()); } } @Test public void testToContractStatus_String_String() { //Enum for (RawContract.ContractStatus value : RawContract.ContractStatus.values()) { assertEquals(value, RawConverter.toContractStatus(value.name(), null)); } //String for (RawContract.ContractStatus value : RawContract.ContractStatus.values()) { assertEquals(value, RawConverter.toContractStatus(null, value.getValue())); } //EveAPI Map map = new HashMap<>(); map.put("COMPLETED", RawContract.ContractStatus.FINISHED); map.put("COMPLETEDBYCONTRACTOR", RawContract.ContractStatus.FINISHED_CONTRACTOR); map.put("COMPLETEDBYISSUER", RawContract.ContractStatus.FINISHED_ISSUER); map.put("INPROGRESS", RawContract.ContractStatus.IN_PROGRESS); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), RawConverter.toContractStatus(entry.getKey(), null)); } } @Test public void testToContractStatus_CharacterContractsResponseStatusEnum() { //Enum for (CharacterContractsResponse.StatusEnum value : CharacterContractsResponse.StatusEnum.values()) { assertEquals(value.name(), RawConverter.toContractStatus(value).name()); } } @Test public void testToContractStatus_CorporationContractsResponseStatusEnum() { //Enum for (CorporationContractsResponse.StatusEnum value : CorporationContractsResponse.StatusEnum.values()) { assertEquals(value.name(), RawConverter.toContractStatus(value).name()); } } @Test public void testToContractType_String_String() { //Enum for (RawContract.ContractType value : RawContract.ContractType.values()) { assertEquals(value, RawConverter.toContractType(value.name(), null)); } //String for (RawContract.ContractType value : RawContract.ContractType.values()) { assertEquals(value, RawConverter.toContractType(null, value.getValue())); } //EveAPI Map map = new HashMap<>(); map.put("Auction", RawContract.ContractType.AUCTION); map.put("Courier", RawContract.ContractType.COURIER); map.put("ItemExchange", RawContract.ContractType.ITEM_EXCHANGE); map.put("Loan", RawContract.ContractType.LOAN); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), RawConverter.toContractType(entry.getKey(), null)); } } @Test public void testToContractType_CharacterContractsResponseTypeEnum() { //Enum for (CharacterContractsResponse.TypeEnum value : CharacterContractsResponse.TypeEnum.values()) { assertEquals(value.name(), RawConverter.toContractType(value).name()); } } @Test public void testToContractType_CorporationContractsResponseTypeEnum() { //Enum for (CorporationContractsResponse.TypeEnum value : CorporationContractsResponse.TypeEnum.values()) { assertEquals(value.name(), RawConverter.toContractType(value).name()); } } @Test public void testToIndustryJobStatus_3args() { //Enum for (RawIndustryJob.IndustryJobStatus value : RawIndustryJob.IndustryJobStatus.values()) { assertEquals(value, RawConverter.toIndustryJobStatus(null, value.name(), null)); } //String for (RawIndustryJob.IndustryJobStatus value : RawIndustryJob.IndustryJobStatus.values()) { assertEquals(value, RawConverter.toIndustryJobStatus(null, null, value.getValue())); } //EveAPI Map map = new HashMap<>(); map.put(1, RawIndustryJob.IndustryJobStatus.ACTIVE); map.put(2, RawIndustryJob.IndustryJobStatus.PAUSED); map.put(3, RawIndustryJob.IndustryJobStatus.READY); map.put(101, RawIndustryJob.IndustryJobStatus.DELIVERED); map.put(102, RawIndustryJob.IndustryJobStatus.CANCELLED); map.put(103, RawIndustryJob.IndustryJobStatus.REVERTED); map.put(-100, RawIndustryJob.IndustryJobStatus.ARCHIVED); assertEquals(map.size(), RawIndustryJob.IndustryJobStatus.values().length); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), RawConverter.toIndustryJobStatus(entry.getKey(), null, null)); } } @Test public void testToIndustryJobStatus_CharacterIndustryJobsResponseStatusEnum() { //Enum for (CharacterIndustryJobsResponse.StatusEnum value : CharacterIndustryJobsResponse.StatusEnum.values()) { assertEquals(value.name(), RawConverter.toIndustryJobStatus(value).name()); } } @Test public void testToIndustryJobStatus_CorporationIndustryJobsResponseStatusEnum() { //Enum for (CorporationIndustryJobsResponse.StatusEnum value : CorporationIndustryJobsResponse.StatusEnum.values()) { assertEquals(value.name(), RawConverter.toIndustryJobStatus(value).name()); } } @Test public void testToJournalRefType_Integer_String() { for (RawJournalRefType refType : RawJournalRefType.values()) { RawJournalRefType type = RawConverter.toJournalRefType(refType.getID(), null); assertEquals(type.name(), refType.name()); } for (CharacterWalletJournalResponse.RefTypeEnum refType : CharacterWalletJournalResponse.RefTypeEnum.values()) { RawJournalRefType type = RawConverter.toJournalRefType(null, refType.toString()); if (type == RawJournalRefType.KILL_RIGHT && refType == CharacterWalletJournalResponse.RefTypeEnum.KILL_RIGHT_FEE) { continue; } if (type == RawJournalRefType.RESOURCE_WARS_SITE_COMPLETION && refType == CharacterWalletJournalResponse.RefTypeEnum.RESOURCE_WARS_REWARD) { continue; } if (type == RawJournalRefType.REACTIONS && refType == CharacterWalletJournalResponse.RefTypeEnum.REACTION) { continue; } assertEquals(type.name(), refType.name()); } for (CorporationWalletJournalResponse.RefTypeEnum refType : CorporationWalletJournalResponse.RefTypeEnum.values()) { RawJournalRefType type = RawConverter.toJournalRefType(null, refType.toString()); if (type == RawJournalRefType.KILL_RIGHT && refType == CorporationWalletJournalResponse.RefTypeEnum.KILL_RIGHT_FEE) { continue; } if (type == RawJournalRefType.RESOURCE_WARS_SITE_COMPLETION && refType == CorporationWalletJournalResponse.RefTypeEnum.RESOURCE_WARS_REWARD) { continue; } if (type == RawJournalRefType.REACTIONS && refType == CorporationWalletJournalResponse.RefTypeEnum.REACTION) { continue; } assertEquals(type.name(), refType.name()); } } @Test public void testToJournalRefType_CharacterWalletJournalResponseRefTypeEnum() { assertEquals(155, CharacterWalletJournalResponse.RefTypeEnum.values().length); int undefined = 0; for (CharacterWalletJournalResponse.RefTypeEnum refType : CharacterWalletJournalResponse.RefTypeEnum.values()) { RawJournalRefType rawJournalRefType = RawConverter.toJournalRefType(refType); assertNotNull("No value for: " + refType.name(), rawJournalRefType); if (rawJournalRefType == RawJournalRefType.UNDEFINED) { undefined++; } } assertEquals(0, undefined); } @Test public void testToJournalRefType_CorporationWalletJournalResponseRefTypeEnum() { assertEquals(155, CorporationWalletJournalResponse.RefTypeEnum.values().length); int undefined = 0; for (CorporationWalletJournalResponse.RefTypeEnum refType : CorporationWalletJournalResponse.RefTypeEnum.values()) { RawJournalRefType rawJournalRefType = RawConverter.toJournalRefType(refType); assertNotNull("No value for: " + refType.name(), rawJournalRefType); if (rawJournalRefType == RawJournalRefType.UNDEFINED) { undefined++; } } assertEquals(0, undefined); } @Test public void testToJournalContextType_CharacterWalletJournalResponseContextIdTypeEnum() { Map map = new EnumMap<>(CharacterWalletJournalResponse.ContextIdTypeEnum.class); map.put(CharacterWalletJournalResponse.ContextIdTypeEnum.ALLIANCE_ID, ContextType.ALLIANCE_ID); map.put(CharacterWalletJournalResponse.ContextIdTypeEnum.CHARACTER_ID, ContextType.CHARACTER_ID); map.put(CharacterWalletJournalResponse.ContextIdTypeEnum.CONTRACT_ID, ContextType.CONTRACT_ID); map.put(CharacterWalletJournalResponse.ContextIdTypeEnum.CORPORATION_ID, ContextType.CORPORATION_ID); map.put(CharacterWalletJournalResponse.ContextIdTypeEnum.EVE_SYSTEM, ContextType.EVE_SYSTEM); map.put(CharacterWalletJournalResponse.ContextIdTypeEnum.INDUSTRY_JOB_ID, ContextType.INDUSTRY_JOB_ID); map.put(CharacterWalletJournalResponse.ContextIdTypeEnum.MARKET_TRANSACTION_ID, ContextType.MARKET_TRANSACTION_ID); map.put(CharacterWalletJournalResponse.ContextIdTypeEnum.PLANET_ID, ContextType.PLANET_ID); map.put(CharacterWalletJournalResponse.ContextIdTypeEnum.STATION_ID, ContextType.STATION_ID); map.put(CharacterWalletJournalResponse.ContextIdTypeEnum.STRUCTURE_ID, ContextType.STRUCTURE_ID); map.put(CharacterWalletJournalResponse.ContextIdTypeEnum.SYSTEM_ID, ContextType.SYSTEM_ID); map.put(CharacterWalletJournalResponse.ContextIdTypeEnum.TYPE_ID, ContextType.TYPE_ID); assertEquals(map.size(), CharacterWalletJournalResponse.ContextIdTypeEnum.values().length); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), RawConverter.toJournalContextType(entry.getKey())); } } @Test public void testToJournalContextType_CorporationWalletJournalResponseContextIdTypeEnum() { Map map = new EnumMap<>(CorporationWalletJournalResponse.ContextIdTypeEnum.class); map.put(CorporationWalletJournalResponse.ContextIdTypeEnum.ALLIANCE_ID, ContextType.ALLIANCE_ID); map.put(CorporationWalletJournalResponse.ContextIdTypeEnum.CHARACTER_ID, ContextType.CHARACTER_ID); map.put(CorporationWalletJournalResponse.ContextIdTypeEnum.CONTRACT_ID, ContextType.CONTRACT_ID); map.put(CorporationWalletJournalResponse.ContextIdTypeEnum.CORPORATION_ID, ContextType.CORPORATION_ID); map.put(CorporationWalletJournalResponse.ContextIdTypeEnum.EVE_SYSTEM, ContextType.EVE_SYSTEM); map.put(CorporationWalletJournalResponse.ContextIdTypeEnum.INDUSTRY_JOB_ID, ContextType.INDUSTRY_JOB_ID); map.put(CorporationWalletJournalResponse.ContextIdTypeEnum.MARKET_TRANSACTION_ID, ContextType.MARKET_TRANSACTION_ID); map.put(CorporationWalletJournalResponse.ContextIdTypeEnum.PLANET_ID, ContextType.PLANET_ID); map.put(CorporationWalletJournalResponse.ContextIdTypeEnum.STATION_ID, ContextType.STATION_ID); map.put(CorporationWalletJournalResponse.ContextIdTypeEnum.STRUCTURE_ID, ContextType.STRUCTURE_ID); map.put(CorporationWalletJournalResponse.ContextIdTypeEnum.SYSTEM_ID, ContextType.SYSTEM_ID); map.put(CorporationWalletJournalResponse.ContextIdTypeEnum.TYPE_ID, ContextType.TYPE_ID); assertEquals(map.size(), CorporationWalletJournalResponse.ContextIdTypeEnum.values().length); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), RawConverter.toJournalContextType(entry.getKey())); } } @Test public void testToJournalContextType_String_String() { //Enum for (ContextType value : ContextType.values()) { assertEquals(value, RawConverter.toJournalContextType(value.name(), null)); } //String for (ContextType value : ContextType.values()) { assertEquals(value, RawConverter.toJournalContextType(null, value.getValue())); } } @Test public void testToJournalContextType_RawJournalRefType() { Map map = new EnumMap<>(RawJournalRefType.class); map.put(RawJournalRefType.ALLIANCE_MAINTAINANCE_FEE, ContextType.ALLIANCE_ID); map.put(RawJournalRefType.MISSION_REWARD, ContextType.CHARACTER_ID); map.put(RawJournalRefType.CONTRACT_AUCTION_BID, ContextType.CONTRACT_ID); map.put(RawJournalRefType.CORPORATION_LOGO_CHANGE_COST, ContextType.CORPORATION_ID); //map.put(RawJournalRefType., ContextType.EVE_SYSTEM); map.put(RawJournalRefType.MANUFACTURING, ContextType.INDUSTRY_JOB_ID); map.put(RawJournalRefType.MARKET_TRANSACTION, ContextType.MARKET_TRANSACTION_ID); map.put(RawJournalRefType.PLANETARY_IMPORT_TAX, ContextType.PLANET_ID); map.put(RawJournalRefType.INDUSTRY_JOB_TAX, ContextType.STATION_ID); //map.put(RawJournalRefType., ContextType.STRUCTURE_ID); map.put(RawJournalRefType.BOUNTY_PRIZES, ContextType.SYSTEM_ID); map.put(RawJournalRefType.BOUNTY_PRIZE, ContextType.TYPE_ID); assertEquals(map.size(), ContextType.values().length - 2); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), RawConverter.toJournalContextType(entry.getKey())); } } @Test public void testToJournalContextID_3args() { Map map = new EnumMap<>(RawJournalRefType.class); map.put(RawJournalRefType.ALLIANCE_MAINTAINANCE_FEE, 1L); map.put(RawJournalRefType.MISSION_REWARD, 1L); map.put(RawJournalRefType.CONTRACT_AUCTION_BID, 1L); map.put(RawJournalRefType.CORPORATION_LOGO_CHANGE_COST, 1L); //map.put(RawJournalRefType., ContextType.EVE_SYSTEM); map.put(RawJournalRefType.MANUFACTURING, 1L); map.put(RawJournalRefType.MARKET_TRANSACTION, 1L); map.put(RawJournalRefType.PLANETARY_IMPORT_TAX, 1L); map.put(RawJournalRefType.INDUSTRY_JOB_TAX, 1L); //map.put(RawJournalRefType., ContextType.STRUCTURE_ID); map.put(RawJournalRefType.BOUNTY_PRIZES, 1L); map.put(RawJournalRefType.BOUNTY_PRIZE, 1L); assertEquals(map.size(), ContextType.values().length - 2); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), RawConverter.toJournalContextID(1L, "1", entry.getKey())); } } @Test public void testToMarketOrderRange_3args() { //Enum for (RawMarketOrder.MarketOrderRange value : RawMarketOrder.MarketOrderRange.values()) { assertEquals(value, RawConverter.toMarketOrderRange(null, value.name(), null)); } //String for (RawMarketOrder.MarketOrderRange value : RawMarketOrder.MarketOrderRange.values()) { assertEquals(value, RawConverter.toMarketOrderRange(null, null, value.getValue())); } Map map = new HashMap<>(); map.put(-1, RawMarketOrder.MarketOrderRange.STATION); map.put(0, RawMarketOrder.MarketOrderRange.SOLARSYSTEM); map.put(1, RawMarketOrder.MarketOrderRange._1); map.put(2, RawMarketOrder.MarketOrderRange._2); map.put(3, RawMarketOrder.MarketOrderRange._3); map.put(4, RawMarketOrder.MarketOrderRange._4); map.put(5, RawMarketOrder.MarketOrderRange._5); map.put(10, RawMarketOrder.MarketOrderRange._10); map.put(20, RawMarketOrder.MarketOrderRange._20); map.put(30, RawMarketOrder.MarketOrderRange._30); map.put(40, RawMarketOrder.MarketOrderRange._40); map.put(32767, RawMarketOrder.MarketOrderRange.REGION); assertEquals(map.size(), RawMarketOrder.MarketOrderRange.values().length); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), RawConverter.toMarketOrderRange(entry.getKey(), null, null)); } } @Test public void testToMarketOrderRange_CharacterOrdersResponseRangeEnum() { //Enum for (CharacterOrdersResponse.RangeEnum value : CharacterOrdersResponse.RangeEnum.values()) { assertEquals(value.name(), RawConverter.toMarketOrderRange(value).name()); } } @Test public void testToMarketOrderRange_CharacterOrdersHistoryResponseRangeEnum() { //Enum for (CharacterOrdersHistoryResponse.RangeEnum value : CharacterOrdersHistoryResponse.RangeEnum.values()) { assertEquals(value.name(), RawConverter.toMarketOrderRange(value).name()); } } @Test public void testToMarketOrderRange_CorporationOrdersResponseRangeEnum() { //Enum for (CorporationOrdersResponse.RangeEnum value : CorporationOrdersResponse.RangeEnum.values()) { assertEquals(value.name(), RawConverter.toMarketOrderRange(value).name()); } } @Test public void testToMarketOrderRange_CorporationOrdersHistoryResponseRangeEnum() { //Enum for (CorporationOrdersHistoryResponse.RangeEnum value : CorporationOrdersHistoryResponse.RangeEnum.values()) { assertEquals(value.name(), RawConverter.toMarketOrderRange(value).name()); } } @Test public void testToMarketOrderRange_MarketRegionOrdersResponseRangeEnum() { //Enum for (MarketRegionOrdersResponse.RangeEnum value : MarketRegionOrdersResponse.RangeEnum.values()) { assertEquals(value.name(), RawConverter.toMarketOrderRange(value).name()); } } @Test public void testToMarketOrderRange_MarketStructuresResponseRangeEnum() { //Enum for (MarketStructureResponse.RangeEnum value : MarketStructureResponse.RangeEnum.values()) { assertEquals(value.name(), RawConverter.toMarketOrderRange(value).name()); } } @Test public void testToMarketOrderState_3args() { //Enum for (RawMarketOrder.MarketOrderState value : RawMarketOrder.MarketOrderState.values()) { assertEquals(value, RawConverter.toMarketOrderState(null, value.name(), null)); } //String for (RawMarketOrder.MarketOrderState value : RawMarketOrder.MarketOrderState.values()) { assertEquals(value, RawConverter.toMarketOrderState(null, null, value.getValue())); } Map map = new HashMap<>(); map.put(0, RawMarketOrder.MarketOrderState.OPEN); map.put(1, RawMarketOrder.MarketOrderState.CLOSED); map.put(2, RawMarketOrder.MarketOrderState.EXPIRED); map.put(3, RawMarketOrder.MarketOrderState.CANCELLED); map.put(4, RawMarketOrder.MarketOrderState.PENDING); map.put(5, RawMarketOrder.MarketOrderState.CHARACTER_DELETED); map.put(-100, RawMarketOrder.MarketOrderState.UNKNOWN); assertEquals(map.size(), RawMarketOrder.MarketOrderState.values().length); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), RawConverter.toMarketOrderState(entry.getKey(), null, null)); } } @Test public void testToMarketOrderState_CharacterOrdersHistoryResponseStateEnum() { //Enum for (CharacterOrdersHistoryResponse.StateEnum value : CharacterOrdersHistoryResponse.StateEnum.values()) { assertEquals(value.name(), RawConverter.toMarketOrderState(value).name()); } } @Test public void testToMarketOrderState_CorporationOrdersHistoryResponseStateEnum() { //Enum for (CorporationOrdersHistoryResponse.StateEnum value : CorporationOrdersHistoryResponse.StateEnum.values()) { assertEquals(value.name(), RawConverter.toMarketOrderState(value).name()); } } @Test public void testFromMarketOrderIsBuyOrder() { Map map = new HashMap<>(); map.put(true, 1); map.put(false, 0); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), (Integer) RawConverter.fromMarketOrderIsBuyOrder(entry.getKey())); } } @Test public void testToTransactionIsBuy() { Map map = new HashMap<>(); map.put("buy", true); map.put("sell", false); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), RawConverter.toTransactionIsBuy(entry.getKey())); } } @Test public void testToTransactionIsPersonal() { Map map = new HashMap<>(); map.put("personal", true); map.put("corporate", false); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), RawConverter.toTransactionIsPersonal(entry.getKey())); } } @Test public void testFromTransactionIsBuy() { Map map = new HashMap<>(); map.put(true, "buy"); map.put(false, "sell"); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), RawConverter.fromTransactionIsBuy(entry.getKey())); } } @Test public void testFromTransactionIsPersonal() { Map map = new HashMap<>(); map.put(true, "personal"); map.put(false, "corporate"); for (Map.Entry entry : map.entrySet()) { assertEquals(entry.getValue(), RawConverter.fromTransactionIsPersonal(entry.getKey())); } } @Test public void testToAssetQuantity() { assertEquals(1, RawConverter.toAssetQuantity(1, null)); assertEquals(10, RawConverter.toAssetQuantity(10, null)); assertEquals(10, RawConverter.toAssetQuantity(10, 0)); assertEquals(-1, RawConverter.toAssetQuantity(10, -1)); assertEquals(-2, RawConverter.toAssetQuantity(10, -2)); } @Test public void testLocationFlag() { for (LocationFlag locationFlag : LocationFlag.values()) { ItemFlag itemFlag = StaticData.get().getItemFlags().get(locationFlag.getID()); assertNotNull(locationFlag); assertTrue(locationFlag.name() + " != " + itemFlag.getFlagName(), itemFlag.getFlagID() == 0 || locationFlag.toString().toLowerCase().equals(itemFlag.getFlagText().toLowerCase().replace(" ", "")) || locationFlag.toString().toLowerCase().equals(itemFlag.getFlagName().toLowerCase())); } } @Test public void testToLong_Number() { assertEquals(RawConverter.toLong(1L), (Long) 1L); assertEquals(RawConverter.toLong(0), (Long) 0L); assertEquals(RawConverter.toLong(0.0), (Long) 0L); assertEquals(RawConverter.toLong(0.0f), (Long) 0L); assertEquals((long) RawConverter.toLong(Long.MAX_VALUE), Long.MAX_VALUE); assertEquals((long) RawConverter.toLong(Long.MIN_VALUE), Long.MIN_VALUE); assertEquals((long) RawConverter.toLong(Integer.MAX_VALUE), (long) Integer.MAX_VALUE); assertEquals((long) RawConverter.toLong(Integer.MIN_VALUE), (long) Integer.MIN_VALUE); assertEquals((long) RawConverter.toLong(Double.MAX_VALUE), (long) Double.MAX_VALUE); assertEquals((long) RawConverter.toLong(Double.MIN_VALUE), (long) Double.MIN_VALUE); assertEquals((long) RawConverter.toLong(Float.MAX_VALUE), (long) Float.MAX_VALUE); assertEquals((long) RawConverter.toLong(Float.MIN_VALUE), (long) Float.MIN_VALUE); } @Test public void testToLong_String() { assertEquals(RawConverter.toLong(String.valueOf(1L)), (Long) 1L); assertEquals(RawConverter.toLong(String.valueOf(0)), (Long) 0L); assertEquals((long) RawConverter.toLong(String.valueOf(Long.MAX_VALUE)), Long.MAX_VALUE); assertEquals((long) RawConverter.toLong(String.valueOf(Long.MIN_VALUE)), Long.MIN_VALUE); assertEquals((long) RawConverter.toLong(String.valueOf(Integer.MAX_VALUE)), (long) Integer.MAX_VALUE); assertEquals((long) RawConverter.toLong(String.valueOf(Integer.MIN_VALUE)), (long) Integer.MIN_VALUE); assertEquals(RawConverter.toLong((String)null), null); } @Test public void testToInteger_Number() { assertEquals((int) RawConverter.toInteger(1L), 1); assertEquals((int) RawConverter.toInteger(0), 0); assertEquals((int) RawConverter.toInteger(0.0), 0); assertEquals((int) RawConverter.toInteger(0.0f), 0); assertEquals((int) RawConverter.toInteger(Long.MAX_VALUE), (int) Long.MAX_VALUE); assertEquals((int) RawConverter.toInteger(Long.MIN_VALUE), (int) Long.MIN_VALUE); assertEquals((int) RawConverter.toInteger(Integer.MAX_VALUE), Integer.MAX_VALUE); assertEquals((int) RawConverter.toInteger(Integer.MIN_VALUE), Integer.MIN_VALUE); assertEquals((int) RawConverter.toInteger(Double.MAX_VALUE), (int) Double.MAX_VALUE); assertEquals((int) RawConverter.toInteger(Double.MIN_VALUE), (int) Double.MIN_VALUE); assertEquals((int) RawConverter.toInteger(Float.MAX_VALUE), (int) Float.MAX_VALUE); assertEquals((int) RawConverter.toInteger(Float.MIN_VALUE), (int) Float.MIN_VALUE); } @Test public void testToInteger_Number_int() { assertEquals(RawConverter.toInteger(1L, 0), 1); assertEquals(RawConverter.toInteger(0, 1), 0); assertEquals(RawConverter.toInteger(0.0, 0), 0); assertEquals(RawConverter.toInteger(0.0f, 0), 0); assertEquals(RawConverter.toInteger(Long.MAX_VALUE, 0), (int) Long.MAX_VALUE); assertEquals(RawConverter.toInteger(Long.MIN_VALUE, 0), (int) Long.MIN_VALUE); assertEquals(RawConverter.toInteger(Integer.MAX_VALUE, 0), Integer.MAX_VALUE); assertEquals(RawConverter.toInteger(Integer.MIN_VALUE, 0), Integer.MIN_VALUE); assertEquals(RawConverter.toInteger(Double.MAX_VALUE, 0), (int) Double.MAX_VALUE); assertEquals(RawConverter.toInteger(Double.MIN_VALUE, 0), (int) Double.MIN_VALUE); assertEquals(RawConverter.toInteger(Float.MAX_VALUE, 0), (int) Float.MAX_VALUE); assertEquals(RawConverter.toInteger(Float.MIN_VALUE, 0), (int) Float.MIN_VALUE); assertEquals(RawConverter.toInteger(null, 0), 0); assertEquals(RawConverter.toInteger(null, 1), 1); } @Test public void testToInteger_String() { assertEquals((int) RawConverter.toInteger(String.valueOf(1L)), 1); assertEquals((int) RawConverter.toInteger(String.valueOf(0)), 0); assertEquals((int) RawConverter.toInteger(String.valueOf(Integer.MAX_VALUE)), Integer.MAX_VALUE); assertEquals((int) RawConverter.toInteger(String.valueOf(Integer.MIN_VALUE)), Integer.MIN_VALUE); assertEquals(RawConverter.toInteger((String)null), null); } @Test public void testToFloat() { float delta = 0; assertEquals(RawConverter.toFloat(Long.MAX_VALUE), Long.MAX_VALUE, delta); assertEquals(RawConverter.toFloat(Long.MIN_VALUE), Long.MIN_VALUE, delta); assertEquals(RawConverter.toFloat(Integer.MAX_VALUE), Integer.MAX_VALUE, delta); assertEquals(RawConverter.toFloat(Integer.MIN_VALUE), Integer.MIN_VALUE, delta); assertEquals((float) RawConverter.toFloat(Double.MAX_VALUE), (float) Double.MAX_VALUE, delta); assertEquals((float) RawConverter.toFloat(Double.MIN_VALUE), (float) Double.MIN_VALUE, delta); assertEquals(RawConverter.toFloat(Float.MAX_VALUE), Float.MAX_VALUE, delta); assertEquals(RawConverter.toFloat(Float.MIN_VALUE), Float.MIN_VALUE, delta); } @Test public void testToDouble() { float delta = 0; assertEquals(RawConverter.toDouble(Long.MAX_VALUE, 0), Long.MAX_VALUE, delta); assertEquals(RawConverter.toDouble(Long.MIN_VALUE, 0), Long.MIN_VALUE, delta); assertEquals(RawConverter.toDouble(Integer.MAX_VALUE, 0), Integer.MAX_VALUE, delta); assertEquals(RawConverter.toDouble(Integer.MIN_VALUE, 0), Integer.MIN_VALUE, delta); assertEquals(RawConverter.toDouble(Double.MAX_VALUE, 0), Double.MAX_VALUE, delta); assertEquals(RawConverter.toDouble(Double.MIN_VALUE, 0), Double.MIN_VALUE, delta); assertEquals(RawConverter.toDouble(Float.MAX_VALUE, 0), Float.MAX_VALUE, delta); assertEquals(RawConverter.toDouble(Float.MIN_VALUE, 0), Float.MIN_VALUE, delta); assertEquals(RawConverter.toDouble(null, 0), 0, delta); assertEquals(RawConverter.toDouble(null, 1), 1, delta); } @Test public void testToBoolean() { assertEquals(RawConverter.toBoolean(null), false); assertEquals(RawConverter.toBoolean(false), false); assertEquals(RawConverter.toBoolean(true), true); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/lib/LibTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.lib; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import net.nikr.eve.jeveasset.LibraryManager; import net.nikr.eve.jeveasset.TestUtil; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.junit.Assert; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; public class LibTest extends TestUtil { @Test public void test() { testLibs(); testPurge(); } public void testLibs() { File folder = new File("target" + File.separator + "lib"); assertTrue(folder.exists()); File[] listOfFiles = folder.listFiles(); Set files = new HashSet<>(); for (File file : listOfFiles) { files.add(file.getName()); } Set libsNames = new HashSet<>(); Set libs = LibraryManager.getLibFiles(); StringBuilder missingLibraries = new StringBuilder(); missingLibraries.append("\r\n---Libs added---\r\n"); StringBuilder removedLibraries = new StringBuilder(); removedLibraries.append("---Libs removed---\r\n"); boolean missing = false; boolean removed = false; for (String file : files) { if (file.endsWith(".md5")) { continue; } if (!libs.contains(file)) { missing = true; missingLibraries.append(file); missingLibraries.append("\r\n"); } } for (String lib : libs) { String libName = lib.substring(0, lib.lastIndexOf("-")); assertTrue("Duplicate: " + libName, libsNames.add(libName)); if (!files.contains(lib)) { removedLibraries.append(lib); removedLibraries.append("\r\n"); } } assertFalse(missingLibraries.toString() + removedLibraries.toString(), missing || removed); } public void testPurge() { List files = new ArrayList<>(); for (int i = 0; i < 10; i++) { File file = new File(FileUtil.getPathLib(i + ".jar")); files.add(file); try { assertTrue("Failed to create file: " + file.getName(), file.createNewFile()); } catch (IOException ex) { Assert.fail("Failed to create file: " + file.getName() + " (" + ex.getMessage() + ")"); } } for (File file : files) { assertTrue("File doesn't exist: " + file.getName(), file.exists()); } LibraryManager.checkLibraries(); for (File file : files) { assertFalse("File still exist (after purge): " + file.getName(), file.exists()); } } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/tests/mocks/FakeProgram.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.tests.mocks; import java.awt.event.ActionEvent; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.accounts.OwnerType; import net.nikr.eve.jeveasset.data.api.my.MyAccountBalance; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.api.my.MyContract; import net.nikr.eve.jeveasset.data.api.my.MyContractItem; import net.nikr.eve.jeveasset.data.api.my.MyIndustryJob; import net.nikr.eve.jeveasset.data.api.my.MyJournal; import net.nikr.eve.jeveasset.data.api.my.MyMarketOrder; import net.nikr.eve.jeveasset.data.api.my.MyTransaction; import net.nikr.eve.jeveasset.data.profile.ProfileData; import net.nikr.eve.jeveasset.data.profile.ProfileManager; import net.nikr.eve.jeveasset.data.sde.MyLocation; import net.nikr.eve.jeveasset.gui.dialogs.settings.UserLocationSettingsPanel; import net.nikr.eve.jeveasset.gui.dialogs.settings.UserNameSettingsPanel; import net.nikr.eve.jeveasset.gui.dialogs.settings.UserPriceSettingsPanel; import net.nikr.eve.jeveasset.gui.frame.MainWindow; import net.nikr.eve.jeveasset.gui.frame.StatusPanel; import net.nikr.eve.jeveasset.gui.shared.components.JMainTab; import net.nikr.eve.jeveasset.gui.tabs.agents.AgentsTab; import net.nikr.eve.jeveasset.gui.tabs.assets.AssetsTab; import net.nikr.eve.jeveasset.gui.tabs.contracts.ContractsTab; import net.nikr.eve.jeveasset.gui.tabs.items.ItemsTab; import net.nikr.eve.jeveasset.gui.tabs.jobs.IndustryJobsTab; import net.nikr.eve.jeveasset.gui.tabs.journal.JournalTab; import net.nikr.eve.jeveasset.gui.tabs.loadout.LoadoutsTab; import net.nikr.eve.jeveasset.gui.tabs.loyalty.LoyaltyPointsTab; import net.nikr.eve.jeveasset.gui.tabs.materials.MaterialsTab; import net.nikr.eve.jeveasset.gui.tabs.mining.ExtractionsTab; import net.nikr.eve.jeveasset.gui.tabs.mining.MiningGraphTab; import net.nikr.eve.jeveasset.gui.tabs.mining.MiningTab; import net.nikr.eve.jeveasset.gui.tabs.orders.MarketOrdersTab; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewTab; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceChangesTab; import net.nikr.eve.jeveasset.gui.tabs.prices.PriceHistoryTab; import net.nikr.eve.jeveasset.gui.tabs.reprocessed.ReprocessedTab; import net.nikr.eve.jeveasset.gui.tabs.routing.RoutingTab; import net.nikr.eve.jeveasset.gui.tabs.skills.SkillsTab; import net.nikr.eve.jeveasset.gui.tabs.skills.SkillsOverviewTab; import net.nikr.eve.jeveasset.gui.tabs.slots.SlotsTab; import net.nikr.eve.jeveasset.gui.tabs.standing.NpcStandingTab; import net.nikr.eve.jeveasset.gui.tabs.stockpile.StockpileTab; import net.nikr.eve.jeveasset.gui.tabs.tracker.TrackerTab; import net.nikr.eve.jeveasset.gui.tabs.transaction.TransactionTab; import net.nikr.eve.jeveasset.gui.tabs.tree.TreeTab; import net.nikr.eve.jeveasset.gui.tabs.values.ValueRetroTab; import net.nikr.eve.jeveasset.gui.tabs.values.ValueTableTab; import net.nikr.eve.jeveasset.io.local.profile.ProfileDatabase.Table; import net.nikr.eve.jeveasset.io.online.PriceDataGetter; /** * any method called will throw an exception. extend and override only the ones that are needed to perform the tests. * @author Candle */ public abstract class FakeProgram extends Program { public FakeProgram() { super(false); } @Override public AssetsTab getAssetsTab() { throw new UnsupportedOperationException("Not implemented"); } @Override public SlotsTab getSlotsTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public void actionPerformed(final ActionEvent e) { throw new UnsupportedOperationException("Not implemented"); } @Override public void exit() { throw new UnsupportedOperationException("Not implemented"); } @Override public MainWindow getMainWindow() { throw new UnsupportedOperationException("Not implemented"); } @Override public String getProgramDataVersion() { throw new UnsupportedOperationException("Not implemented"); } @Override public StatusPanel getStatusPanel() { throw new UnsupportedOperationException("Not implemented"); } @Override public void saveSettingsAndProfile() { throw new UnsupportedOperationException("Not implemented"); } @Override public StockpileTab getStockpileTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public UserNameSettingsPanel getUserNameSettingsPanel() { throw new UnsupportedOperationException("Not implemented"); } @Override public UserPriceSettingsPanel getUserPriceSettingsPanel() { throw new UnsupportedOperationException("Not implemented"); } @Override public void overviewGroupsChanged() { throw new UnsupportedOperationException("Not implemented"); } @Override public void tabChanged() { throw new UnsupportedOperationException("Not implemented"); } @Override public void updateTableMenu() { throw new UnsupportedOperationException("Not implemented"); } @Override public OverviewTab getOverviewTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public void createTrackerDataPoint() { throw new UnsupportedOperationException("Not implemented"); } @Override public ReprocessedTab getReprocessedTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public List getIndustryJobsList() { throw new UnsupportedOperationException("Not implemented"); } @Override public List getMarketOrdersList() { throw new UnsupportedOperationException("Not implemented"); } @Override public List getOwnerNames(boolean all) { throw new UnsupportedOperationException("Not implemented"); } @Override public ProfileManager getProfileManager() { throw new UnsupportedOperationException("Not implemented"); } @Override public PriceDataGetter getPriceDataGetter() { throw new UnsupportedOperationException("Not implemented"); } @Override public List getAccountBalanceList() { throw new UnsupportedOperationException("Not implemented"); } @Override public List getTransactionsList() { throw new UnsupportedOperationException("Not implemented"); } @Override public RoutingTab getRoutingTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public void updateTags() { throw new UnsupportedOperationException("Not implemented"); } @Override public void saveSettings(String msg) { throw new UnsupportedOperationException("Not implemented"); } @Override public void saveProfile() { throw new UnsupportedOperationException("Not implemented"); } @Override public List getContractList() { throw new UnsupportedOperationException("Not implemented"); } @Override public List getAssetsList() { throw new UnsupportedOperationException("Not implemented"); } @Override public ProfileData getProfileData() { throw new UnsupportedOperationException("Not implemented"); } @Override public TreeTab getTreeTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public List getContractItemList() { throw new UnsupportedOperationException("Not implemented"); } @Override public Map getOwners() { throw new UnsupportedOperationException("Not implemented"); } @Override public List getOwnerTypes() { throw new UnsupportedOperationException("Not implemented"); } @Override public List getJournalList() { throw new UnsupportedOperationException("Not implemented"); } @Override public UserLocationSettingsPanel getUserLocationSettingsPanel() { throw new UnsupportedOperationException("Not implemented"); } @Override public void updateStructures(Set locations, boolean minimizable) { throw new UnsupportedOperationException("Not implemented"); } @Override public boolean checkDataUpdate() { throw new UnsupportedOperationException("Not implemented"); } @Override public boolean checkProgramUpdate() { throw new UnsupportedOperationException("Not implemented"); } @Override public TransactionTab getTransactionsTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public ValueTableTab getIskTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public TrackerTab getTrackerTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public Map getMainTabs() { throw new UnsupportedOperationException("Not implemented"); } @Override public void addMainTab(String toolName, JMainTab jMainTab) { throw new UnsupportedOperationException("Not implemented"); } @Override public LoadoutsTab getLoadoutsTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public MarketOrdersTab getMarketOrdersTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public void repaintTables() { throw new UnsupportedOperationException("Not implemented"); } @Override public PriceHistoryTab getPriceHistoryTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public IndustryJobsTab getIndustryJobsTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public ContractsTab getContractsTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public SkillsTab getSkillsTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public ItemsTab getItemsTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public JournalTab getJournalTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public PriceChangesTab getPriceChangesTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public MaterialsTab getMaterialsTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public ExtractionsTab getExtractionsTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public MiningGraphTab getMiningGraphTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public MiningTab getMiningTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public ValueRetroTab getValueTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public Map getInitTabs() { throw new UnsupportedOperationException("Not implemented"); } @Override public synchronized void saveTable(Table table) { throw new UnsupportedOperationException("Not implemented"); } @Override public void showJumpsSettingsPanel() { throw new UnsupportedOperationException("Not implemented"); } @Override public AgentsTab getAgentsTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public NpcStandingTab getNpcStandingTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public LoyaltyPointsTab getLoyaltyPointsTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } @Override public SkillsOverviewTab getSkillsOverviewTab(boolean init) { throw new UnsupportedOperationException("Not implemented"); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/tests/mocks/FakeProgress.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.tests.mocks; import uk.me.candle.eve.routing.Progress; /** * * @author Candle */ public class FakeProgress implements Progress { private int value; private int min; private int max; @Override public int getMaximum() { return max; } @Override public void setMaximum(final int max) { this.max = max; } @Override public int getMinimum() { return min; } @Override public void setMinimum(final int min) { this.min = min; } @Override public int getValue() { return value; } @Override public void setValue(final int value) { this.value = value; } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/tests/mocks/FakeSettings.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.tests.mocks; import java.awt.Dimension; import java.awt.Point; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import net.nikr.eve.jeveasset.data.api.raw.RawMarketOrder.MarketOrderRange; import net.nikr.eve.jeveasset.data.settings.ColorSettings; import net.nikr.eve.jeveasset.data.settings.CopySettings; import net.nikr.eve.jeveasset.data.settings.ExportSettings; import net.nikr.eve.jeveasset.data.settings.ManufacturingSettings; import net.nikr.eve.jeveasset.data.settings.MarketOrdersSettings; import net.nikr.eve.jeveasset.data.settings.PriceData; import net.nikr.eve.jeveasset.data.settings.PriceDataSettings; import net.nikr.eve.jeveasset.data.settings.ProxyData; import net.nikr.eve.jeveasset.data.settings.ReprocessSettings; import net.nikr.eve.jeveasset.data.settings.RouteAvoidSettings; import net.nikr.eve.jeveasset.data.settings.RoutingSettings; import net.nikr.eve.jeveasset.data.settings.Settings; import net.nikr.eve.jeveasset.data.settings.StockpileGroupSettings; import net.nikr.eve.jeveasset.data.settings.TrackerSettings; import net.nikr.eve.jeveasset.data.settings.UserItem; import net.nikr.eve.jeveasset.data.settings.tag.Tag; import net.nikr.eve.jeveasset.data.settings.tag.TagID; import net.nikr.eve.jeveasset.data.settings.tag.Tags; import net.nikr.eve.jeveasset.gui.dialogs.settings.SoundsSettingsPanel.SoundOption; import net.nikr.eve.jeveasset.gui.shared.filter.Filter; import net.nikr.eve.jeveasset.gui.shared.menu.JFormulaDialog; import net.nikr.eve.jeveasset.gui.shared.menu.JMenuJumps; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.ResizeMode; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor.SimpleColumn; import net.nikr.eve.jeveasset.gui.shared.table.View; import net.nikr.eve.jeveasset.gui.sounds.Sound; import net.nikr.eve.jeveasset.gui.tabs.orders.Outbid; import net.nikr.eve.jeveasset.gui.tabs.overview.OverviewGroup; import net.nikr.eve.jeveasset.gui.tabs.stockpile.Stockpile; /** * * @author Candle */ public abstract class FakeSettings extends Settings { @Override public Map getFlags() { throw new UnsupportedOperationException("not implemented"); } @Override public PriceDataSettings getPriceDataSettings() { throw new UnsupportedOperationException("not implemented"); } @Override public ReprocessSettings getReprocessSettings() { throw new UnsupportedOperationException("not implemented"); } @Override public Map> getUserItemNames() { throw new UnsupportedOperationException("not implemented"); } @Override public Map> getUserPrices() { throw new UnsupportedOperationException("not implemented"); } @Override public Point getWindowLocation() { throw new UnsupportedOperationException("not implemented"); } @Override public Dimension getWindowSize() { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isHighlightSelectedRows() { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isReprocessColors() { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isSettingsLoadError() { throw new UnsupportedOperationException("not implemented"); } @Override public void setSettingsLoadError(boolean settingsLoadError) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isWindowAutoSave() { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isWindowMaximized() { throw new UnsupportedOperationException("not implemented"); } @Override public void setFilterOnEnter(final boolean filterOnEnter) { throw new UnsupportedOperationException("not implemented"); } @Override public void setHighlightSelectedRows(final boolean filterOnEnter) { throw new UnsupportedOperationException("not implemented"); } @Override public void setPriceData(final Map priceData) { throw new UnsupportedOperationException("not implemented"); } @Override public void setPriceDataSettings(final PriceDataSettings priceDataSettings) { throw new UnsupportedOperationException("not implemented"); } @Override public void setReprocessColors(final boolean updateDev) { throw new UnsupportedOperationException("not implemented"); } @Override public void setReprocessSettings(final ReprocessSettings reprocessSettings) { throw new UnsupportedOperationException("not implemented"); } @Override public void setUserItemNames(final Map> userItemNames) { throw new UnsupportedOperationException("not implemented"); } @Override public void setUserPrices(final Map> userPrices) { throw new UnsupportedOperationException("not implemented"); } @Override public void setWindowAutoSave(final boolean windowAutoSave) { throw new UnsupportedOperationException("not implemented"); } @Override public void setWindowLocation(final Point windowLocation) { throw new UnsupportedOperationException("not implemented"); } @Override public void setWindowMaximized(final boolean windowMaximized) { throw new UnsupportedOperationException("not implemented"); } @Override public void setWindowSize(final Dimension windowSize) { throw new UnsupportedOperationException("not implemented"); } @Override public Map getOverviewGroups() { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isIgnoreSecureContainers() { throw new UnsupportedOperationException("not implemented"); } @Override public void setIgnoreSecureContainers(final boolean ignoreSecureContainers) { throw new UnsupportedOperationException("not implemented"); } @Override public List getStockpiles() { throw new UnsupportedOperationException("not implemented"); } @Override public Map> getTableColumns() { throw new UnsupportedOperationException("not implemented"); } @Override public Map>> getTableFilters() { throw new UnsupportedOperationException("not implemented"); } @Override public Map> getTableFilters(final String key) { throw new UnsupportedOperationException("not implemented"); } @Override public Map> getCurrentTableFilters() { throw new UnsupportedOperationException("not implemented"); } @Override public List getCurrentTableFilters(final String tableName) { throw new UnsupportedOperationException("not implemented"); } @Override public Map getCurrentTableFiltersShown() { throw new UnsupportedOperationException("not implemented"); } @Override public boolean getCurrentTableFiltersShown(final String tableName) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isStockpileFocusTab() { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isStockpileHalfColors() { throw new UnsupportedOperationException("not implemented"); } @Override public void setStockpileFocusTab(final boolean stockpileFocusOnAdd) { throw new UnsupportedOperationException("not implemented"); } @Override public void setStockpileHalfColors(final boolean stockpileHalfColors) { throw new UnsupportedOperationException("not implemented"); } @Override public Map getTableResize() { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isWindowAlwaysOnTop() { throw new UnsupportedOperationException("not implemented"); } @Override public void setWindowAlwaysOnTop(final boolean windowAlwaysOnTop) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isIncludeBuyOrders() { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isIncludeSellOrders() { throw new UnsupportedOperationException("not implemented"); } @Override public void setIncludeBuyOrders(boolean includeBuyOrders) { throw new UnsupportedOperationException("not implemented"); } @Override public void setIncludeSellOrders(boolean includeSellOrders) { throw new UnsupportedOperationException("not implemented"); } @Override public Map> getTableColumnsWidth() { throw new UnsupportedOperationException("not implemented"); } @Override public int getMaximumPurchaseAge() { throw new UnsupportedOperationException("not implemented"); } @Override public void setMaximumPurchaseAge(int maximumPurchaseAge) { throw new UnsupportedOperationException("not implemented"); } @Override public Map getOwners() { throw new UnsupportedOperationException("not implemented"); } @Override public Map getPriceData() { throw new UnsupportedOperationException("not implemented"); } @Override public CopySettings getCopySettings() { throw new UnsupportedOperationException("not implemented"); } @Override public Map getExportSettings() { throw new UnsupportedOperationException("not implemented"); } @Override public ExportSettings getExportSettings(String toolName) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isFilterOnEnter() { throw new UnsupportedOperationException("not implemented"); } @Override public Map> getTableViews() { throw new UnsupportedOperationException("not implemented"); } @Override public Map getTableViews(String name) { throw new UnsupportedOperationException("not implemented"); } @Override public Map getTags() { throw new UnsupportedOperationException("not implemented"); } @Override public Tags getTags(TagID tagID) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isBlueprintBasePriceTech1() { throw new UnsupportedOperationException("not implemented"); } @Override public void setBlueprintBasePriceTech1(boolean includeBuyOrders) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isBlueprintBasePriceTech2() { throw new UnsupportedOperationException("not implemented"); } @Override public void setBlueprintBasePriceTech2(boolean includeBuyOrders) { throw new UnsupportedOperationException("not implemented"); } @Override public void setJournalHistory(boolean blueprintsTech2) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isJournalHistory() { throw new UnsupportedOperationException("not implemented"); } @Override public void setTransactionHistory(boolean transactionHistory) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isTransactionHistory() { throw new UnsupportedOperationException("not implemented"); } @Override public void setEveNames(Map eveNames) { throw new UnsupportedOperationException("not implemented"); } @Override public Map getEveNames() { throw new UnsupportedOperationException("not implemented"); } @Override public RoutingSettings getRoutingSettings() { throw new UnsupportedOperationException("not implemented"); } @Override public void setIncludeSellContracts(boolean includeBuyOrders) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isIncludeSellContracts() { throw new UnsupportedOperationException("not implemented"); } @Override public void setIncludeBuyContracts(boolean includeBuyOrders) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isIncludeBuyContracts() { throw new UnsupportedOperationException("not implemented"); } @Override public void setStockpileColorGroup3(int stockpileColorGroup2) { throw new UnsupportedOperationException("not implemented"); } @Override public int getStockpileColorGroup3() { throw new UnsupportedOperationException("not implemented"); } @Override public void setStockpileColorGroup2(int stockpileColorGroup1) { throw new UnsupportedOperationException("not implemented"); } @Override public int getStockpileColorGroup2() { throw new UnsupportedOperationException("not implemented"); } @Override public void setMarketOrderHistory(boolean blueprintsTech2) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isMarketOrderHistory() { throw new UnsupportedOperationException("not implemented"); } @Override public MarketOrdersSettings getMarketOrdersSettings() { throw new UnsupportedOperationException("not implemented"); } @Override public void setProxyData(ProxyData proxyData) { throw new UnsupportedOperationException("not implemented"); } @Override public ProxyData getProxyData() { throw new UnsupportedOperationException("not implemented"); } @Override public boolean setIncludeManufacturing(boolean includeManufacturing) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isIncludeManufacturing() { throw new UnsupportedOperationException("not implemented"); } @Override public void setAskedCheckAllTracker(boolean checkAllTracker) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isAskedCheckAllTracker() { throw new UnsupportedOperationException("not implemented"); } @Override public void setTrackerUseAssetPriceForSellOrders(boolean checkAllTracker) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isTrackerUseAssetPriceForSellOrders() { throw new UnsupportedOperationException("not implemented"); } @Override public void setPublicMarketOrdersNextUpdate(Date publicMarketOrdersNextUpdate) { throw new UnsupportedOperationException("not implemented"); } @Override public Date getPublicMarketOrdersNextUpdate() { throw new UnsupportedOperationException("not implemented"); } @Override public void setMarketOrdersOutbid(Map outbids) { throw new UnsupportedOperationException("not implemented"); } @Override public Map getMarketOrdersOutbid() { throw new UnsupportedOperationException("not implemented"); } @Override public void setOutbidOrderRange(MarketOrderRange sellOrderOutbidRange) { throw new UnsupportedOperationException("not implemented"); } @Override public MarketOrderRange getOutbidOrderRange() { throw new UnsupportedOperationException("not implemented"); } @Override public void setFocusEveOnlineOnEsiUiCalls(boolean focusEveOnlineOnEsiUiCalls) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isFocusEveOnlineOnEsiUiCalls() { throw new UnsupportedOperationException("not implemented"); } @Override public void setPublicMarketOrdersLastUpdate(Date date) { throw new UnsupportedOperationException("not implemented"); } @Override public Date getPublicMarketOrdersLastUpdate() { throw new UnsupportedOperationException("not implemented"); } @Override public List getShowTools() { throw new UnsupportedOperationException("not implemented"); } @Override public void setSaveToolsOnExit(boolean saveToolsOnExit) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isSaveToolsOnExit() { throw new UnsupportedOperationException("not implemented"); } @Override public ColorSettings getColorSettings() { throw new UnsupportedOperationException("not implemented"); } @Override public void setTransactionProfitPrice(TransactionProfitPrice transactionProfitPrice) { throw new UnsupportedOperationException("not implemented"); } @Override public TransactionProfitPrice getTransactionProfitPrice() { throw new UnsupportedOperationException("not implemented"); } @Override public void setFactionWarfareNextUpdate(Date factionWarfareNextUpdate) { throw new UnsupportedOperationException("not implemented"); } @Override public Date getFactionWarfareNextUpdate() { throw new UnsupportedOperationException("not implemented"); } @Override public void setFactionWarfareSystemOwners(Map factionWarfareSystemOwners) { throw new UnsupportedOperationException("not implemented"); } @Override public Map getFactionWarfareSystemOwners() { throw new UnsupportedOperationException("not implemented"); } @Override public Map getOwnersNextUpdate() { throw new UnsupportedOperationException("not implemented"); } @Override public void setTransactionProfitMargin(int transactionProfitMargin) { throw new UnsupportedOperationException("not implemented"); } @Override public int getTransactionProfitMargin() { throw new UnsupportedOperationException("not implemented"); } @Override public TrackerSettings getTrackerSettings() { throw new UnsupportedOperationException("not implemented"); } @Override public List getTableFormulas(String name) { throw new UnsupportedOperationException("not implemented"); } @Override public Map> getTableFormulas() { throw new UnsupportedOperationException("not implemented"); } @Override public List getTableJumps(String toolName) { throw new UnsupportedOperationException("not implemented"); } @Override public Map> getTableJumps() { throw new UnsupportedOperationException("not implemented"); } @Override public Date getTableChanged(String toolName) { throw new UnsupportedOperationException("not implemented"); } @Override public Map getTableChanged() { throw new UnsupportedOperationException("not implemented"); } @Override public void setContractHistory(boolean contractHistory) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isContractHistory() { throw new UnsupportedOperationException("not implemented"); } @Override public Map> getDefaultTableFilters(String key) { throw new UnsupportedOperationException("not implemented"); } @Override public Map> getPriceHistorySets() { throw new UnsupportedOperationException("not implemented"); } @Override public boolean setIncludeCopying(boolean includeCopying) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isIncludeCopying() { throw new UnsupportedOperationException("not implemented"); } @Override public StockpileGroupSettings getStockpileGroupSettings() { throw new UnsupportedOperationException("not implemented"); } @Override public void setMiningHistory(boolean contractHistory) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isMiningHistory() { throw new UnsupportedOperationException("not implemented"); } @Override public Map getSoundSettings() { throw new UnsupportedOperationException("not implemented"); } @Override public void setManufacturingDefault(boolean manufacturingDefault) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isManufacturingDefault() { throw new UnsupportedOperationException("not implemented"); } @Override public ManufacturingSettings getManufacturingSettings() { throw new UnsupportedOperationException("not implemented"); } @Override public void setEasyChartColors(boolean easyChartColors) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isEasyChartColors() { throw new UnsupportedOperationException("not implemented"); } @Override public void setContainersShowItemID(boolean containersShowItemID) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isContainersShowItemID() { throw new UnsupportedOperationException("not implemented"); } @Override public void setToolsLocked(boolean toolsLocked) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isToolsLocked() { throw new UnsupportedOperationException("not implemented"); } @Override public void setShowSubpileTree(boolean showSubpileTree) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isShowSubpileTree() { throw new UnsupportedOperationException("not implemented"); } @Override public void setIndustryJobsHistory(boolean journalHistory) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isIndustryJobsHistory() { throw new UnsupportedOperationException("not implemented"); } @Override public void setAssetsContractsOwnerBoth(boolean assetsContractsOwnerBoth) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isAssetsContractsOwnerBoth() { throw new UnsupportedOperationException("not implemented"); } @Override public void setAssetsContractsOwnerCorporation(boolean assetsContractsOwnerCorporation) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isAssetsContractsOwnerCorporation() { throw new UnsupportedOperationException("not implemented"); } @Override public void setCellValueCache(boolean cellValueCache) { throw new UnsupportedOperationException("not implemented"); } @Override public void setLoadToolsStartup(boolean loadToolsStartup) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isLoadToolsStartup() { throw new UnsupportedOperationException("not implemented"); } @Override public void setLoadToolsBackground(boolean loadToolsBackground) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isLoadToolsBackground() { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isColumnValueCache() { throw new UnsupportedOperationException("not implemented"); } @Override public void putImportSettings(String toolName, Enum type) { throw new UnsupportedOperationException("not implemented"); } @Override public String getImportSettings(String toolName, Enum defaultValue) { throw new UnsupportedOperationException("not implemented"); } @Override public Map getImportSettings() { throw new UnsupportedOperationException("not implemented"); } @Override public boolean setIncludePluggedInImplants(boolean includePluggedInImplants) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isIncludePluggedInImplants() { throw new UnsupportedOperationException("not implemented"); } @Override public boolean setIncludeJumpClones(boolean includeJumpClones) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isIncludeJumpClones() { throw new UnsupportedOperationException("not implemented"); } @Override public String getCurrentTableSorting(String toolName) { throw new UnsupportedOperationException("not implemented"); } @Override public Map getCurrentTableSorting() { throw new UnsupportedOperationException("not implemented"); } @Override public RouteAvoidSettings getJumpsAvoidSettings() { throw new UnsupportedOperationException("not implemented"); } @Override public Map> getSkillPlans() { throw new UnsupportedOperationException("not implemented"); } @Override public void setEveGatecampCheckUnsecure(boolean eveGatecampCheckUnsecure) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isEveGatecampCheckUnsecure() { throw new UnsupportedOperationException("not implemented"); } @Override public void setEveGatecampCheckSecure(boolean eveGatecampCheckSecure) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isEveGatecampCheckSecure() { throw new UnsupportedOperationException("not implemented"); } @Override public void setEveGatecampCheckNeverOpen(boolean eveGatecampCheckNeverOpen) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isEveGatecampCheckNeverOpen() { throw new UnsupportedOperationException("not implemented"); } @Override public void setEveGatecampCheckAlwaysOpen(boolean eveGatecampCheckAlwaysOpen) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isEveGatecampCheckAlwaysOpen() { throw new UnsupportedOperationException("not implemented"); } @Override public void setEveGatecampCheckSet(boolean eveGatecampCheckSet) { throw new UnsupportedOperationException("not implemented"); } @Override public boolean isEveGatecampCheckSet() { throw new UnsupportedOperationException("not implemented"); } } ================================================ FILE: src/test/java/net/nikr/eve/jeveasset/tests/mocks/OverwriteTest.java ================================================ /* * Copyright 2009-2026 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.tests.mocks; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import static org.junit.Assert.*; import org.junit.Test; public class OverwriteTest { private void test(Class c) { Method methods[] = c.getMethods(); for (Method method : methods) { if (method.getDeclaringClass() != c && method.getDeclaringClass() != Object.class && ((method.getModifiers() & Modifier.STATIC) != Modifier.STATIC) && ((method.getModifiers() & Modifier.FINAL) != Modifier.FINAL)) { fail(c.getSimpleName()+" - overwrite method: "+method.toString()); } } } @Test public void testOverwrite() { test(FakeProgram.class); test(FakeSettings.class); test(FakeProgress.class); } } ================================================ FILE: src/test/resources/added.json ================================================ {"0":1491742865376,"1020017671461":1509788625017,"1022040405693":1478686417170,"1025513801116":1509788624227,"1025710936541":1509788624346,"1025710936536":1509788624345,"1025710936539":1509788624346,"1025710936532":1509788624346,"1011606128798":1478686417220,"1025710936533":1509788624345,"1025513801110":1509788624270,"1025710936528":1509788624345,"1025710936529":1509788624345,"1025710936530":1509788624345,"1025513801107":1509788624270,"1025710936531":1509788624345,"1025710936556":1509788624345,"1013041257791":1478686417074,"1019541348776":1509788625076,"1025714868628":1509788624212,"1025714868629":1509788624212,"1025710936553":1509788624345,"1025513801130":1509788624227,"1025710936554":1509788624345,"1016819662823":1478686804025,"1025710936555":1509788624345,"1019541348780":1509788625076,"1025513801124":1509788624227,"1022044862043":1509788624958,"1025710936549":1509788624345,"1021529741102":1509788624913,"1021529741101":1509788624913,"1025710936544":1509788624345,"1022044862045":1509788624958,"1021529741110":1509788624913,"1021529741109":1509788624913,"1023701703101":1509788624234,"1020391888064":1478686804028,"1021529741104":1509788624913,"1021529741119":1509788624913,"1021529741117":1509788624913,"1025714868620":1509788624211,"1025714868621":1509788624212,"1021529741114":1509788624913,"1025714868622":1509788624212,"1021529741113":1509788624913,"1021529741124":1509788624913,"1021529741121":1509788624913,"1022249402996":1509788624304,"1021529741133":1509788624913,"1021644562019":1478686417008,"1015307462058":1478686804062,"1025513801155":1509788624207,"1021529741128":1509788624913,"1021529741139":1509788624913,"1021529741150":1509788624913,"1021529741145":1509788624913,"746466337":1444487341721,"1021328411495":1478686804043,"1022511157989":1480585069131,"1021529741158":1509788624913,"1022511157990":1480585069126,"1021529741157":1509788624913,"1021529741152":1509788624913,"1022511157997":1480585069126,"1008957057543":1478686804023,"1020783274988":1478686417029,"1022511157994":1480585069126,"1022511157995":1480585069126,"1022511158004":1480585069126,"1025043376582":1509788624452,"1022511158005":1480585069126,"1021831342459":1478686417256,"1022511158000":1480585069131,"1025513801208":1509788624539,"1022511158002":1480585069130,"1022511158003":1480585069126,"1025513801211":1509788624552,"1025513801204":1509788624611,"1022511158013":1480585069126,"1025513801206":1509788624565,"1025513801207":1509788624565,"1022511158008":1480585069126,"1022511158009":1480585069126,"1022511158010":1480585069126,"1025513801203":1509788624613,"1022485729416":1480585069126,"1022485729417":1480585069126,"1021529741190":1509788624913,"1022485729418":1480585069126,"1022485729419":1480585069126,"1021687554362":1480585069059,"1022485729421":1480585069126,"1022485729422":1480585069126,"1021529741198":1509788624913,"1021529741196":1509788624913,"1021893733884":1509788624433,"1021529741194":1509788624913,"1022485729415":1480585069126,"1022485729432":1480585069126,"1022903462322":1509788624382,"1022485729433":1480585069126,"1021529741206":1509788624913,"1022430678498":1478686417302,"1022485729435":1480585069126,"1021529741203":1509788624913,"1022485729437":1480585069126,"1022485729438":1480585069126,"1022485729439":1480585069126,"1022485729425":1480585069126,"1022485729426":1480585069126,"1021529741213":1509788624913,"1022485729427":1480585069126,"1021489370611":1478686417110,"1022485729428":1480585069126,"1022485729429":1480585069126,"1022485729431":1480585069126,"1021529741222":1509788624913,"1024519866985":1509788625070,"1022229479915":1478686417014,"1021529741217":1509788624913,"1012328870851":1478686416977,"1022485729440":1480585069126,"1022485729441":1480585069126,"1022485729442":1480585069126,"1021529741229":1509788624913,"1019169753856":1509788624373,"1021529741226":1509788624913,"1019982019575":1509788624323,"1021529741239":1509788624913,"1021390147524":1478686417042,"1008351626795":1478686804023,"1019982019574":1509788624323,"1019982019573":1509788624323,"1021529741237":1509788624913,"1019982019572":1509788624323,"1021529741236":1509788624913,"1022020351345":1478686417161,"1019982019571":1509788624323,"1021529741233":1509788624913,"1021529741244":1509788624913,"1021529741242":1509788624913,"1021529741241":1509788624913,"1021390147530":1478686417042,"1021529741240":1509788624913,"1025556006861":1509788624297,"1025524024796":1509788624843,"1025593887255":1509788624186,"1025593887252":1509788624198,"1021151854938":1478686417097,"1022485729500":1480585069126,"1025593887250":1509788624200,"1025593887251":1509788624204,"1022044862127":1509788624938,"1022485729513":1480585069127,"1022485729515":1480585069127,"1022485729516":1480585069127,"1022485729517":1480585069127,"1022485729519":1480585069127,"1022485729505":1480585069126,"1022485729507":1480585069127,"1022485729509":1480585069127,"1022485729510":1480585069127,"1022485729528":1480585069127,"1023946418156":1491634246529,"1022485729533":1480585069127,"1022485729535":1480585069127,"1022485729520":1480585069127,"1022485729521":1480585069127,"1022485729522":1480585069127,"1025002481404":1509788625006,"1022485729525":1480585069127,"1022485729526":1480585069127,"1021981553461":1478686417010,"1021457257077":1478686417044,"1024615288378":1509788624810,"1024615288379":1509788624810,"1024615288377":1509788624810,"1024615288383":1509788624810,"1024615288381":1509788624810,"1022485729536":1480585069127,"1024615288370":1509788624810,"1022485729537":1480585069127,"1022049056569":1478686417269,"1024615288369":1509788624810,"1022485729540":1480585069127,"1024615288375":1509788624810,"1023730801404":1509788624960,"1022485729543":1480585069127,"1021633552376":1509788624404,"1024615288373":1509788624810,"1003909594196":1478686804046,"1022501720102":1509788624609,"1024615288367":1509788624810,"1022501720098":1509788624609,"1022501720099":1509788624609,"1024615288352":1509788624811,"1015591629834":1478686804016,"1022501720105":1509788624609,"1024615288359":1509788624811,"1022501720106":1509788624610,"1022501720084":1509788624609,"1022501720086":1509788624609,"1022501720087":1509788624610,"1021629750313":1478686417247,"1022501720080":1509788624610,"1022501720081":1509788624609,"1022485729582":1480585069127,"1024615288348":1509788624811,"1022485729583":1480585069127,"1022501720083":1509788624610,"1022038177788":1478686417267,"1024615288339":1509788624810,"1018858060139":1509788624372,"1022501720094":1509788624609,"1022501720095":1509788624609,"1022501720088":1509788624609,"1022501720089":1509788624609,"1022501720090":1509788624609,"1022049711914":1509788624430,"1022501720091":1509788624609,"1022485729592":1480585069127,"1022485729593":1480585069127,"1022485729594":1480585069127,"1022519153464":1509788624862,"1022485729597":1480585069127,"1022485729584":1480585069127,"1022485729585":1480585069127,"1022519153459":1509788624862,"1022485729586":1480585069127,"1022501720079":1509788624609,"1022485729588":1480585069127,"1022519153462":1509788624862,"1022485729590":1480585069127,"1021629750322":1478686417248,"1022485729591":1480585069127,"1022519153461":1509788624862,"1022485729608":1480585069127,"1022485729610":1480585069127,"1022813021636":1509788625055,"1022485729611":1480585069127,"1022485729600":1480585069127,"1022485729601":1480585069127,"1022485729602":1480585069127,"1022031361143":1509788624368,"1004588296066":1444487341762,"1022485729604":1480585069127,"1022485729605":1480585069127,"1022485729607":1480585069127,"1021098114953":1509788624930,"1021098114955":1509788624930,"1022485729616":1480585069127,"1013208901189":1478686804015,"1021098114945":1509788624932,"1021098114946":1509788624940,"1024615288411":1509788624810,"1025433321754":1509788624935,"1013390177098":1444487341759,"1016400095136":1480585069069,"1024615288413":1509788624810,"1022485729657":1480585069127,"1022485729659":1480585069127,"1021490025493":1478686417046,"1022485729660":1480585069127,"1022485729662":1480585069127,"1022485729648":1480585069127,"1024615288386":1509788624811,"1024615288387":1509788624811,"1022485729651":1480585069127,"1024615288385":1509788624811,"1022485729652":1480585069127,"1024615288390":1509788624810,"1022485729654":1480585069127,"1024615288389":1509788624810,"1022485729673":1480585069127,"1022485729675":1480585069128,"1022485729677":1480585069128,"1024313294015":1509788624178,"4560522835":1465469681389,"1022485729678":1480585069128,"1022485729679":1480585069128,"1022485729664":1480585069127,"1009352180597":1478686804030,"1022485729667":1480585069127,"1023926888366":1491634246530,"1022485729669":1480585069127,"1023926888367":1491634246530,"1021527381669":1478686417047,"1010491869030":1491634246530,"1025714606116":1509788625137,"1023926888369":1491634246530,"1025714606112":1509788625138,"1016819662421":1478686804025,"1025714606114":1509788625138,"1025714606115":1509788625138,"1022485729680":1480585069128,"1021529740959":1509788624912,"1022485729681":1480585069128,"1012311962420":1478686804054,"1021529740962":1509788624913,"1021529740961":1509788624913,"1022057575978":1478686417270,"1021529740960":1509788624913,"1022084708794":1478686417272,"1021529740974":1509788624912,"1021529740973":1509788624912,"1020294106887":1465470268290,"1021529740968":1509788624912,"1021529740983":1509788624912,"1022103321412":1478686417181,"1021529740979":1509788624912,"1021529740978":1509788624912,"4333372412":1447930956559,"1021529740976":1509788624912,"1021529740991":1509788624912,"1008829653956":1509788624372,"1025671745506":1509788624943,"1021529740993":1509788624912,"1012147333506":1478686417073,"1021757678757":1478686417126,"1021529741007":1509788624912,"1021529741003":1509788624912,"1021757678755":1478686417126,"1025546438260":1509788624367,"1025101966839":1509788624307,"1021529741000":1509788624912,"1021529741009":1509788624912,"1021529741019":1509788624913,"1025546438245":1509788624368,"1021529741016":1509788624913,"1023628301325":1509788624928,"1024831954364":1509788624939,"1024831954365":1509788624939,"1021217522770":1465470268195,"1025416674951":1509788624293,"1019384191255":1509788624933,"1012816204177":1478686417026,"1023900541996":1491634246530,"1025146400363":1509788624414,"1025101966905":1509788624308,"1022501720885":1509788624911,"1025441317884":1509788624537,"1022501720886":1509788624911,"1024615288126":1509788624529,"1025441317882":1509788624541,"1025441317883":1509788624543,"1022501720881":1509788624911,"1022501720893":1509788624911,"1022501720894":1509788624911,"1020823383862":1478686417226,"1022501720889":1509788624911,"1025101966902":1509788624307,"1024615288116":1509788624529,"1022501720891":1509788624911,"1024615288105":1509788624529,"1024615288110":1509788624529,"1021151331238":1509788624945,"1024615288102":1509788624529,"1022371825903":1478686417204,"1024615288103":1509788624529,"1059863858":1458304307280,"1022501720874":1509788624911,"1021345058340":1478686804023,"1021918375387":1478686417259,"1025782503339":1509788624297,"1022501720848":1509788624912,"1022501720851":1509788624911,"1021801720549":1478686804065,"1022501720860":1509788624911,"1021831211815":1509788625083,"1024615288083":1509788624415,"1024615288080":1509788624415,"1022501720856":1509788624912,"1022251630642":1478686417066,"1024615288084":1509788624415,"1021426717464":1509788624399,"1024615288078":1509788624415,"1024615288076":1509788624415,"1022501720847":1509788624911,"1011978247246":1478686804024,"1024615288069":1509788624415,"1023658710143":1509788624326,"1020779866519":1478686417076,"1023658710141":1509788624326,"1021757417429":1509788624561,"1025714607090":1509788624230,"1021757417431":1509788624561,"1021757417430":1509788624561,"1021257893139":1465470268198,"1021257893138":1465470268197,"1024055864539":1509788624330,"1021661994344":1509788624400,"1021757417432":1509788624561,"1023658710132":1509788624326,"1024615288176":1509788624529,"1021257893136":1465470268197,"1024615288177":1509788624529,"1024831954460":1509788624939,"1010002700897":1491634246524,"1021522662851":1509788624398,"1021429076822":1478686417044,"1024615288168":1509788624529,"1010002700898":1491634246524,"1024615288169":1509788624529,"1023485431489":1509788624537,"1021328410963":1478686804043,"1024615288172":1509788624529,"1024615288173":1509788624529,"1024615288162":1509788624529,"1024615288161":1509788624529,"1024615288164":1509788624529,"1025101966939":1509788624308,"1022501720913":1509788624911,"1024615288146":1509788624529,"1024615288145":1509788624529,"1019833380943":1509788624393,"1024615288150":1509788624529,"1016819662253":1478686804025,"1025101966934":1509788624308,"1022501720897":1509788624911,"1025101966926":1509788624308,"1024615288140":1509788624529,"1022501720908":1509788624911,"1018981139093":1509788624316,"1022501720910":1509788624911,"1024615288134":1509788624529,"1022501720906":1509788624911,"1025101966919":1509788624307,"1024615288251":1509788624189,"1024615288248":1509788624189,"1024615288249":1509788624189,"1024615288254":1509788624189,"1012903630753":1478686417074,"1025782503174":1509788624296,"1024615288245":1509788624188,"1012594164002":1478686804062,"1025441317732":1509788624800,"1021903170650":1478686417054,"1106002807":1478686804024,"1025441317730":1509788624824,"1025303296677":1509788625083,"1025441317728":1509788624829,"1025441317729":1509788624834,"1023154469518":1509788624925,"1012594163999":1478686804062,"1025514587940":1509788624344,"1023154469515":1509788624928,"1024615288208":1509788624529,"1024615288203":1509788624529,"1019721051717":1509788624932,"1022160338901":1478686417063,"1024615288195":1509788624529,"1021352660747":1465470268225,"1023658710148":1509788624326,"1021352660749":1465470268225,"4954793451":1509788624155,"1021352660750":1465470268225,"1024615288314":1509788624188,"1024167802629":1509788624238,"1024167802626":1509788624238,"1024167802627":1509788624238,"1020600296111":1478686417027,"1006918857511":1509788624389,"1024167802636":1509788624238,"1024167802634":1509788624238,"1024615288311":1509788624188,"1024167802635":1509788624238,"1021706428497":1478686417250,"1024167802632":1509788624238,"1022659402080":1509788624435,"1024167802633":1509788624238,"1024615288297":1509788624188,"1024615288302":1509788624188,"1024615288290":1509788624189,"1021013834525":1478686417001,"1020600296114":1478686417027,"1024615288282":1509788624189,"1024615288283":1509788624189,"1024615288284":1509788624189,"1024615288275":1509788624188,"1024615288273":1509788624188,"1020294237255":1465470268299,"1024615288278":1509788624188,"1004342400380":1444487341756,"1024615288279":1509788624189,"708847791":1478686804064,"1021791495580":1478686417129,"1024615288271":1509788624188,"1021098114088":1509788624933,"1024615288258":1509788624188,"1025628491311":1509788624507,"1024615288257":1509788624188,"1022213227195":1478686417281,"1024615288260":1509788624188,"1024615288261":1509788624188,"1022501720629":1509788624267,"1022501720630":1509788624267,"1022501720631":1509788624267,"1022416916263":1478686417209,"1022501720625":1509788624267,"1021041228071":1509788624971,"1021695943222":1509788624404,"1022501720635":1509788624267,"1018665250518":1509788624377,"1024167802590":1509788624238,"1024167802586":1509788624238,"1022501720617":1509788624267,"1021979717966":1478686417151,"1024167802585":1509788624238,"1022501720619":1509788624267,"1025607649589":1509788624213,"1024167802599":1509788624238,"1024167802596":1509788624238,"1024167802597":1509788624238,"1024167802594":1509788624238,"1025607649587":1509788624212,"1021294463520":1478686416990,"1024167802607":1509788624238,"1022943703029":1509788624291,"1025608304832":1509788624823,"1025608304833":1509788624746,"1024167802602":1509788624238,"1022943703024":1509788624291,"1024167802603":1509788624238,"1024167802613":1509788624238,"1025607649581":1509788624212,"1024167802623":1509788624238,"1024167802621":1509788624238,"1024167802618":1509788624238,"1024167802616":1509788624238,"1024615287931":1509788625097,"1025896144771":1509788667402,"1024615287923":1509788625097,"1021687554805":1480585069059,"1024615287920":1509788625097,"1024615287927":1509788625097,"1024615287914":1509788625097,"1024615287912":1509788625096,"1025608304830":1509788624828,"1025608304831":1509788624833,"1024953853882":1509788625169,"1025607649603":1509788624213,"1024615287917":1509788625097,"1023130350822":1509788624374,"1020867556292":1509788624183,"1025524024908":1509788625167,"1019286933937":1509788625079,"1021396438132":1509788624399,"1022041847295":1478686417170,"1652187417":1444487341747,"1022898350840":1509788624402,"1022479962891":1478943089488,"1022501720644":1509788624267,"1020202224470":1465470268243,"1022501720645":1509788624267,"1022501720646":1509788624267,"1025804784934":1509788667463,"1022501720647":1509788624267,"1022501720640":1509788624267,"1022501720652":1509788624267,"1022501720653":1509788624267,"1022501720655":1509788624267,"1022501720648":1509788624267,"1022501720649":1509788624267,"1025142336686":1509788625004,"1022501720651":1509788624267,"1025142336687":1509788625004,"1024519866698":1509788625070,"1025513801230":1509788624546,"1025513801224":1509788624546,"4922418927":1509788624154,"1020817747483":1509788625021,"1015783784975":1478686804025,"1025513801218":1509788624545,"1025513801240":1509788624545,"1022501720736":1509788625236,"1022501720737":1509788625236,"1022501720738":1509788625236,"1025513801237":1509788624546,"1022501720749":1509788625236,"1025782502931":1509788624295,"1025513801239":1509788624546,"1022501720744":1509788625236,"1025323874659":1509788624298,"1024615287975":1509788625096,"1022501720745":1509788625236,"1024615287973":1509788625097,"1022501720725":1509788625236,"1021982339499":1509788625068,"1024615287961":1509788625097,"1022501720727":1509788625236,"1022501720720":1509788625236,"1024615287967":1509788625096,"1022501720721":1509788625236,"1024615287964":1509788625097,"1022501720722":1509788625236,"1024554602367":1509788624928,"1024615287955":1509788625097,"1022501720735":1509788625236,"1008317286176":1478686804023,"1022501720730":1509788625236,"1024615287946":1509788625096,"1022244946385":1478686417284,"1021568014700":1509788624456,"1012643972374":1478686417223,"1024615287951":1509788625096,"1022501720707":1509788625236,"1021008591759":1478686804039,"1022501720717":1509788625236,"1021035460899":1478686417092,"1022501720718":1509788625236,"1022501720719":1509788625236,"1022501720713":1509788625236,"1024615288058":1509788624415,"1021608517552":1478686417049,"1021608517554":1478686417049,"1024615288062":1509788624415,"1021608517556":1478686417049,"1024615288063":1509788624415,"1020985652311":1478686417088,"1021187899567":1509788624934,"1021187899566":1509788624934,"1022934657164":1509788625100,"1024781490841":1509788624231,"1024615288049":1509788624415,"1024936157649":1509788625006,"1024615288052":1509788624415,"1024615288042":1509788624415,"1024615288041":1509788624415,"1024615288046":1509788624415,"1024615288047":1509788624415,"1024615288045":1509788624415,"1024274495667":1509788624327,"1024615288033":1509788624415,"1021608517548":1478686417049,"1024615288036":1509788624415,"1022445096308":1478686417214,"1024615288026":1509788624415,"1020294106440":1465470268290,"1024615288025":1509788624415,"1024615288031":1509788624415,"1024615288028":1509788624415,"1021791495298":1478686417129,"1024615288022":1509788624415,"1652187540":1444487341744,"1015506957292":1480585069068,"1023018021820":1509788625100,"1016465238296":1478686804046,"1021472460903":1478686417045,"1025141943260":1509788624867,"1009613673805":1478686804034,"1020444709827":1478686804066,"1024960143516":1509788624169,"1024548704036":1509788625007,"706752059":1444487341708,"1020833868477":1509788624390,"1025779487223":1509788624200,"1021987059682":1478686417264,"1025671875093":1509788624942,"1023018022007":1509788624533,"228460965":1478686417019,"1021930171232":1478686417142,"1025715525068":1509788624228,"1019169755134":1509788624375,"1021594492750":1509788624419,"1020294105807":1465470268290,"1023747578015":1509788624940,"1025779487141":1509788624822,"1017167927158":1478686804058,"1025779487139":1509788624828,"1024960143605":1509788624169,"1021412037749":1480585069080,"1020117944236":1465470268277,"1022871217032":1509788624482,"1021971068485":1478686417149,"1018546496102":1480585069070,"1023647044176":1509788625146,"1023647044179":1509788625146,"1025441318229":1509788625089,"1004588294759":1444487341762,"1014343413706":1465470268319,"1004454861425":1478686804046,"1025441318218":1509788625125,"1025441318219":1509788625108,"1025441318217":1509788625117,"1016819661688":1478686804025,"1022229349834":1478686417193,"1023647044170":1509788625146,"1023647044174":1509788625146,"1023647044175":1509788625146,"4333373058":1447930956559,"1019134233861":1509788624315,"1010987984820":1478686804052,"1021083826543":1478686417094,"1021259727837":1478686417040,"1020391886874":1478686804022,"1022091787639":1478686417273,"1022091787637":1478686417273,"1022263429052":1478686417197,"1020792451055":1509788625081,"1023950220766":1509788667501,"1024886875627":1509788624460,"1018513465806":1509788624499,"1018513465803":1509788624499,"1024886875619":1509788624460,"1018513465798":1509788624499,"1024886875616":1509788624460,"1024886875622":1509788624460,"1018513465795":1509788624499,"1024886875620":1509788624460,"1013031688320":1478686804023,"1024886875642":1509788624460,"1016819661521":1478686804025,"1012103947239":1478686417025,"1023018022234":1509788624815,"1024146699792":1509788667505,"1022028083311":1478686417058,"1021951669472":1478686417261,"1021951669465":1478686417261,"1021951669461":1478686417261,"1023950220791":1509788667501,"1021951669463":1478686417261,"1022103715815":1509788624416,"1021951669462":1478686417261,"1024637703403":1509788667502,"1025593757690":1509788624200,"1025593757691":1509788624204,"1025593757692":1509788624198,"1023950220778":1509788667501,"1025593757693":1509788624186,"1021113711307":1478686417037,"1021700663246":1478686804046,"1021700663244":1478686804046,"1023950220768":1509788667501,"1013139695104":1478686804016,"1018513465743":1509788624499,"1025006805637":1509788625006,"1020868605229":1478686417079,"1018513465739":1509788624499,"1022281777429":1478686417067,"812004641":1478950494916,"1018513465735":1509788624499,"1010571956073":1478686804028,"1018513465730":1509788624499,"1021988501235":1478686417154,"1024960143827":1509788624169,"1021999380070":1478686417011,"1020581157605":1480585069077,"1022179605285":1478686417187,"1021589249771":1478686417246,"1007095807500":1478686804025,"1025714607300":1509788624212,"1018513465788":1509788624499,"1000528605626":1444487341710,"1021482946746":1478686417045,"1018513465783":1509788624499,"1018513465780":1509788624499,"1025714607305":1509788624212,"1021974869986":1509788624438,"1025714607306":1509788624212,"1010011483144":1491634246525,"1010011483151":1491634246525,"1023018022346":1509788624419,"1010011483148":1491634246525,"1010011483137":1491634246525,"1010011483143":1491634246525,"1010011483141":1491634246525,"4954792644":1509788624153,"1024095712675":1509788624459,"1009078432959":1478686804023,"1023106756766":1509788624264,"1010011483152":1491634246525,"1022866105052":1509788624268,"1018513465710":1509788624499,"1018513465708":1509788624499,"1018513465707":1509788624499,"1020917233197":1478686417228,"1021599996250":1478686417048,"1025715524663":1509788624211,"1025715524660":1509788624211,"1018513465723":1509788624499,"1025715524659":1509788624212,"1018513465716":1509788624499,"1020907403139":1478686416999,"1025715524667":1509788624211,"1021788480005":1480585069067,"1021531839833":1509788624405,"1023086834076":1509788624987,"1004342399579":1444487341711,"1023086834078":1509788624987,"1004342399582":1444487341756,"1025006805524":1509788625006,"1021845237645":1480585069083,"1023086834060":1509788624987,"1020251901681":1478686804021,"1023086834056":1509788624987,"1023086834058":1509788624986,"1025626523924":1509788625004,"1025626523925":1509788625004,"1023086834098":1509788624987,"1008043995419":1478686804023,"1016819661356":1478686804025,"1013073238746":1478686416995,"1023086834084":1509788624986,"1023086834085":1509788624987,"1022463314572":1478686417218,"1023018022332":1509788624193,"1023086834081":1509788624986,"1020803852733":1509788624318,"1024960143739":1509788624169,"1020739235288":1465470268182,"1023086834088":1509788624987,"1023086834089":1509788624987,"1025441317889":1509788624524,"1024167801794":1509788624882,"1024167801795":1509788624882,"1016731057920":1478686804031,"1024167801806":1509788624883,"1016731057921":1478686804016,"1016731057922":1478686804031,"1024167801800":1509788624882,"1024167801814":1509788624882,"1024167801815":1509788624882,"1024167801812":1509788624882,"1021937252044":1509788624464,"1019524310681":1509788624320,"1024167801809":1509788624882,"1024167801816":1509788624882,"1024167801817":1509788624882,"1008601584528":1478686804030,"1020984996275":1478686804039,"1025296744106":1509788624234,"1025714608116":1509788624844,"1022238655619":1509788624947,"1024008154379":1509788667551,"1018923596349":1509788624282,"1025714608113":1509788624844,"1022238655623":1509788624930,"1024008154380":1509788667551,"1022238655621":1509788624941,"1025532281050":1509788624343,"1025485620498":1509788625089,"1024008154371":1509788667551,"1025485620497":1509788625109,"1024008154373":1509788667551,"1024167801751":1509788624882,"1024167801749":1509788624882,"1024167801746":1509788624883,"1022019171245":1478686417161,"1024167801744":1509788624882,"1024167801745":1509788624883,"1018701294048":1465470268241,"1024008154384":1509788667551,"1018701294050":1465470268242,"1024167801755":1509788624882,"1022002524842":1478686417265,"1024167801753":1509788624882,"1000049398045":1509788625081,"1024167801762":1509788624882,"1024008154414":1509788667551,"1021757678341":1478686417126,"1021757678342":1478686417126,"1024008154407":1509788667551,"1024167801768":1509788624882,"1017221534115":1465470268268,"1024008154424":1509788667551,"1025015062837":1509788624465,"1024008154431":1509788667551,"1024167801776":1509788624882,"1000049398024":1509788625081,"1024008154428":1509788667551,"1021327101251":1465470268215,"1024167801790":1509788624882,"1024008154419":1509788667551,"1019169754582":1509788624375,"1004588294325":1444487341762,"1021327101255":1465470268215,"1024167801787":1509788624882,"1021327101253":1465470268215,"1024167801785":1509788624882,"416161354":1444487341744,"1024625251850":1509788624507,"1000306172032":1478686417027,"1025406843234":1509788624507,"1023707340758":1509788625078,"1022162041835":1478686417186,"1025406843248":1509788624456,"1012376842282":1478686417074,"1016819661150":1478686804025,"1022021530487":1509788624181,"1021390146007":1478686417042,"1025406843204":1509788624466,"1021594492290":1509788624817,"1022021530488":1509788624180,"1025006805362":1509788625006,"1025406843221":1509788624441,"1022063735185":1478686417060,"1021331032631":1478686417239,"1024886875681":1509788624460,"1025671874797":1509788624942,"1025406843196":1509788624512,"1022005408382":1478686417057,"1025406843195":1509788624511,"1468420446":1478950494923,"1022430546856":1478686417016,"1024960143959":1509788624169,"1024497716957":1509788625070,"1024886875648":1509788624460,"1022332502465":1509788624926,"1024886875654":1509788624460,"1025441318672":1509788624186,"1024886875652":1509788624460,"1024886875674":1509788624460,"1025441318668":1509788624198,"1025441318666":1509788624201,"1025441318667":1509788624205,"1024936158447":1509788625006,"1021954946904":1509788624464,"1023647043592":1509788624554,"1024886875667":1509788624460,"1023647043594":1509788624554,"1023647043595":1509788624554,"1021345057529":1478686804023,"1023647043596":1509788624554,"1020101166292":1480585069079,"1024886875671":1509788624460,"1023647043597":1509788624554,"1025779487529":1509788625123,"1021774455149":1509788625010,"1025058581935":1509788624276,"1021774455148":1509788625010,"1021774455145":1509788625010,"1021774455147":1509788625010,"1021799489563":1478686417052,"1021774455141":1509788625010,"1022394240149":1478686417291,"1021774455143":1509788625010,"1021774455137":1509788625009,"1021774455139":1509788625009,"1009007782512":1509788624363,"1025058581938":1509788624276,"372117811":1444487341704,"1025058581939":1509788624276,"1025058581937":1509788624276,"1021328804925":1478686417041,"1019575428258":1509788624375,"1019575428262":1509788624386,"1025525203416":1509788624523,"1019982019695":1509788624324,"1019982019694":1509788624324,"1021776552295":1509788624399,"1021448869061":1478686416980,"1021688342147":1509788624916,"1021774455132":1509788625010,"1022007636921":1478686417057,"1025715525301":1509788624565,"1021774455134":1509788625010,"1021774455129":1509788625010,"1021774455128":1509788625010,"1021774455131":1509788625010,"1021774455130":1509788625010,"1014723003874":1480585069078,"1021774455127":1509788625009,"1025712903825":1509788624306,"1025485620254":1509788624431,"1024167801475":1509788624575,"1024167801472":1509788624575,"1024167801486":1509788624574,"1024167801484":1509788624574,"1024167801482":1509788624574,"1024167801480":1509788624574,"1024167801494":1509788624575,"1024167801495":1509788624575,"1021320809678":1478686417238,"1019982019615":1509788624323,"1024167801502":1509788624575,"1024167801503":1509788624574,"1020438024558":1478686804032,"1022425696993":1478686417210,"1022425696994":1478686417210,"1025671874943":1509788624942,"1007891557518":1478686804023,"1021059841125":1478686804050,"1021059841124":1478686804050,"1024167801508":1509788624574,"1001380913534":1478686804059,"1001380913529":1478686804059,"1024167801504":1509788624575,"1024167801505":1509788624574,"1001380913526":1478686804059,"1016819660972":1478686804025,"1022424386210":1478686417210,"372117853":1444487341705,"1020893378146":1478686417079,"1001380913515":1478686804059,"1025779487406":1509788624537,"1001380913511":1478686804059,"1025779487404":1509788624540,"1001380913510":1478686804059,"1001380913505":1478686804059,"1019325600751":1478686804067,"1019325600750":1478686804067,"1001380913545":1478686804059,"1001380913547":1478686804059,"1001380913541":1478686804059,"1024146175145":1509788624435,"1001380913537":1478686804059,"1021032054064":1478686417091,"1021974869249":1509788624429,"1001380913538":1478686804059,"1021490025167":1478686417110,"1024167801462":1509788624575,"1024167801460":1509788624575,"1024167801461":1509788624575,"1024167801459":1509788624574,"1024167801471":1509788624575,"1024167801468":1509788624575,"1024167801469":1509788624575,"1023134806212":1509788624563,"1024167801466":1509788624575,"1024008154358":1509788667552,"1024167801467":1509788624575,"1024167801465":1509788624575,"1023134806204":1509788624563,"1021687555706":1480585069059,"1023134806205":1509788624563,"1016400093440":1480585069068,"1023134806206":1509788624563,"1013208899800":1478686804015,"1023134806207":1509788624563,"1021376252384":1478686417105,"1021238493609":1465469681395,"1021376252387":1478686417105,"1021700531513":1478686804046,"1019932475285":1509788624922,"706751991":1444487341708,"1483104185":1491634246517,"1016355398798":1465470268254,"1019387600690":1509788624301,"1023497226810":1509788624461,"1016731057895":1478686804015,"1025615383662":1509788625021,"1016731057915":1478686804040,"1016731057918":1478686804031,"1022256874587":1478686417196,"1022007636849":1478686417057,"1025366733937":1509788624293,"1024794071697":1509788624989,"1020833867412":1509788624285,"1020833867409":1509788624285,"1020833867408":1509788624285,"1020833867411":1509788624285,"1020833867410":1509788624285,"1020833867405":1509788624285,"1020833867404":1509788624284,"1020833867407":1509788624285,"1020833867406":1509788624285,"1221738694":1478686804029,"1020833867403":1509788624284,"154403107":1444487341735,"1020780913586":1478686416997,"1018922939517":1509788624282,"1020780913592":1478686416997,"1016601950915":1478686804022,"1018922939512":1509788624302,"1023417008294":1509788625039,"1020833867449":1509788624283,"1012115877376":1478686417223,"1020833867448":1509788624283,"1020833867450":1509788624283,"1020833867445":1509788624283,"1020833867444":1509788624283,"1020833867447":1509788624283,"154403103":1444487341717,"1020833867446":1509788624283,"1020833867441":1509788624283,"1020833867443":1509788624283,"1016819660783":1478686804025,"1020833867442":1509788624283,"1023454626407":1509788624986,"1020887218511":1478686417032,"1021114890211":1465470268183,"1020887218508":1478686417032,"1024262435427":1509788624867,"1024205946824":1509788624185,"1021960321333":1478686417261,"154403173":1444487341721,"1020780913606":1478686416997,"1021595013960":1509788624401,"1022440769190":1478686417295,"1017808220809":1478686804016,"1020294104791":1465470268290,"1021039653595":1478686417035,"1016819660612":1478686804025,"1025711200589":1509788624304,"1021704464959":1478686417250,"1024794071581":1509788624989,"1020833867277":1509788624284,"1020833867276":1509788624284,"1020833867278":1509788624284,"1020833867273":1509788624284,"1020833867272":1509788624284,"1020833867274":1509788624284,"1020833867269":1509788624284,"1021620835628":1478686417247,"1020833867268":1509788624284,"1020833867271":1509788624284,"1020833867270":1509788624284,"1021895173623":1478686417258,"1021949049013":1509788624355,"1025637401754":1509788624294,"1025714608387":1509788624866,"1000528477300":1444487341710,"1022085624152":1478686416988,"1021949311164":1478686417145,"1021993745337":1478686417156,"1020984213324":1478686417034,"1025607647965":1509788624845,"1018919269492":1509788624282,"1022456629013":1478686417072,"1022156928379":1478686417278,"1025607647950":1509788624845,"1022192318297":1478686417279,"1024686464032":1509788625024,"1022192318310":1478686417279,"1021885605166":1509788624368,"1023121964761":1509788624374,"1022452041446":1478686417296,"1017303716870":1478686804049,"1007894045485":1444487341757,"1007894045487":1444487341757,"1020833867373":1509788624284,"1020833867372":1509788624284,"1020833867375":1509788624284,"1020833867374":1509788624284,"1020833867369":1509788624284,"1025607647968":1509788624845,"1020833867368":1509788624284,"1025607647969":1509788624846,"1020833867371":1509788624284,"1020833867370":1509788624284,"1020833867365":1509788624284,"1020833867367":1509788624284,"1021713640179":1509788624396,"1022633840723":1480585069094,"1022633840730":1480585069135,"1022633840711":1480585069140,"1022633840705":1480585069078,"1022633840706":1480585069094,"1025116513347":1509788624945,"1021387261596":1478686417006,"1022633840713":1480585069094,"435687654":1491634246504,"1022633840757":1480585069094,"1004588298210":1444487341763,"1587042229":1491634246505,"1022633840745":1480585069094,"1021741821276":1509788624986,"1023086837099":1509788624987,"1022088376472":1478686417180,"1022088376476":1478686417180,"1016098233735":1478686804065,"1016819660432":1478686804025,"1021654914772":1478686417120,"1022633840692":1480585069094,"1010386351666":1478686804023,"1022633840701":1480585069094,"1022633840699":1480585069094,"1021424490556":1478686417043,"1021791497744":1478686417129,"1022633840685":1480585069094,"4956761843":1509788624155,"1022075793685":1509788624416,"1021729368747":1509788624395,"1025714870312":1509788624549,"1021721504300":1478686804047,"1025714870319":1509788624549,"1021640890305":1509788624818,"1022932689610":1509788625018,"1021692405954":1509788624308,"1010812211271":1509788624276,"1008033511977":1478686804018,"2221706707":1491743595335,"1023086837140":1509788624986,"1022440245020":1478686417071,"4928449536":1509788624154,"1022257007202":1478686417067,"1016819660300":1478686804025,"4954795654":1509788624155,"1022807256358":1490882721865,"1021687556192":1480585069059,"1221738801":1478686804033,"1021151332442":1509788624971,"1021846938578":1478686417135,"1010446256723":1478686804054,"1023086837152":1509788624986,"1010446256724":1478686804054,"1023306385607":1509788625041,"1008664499197":1478686804030,"1012179705981":1478686416994,"1137854916":1444487341733,"1019285625062":1509788624314,"1019285625059":1509788624312,"1021496844083":1478686417112,"1020612488191":1478686417027,"1025320858403":1509788625099,"1019926311556":1509788625016,"1022385717343":1509788624392,"1009987628380":1491634246533,"1018513469068":1509788624500,"1018513469066":1509788624500,"1022385717336":1509788624392,"1018513469063":1509788624500,"1022385717335":1509788624392,"1014767963717":1478686804028,"1021728319841":1478686417051,"1018513469058":1509788624500,"1018513469056":1509788624500,"1022807256747":1490882721865,"1018513469081":1509788624500,"1021853360513":1509788624435,"1018513469079":1509788624500,"1018513469077":1509788624500,"1018513469074":1509788624500,"1021782846860":1478686417128,"1020961799321":1478686417033,"1021485178820":1509788624977,"1023933836712":1491634246529,"1020294104282":1465470268290,"1020817745892":1509788625021,"1024899721818":1509788624334,"1022385717344":1509788624392,"1022074614518":1478686417061,"2007792941":1480585069061,"1025714608951":1509788624469,"1743023459":1478686417020,"1022258579765":1478686417196,"1009078434722":1478686804023,"1019808348983":1509788625077,"1019808348973":1509788625078,"1021187901940":1509788624934,"1019808348965":1509788625078,"1021687556901":1480585069059,"1021949049502":1509788624355,"1012105522247":1478686417223,"1022236952675":1478686417194,"1016819660127":1478686804025,"1018513469039":1509788624500,"1743023430":1478686417020,"1018513469036":1509788624500,"1743023424":1478686417020,"1018513469033":1509788624500,"1018513469030":1509788624500,"1025320858533":1509788625099,"1020294235137":1465470268298,"1652189393":1444487341719,"1743023439":1478686417020,"2007792924":1480585069060,"1743023445":1478686417020,"1018513469053":1509788624500,"2007792927":1480585069060,"2007792920":1480585069060,"1025643169602":1509788624365,"1023970403135":1509788625037,"1021566570567":1509788624405,"1018513469049":1509788624500,"1743023443":1478686417020,"2007792923":1480585069060,"1743023453":1478686417020,"1018513469044":1509788624500,"1021562639281":1478686417113,"1025643169584":1509788624365,"1020882107254":1478686416999,"1003686771293":1478686804060,"1022479309498":1478943089531,"1003686771292":1478686804060,"1003686771295":1478686804060,"1003686771294":1478686804060,"1003686771289":1478686804060,"1003686771288":1478686804060,"1024383159237":1509788624327,"1003686771290":1478686804060,"1003686771285":1478686804060,"1025643169582":1509788624364,"1025643169583":1509788624364,"1025643169580":1509788624364,"1003686771281":1478686804060,"1025643169579":1509788624365,"1004588297239":1444487341762,"1025643169552":1509788624365,"1011209501391":1478686804022,"1003686771296":1478686804060,"4928450350":1509788624155,"1021187901845":1509788624934,"1025643169550":1509788624365,"1025643169551":1509788624365,"1008958365835":1478686804023,"1021262220777":1478686804039,"1022807257087":1490882721865,"1023173341710":1509788625083,"1022444832158":1478686417214,"4557505710":1465469681388,"1652189559":1444487341726,"1020983819394":1478686417230,"1024794071453":1509788624989,"1016819659992":1478686804025,"2068869237":1491634246510,"1003761913":1478686804024,"1012126100656":1478686417025,"4968686360":1509788624154,"1020965731737":1478686417086,"1022073697152":1509788624924,"1012258612358":1478686417073,"1022086804153":1478686417179,"1022501722750":1509788624987,"1024244609566":1509788624948,"1025514589901":1509788624340,"1021387130071":1478686804045,"1014767963999":1478686804022,"1021387130070":1478686804045,"1023932001445":1491634246530,"1021387130069":1478686804045,"1025320858206":1509788625099,"1021387130068":1478686804045,"1021387130067":1478686804045,"1022241540576":1478686417066,"1008905022672":1509788624372,"1025715526367":1509788624549,"1021387130076":1478686804045,"1024781881975":1509788625020,"1009275565620":1478686804025,"1021387130075":1478686804045,"1021387130074":1478686804045,"1023932001449":1491634246530,"1021387130073":1478686804045,"1021387130072":1478686804045,"1022073697243":1509788624530,"1025715526373":1509788624549,"1022491892429":1478943089254,"1025715526369":1509788624549,"1024619617171":1509788624388,"1024619617172":1509788624388,"1024205946093":1509788624184,"1025715526377":1509788624549,"1024205946097":1509788624184,"1024205946099":1509788624184,"1023880884116":1509788625038,"1021974477304":1509788624437,"716579273":1444487341733,"1022238787905":1509788624947,"1012568083115":1478686417026,"1022238787906":1509788624941,"1022238787907":1509788624932,"1017303717740":1478686804049,"1022238787910":1509788624971,"1022238787911":1509788624933,"1022238787912":1509788624931,"1024619617137":1509788624392,"1024619617138":1509788624392,"1024619617139":1509788624392,"1024619617140":1509788624392,"1024619617141":1509788624392,"1024619617142":1509788624392,"1022501722788":1509788624986,"1023354752972":1509788625101,"1025142334529":1509788625004,"1021601306455":1478686417115,"1016857676298":1509788624976,"1025142334534":1509788625004,"1024383158919":1509788624327,"1025142334535":1509788625004,"1025142334536":1509788625004,"1025142334537":1509788625004,"1018754119949":1509788624378,"1022501722798":1509788624986,"1025142334538":1509788625004,"1025142334540":1509788625004,"1022501722795":1509788624986,"1022501722772":1509788624986,"1021832127166":1478686417134,"1025714870803":1509788625137,"1022501722770":1509788624986,"1025714870806":1509788625137,"1025714870808":1509788625137,"1022074876716":1478686417177,"1022420060091":1478686417293,"1025714870809":1509788625137,"1025714870811":1509788625137,"1022074876715":1478686417177,"1023628303967":1509788624928,"1025320858297":1509788625099,"1022073697037":1509788624971,"1022501722755":1509788624986,"1021003346910":1478686417089,"1021003346909":1478686417089,"1020586661093":1478686417224,"1025715526202":1509788625136,"1022088770069":1478686417180,"1013390178785":1444487341759,"1019596533652":1509788624932,"1021613889486":1478686416991,"1022398169230":1478686417291,"1021009114075":1478686417001,"1022420060103":1478686417293,"2068869255":1491634246510,"1022420060106":1478686417293,"1025900336987":1509788667462,"1022420060104":1478686417293,"1025900336984":1509788667463,"1022420060105":1478686417293,"1025900336990":1509788667458,"1024205945950":1509788624184,"1020965731710":1478686417086,"1024002777181":1491634246532,"1024002777183":1491634246532,"1020983819371":1478686417230,"1017972787437":1509788624372,"1019761026426":1509788625078,"1022440244532":1478686417071,"1019761026425":1509788625078,"1022487697921":1478943089532,"1020955639475":1465470268304,"1025142334526":1509788625004,"1025548405869":1509788625020,"1022088770082":1478686417180,"1020983819384":1478686417230,"1021015274072":1478686417231,"1020220048078":1478686804039,"1020927850726":1478686417082,"1021147401676":1478686417097,"1016819659713":1478686804025,"1019745689969":1509788624314,"1023320018536":1509788625041,"1024095321104":1509788667892,"1021032314503":1478686417091,"1022934656873":1509788624533,"1020471448590":1478686804047,"1021604450437":1478686417115,"1022045911675":1478686804040,"1022045911674":1478686804040,"1022045911678":1478686804040,"1022045911677":1478686804040,"1022045911676":1478686804040,"1018513467535":1509788624499,"1018513467533":1509788624499,"1024167803278":1509788624473,"1018513467527":1509788624499,"1024167803279":1509788624473,"1024167803276":1509788624473,"1018513467525":1509788624499,"1004588296836":1444487341763,"1021035460311":1478686417091,"1024167803284":1509788624473,"1024167803282":1509788624473,"1021982604880":1478686417151,"1021920076694":1478686417259,"1024167803283":1509788624473,"1024167803280":1509788624473,"1024167803290":1509788624473,"1018513467539":1509788624499,"1024167803291":1509788624473,"1024167803288":1509788624473,"1024167803289":1509788624473,"1021003346951":1478686417089,"1024167803300":1509788624473,"1024167803301":1509788624473,"1022851951152":1490882721866,"1021003346946":1478686417089,"1652190748":1444487341727,"1021003346945":1478686417089,"1024167803296":1509788624473,"1021727403830":1478686417051,"1024167803309":1509788624473,"1024167803306":1509788624473,"1024946515728":1509788624867,"1024946515729":1509788624844,"1024167803304":1509788624473,"1024946515730":1509788624822,"1024946515724":1509788624829,"1024167803319":1509788624473,"1024167803317":1509788624473,"1024334132104":1509788624198,"1024167803314":1509788624473,"1024167803312":1509788624473,"1024167803313":1509788624473,"1024946515716":1509788624830,"1024946515717":1509788624829,"1021003346973":1478686417089,"1024946515718":1509788624829,"1024946515719":1509788624829,"1024167803322":1509788624473,"1024946515712":1509788624829,"1022058757089":1475218613699,"1024946515715":1509788624829,"1022073697331":1509788624530,"1012895766824":1478686417224,"1010093924904":1491634246522,"1022073697330":1509788624530,"1022073697332":1509788624530,"1018513467485":1509788624499,"1022073697321":1509788624530,"1022073697327":1509788624530,"1022045911771":1478686804065,"1022073697314":1509788624530,"1022073697313":1509788624530,"1022073697317":1509788624530,"1018513467503":1509788624499,"1022073697305":1509788624530,"1022073697304":1509788624530,"1022073697311":1509788624530,"1955100717":1444487341738,"1018513467495":1509788624499,"1020294103555":1465470268289,"1018513467493":1509788624499,"1018554362580":1509788624372,"1022073697303":1509788624530,"1018513467490":1509788624499,"1022073697301":1509788624530,"1018513467488":1509788624499,"1018513467519":1509788624499,"1022073697291":1509788624530,"1021903168112":1478686417300,"1018513467517":1509788624499,"1022073697288":1509788624530,"1021517421430":1478686416982,"1018513467514":1509788624499,"1022073697293":1509788624530,"1018513467511":1509788624499,"1018513467508":1509788624499,"1022073697285":1509788624530,"1022045911683":1478686804040,"1022045911682":1478686804040,"1022045911681":1478686804040,"1022045911680":1478686804040,"1022045911687":1478686804040,"1022045911686":1478686804040,"1022045911685":1478686804040,"1022045911684":1478686804040,"1023054462700":1509788625047,"1019939681561":1509788624288,"1021328410591":1478686804045,"1022181700338":1478686417187,"1021925712773":1478686417259,"1022956937446":1509788624221,"1022956937447":1509788624221,"1020294234716":1465470268298,"1022956937445":1509788624221,"1022956937448":1509788624221,"1022956937449":1509788624221,"1022073697723":1509788624416,"1022200443400":1478686417013,"1022073697722":1509788624416,"1022303276010":1478686417287,"1023342693910":1509788625041,"1022073697725":1509788624416,"1022073697719":1509788624416,"1020815777980":1478686417078,"1022073697716":1509788624416,"1022156009692":1509788624958,"1020815777953":1478686417078,"1022073697706":1509788624416,"1022073697705":1509788624416,"1006805215162":1478686804029,"1022073697709":1509788624416,"1023393942256":1509788624825,"1020815777961":1478686417078,"1022073697699":1509788624416,"1020815777963":1478686417078,"1022073697703":1509788624416,"1022073697701":1509788624416,"1020574602033":1509788624375,"1020574602035":1509788624375,"1025569506681":1509788624350,"1020574602036":1509788624375,"1022111446867":1478686417276,"1021662908959":1509788624396,"1025569506676":1509788624351,"1025569506677":1509788624351,"1021278602539":1478686417237,"1025320858682":1509788625099,"1021087232091":1478686417094,"1020984998615":1478686804039,"1024167803022":1509788625185,"1024167803023":1509788625185,"1024167803021":1509788625183,"1020050174490":1509788624286,"1024167803030":1509788625185,"1024167803025":1509788625185,"1016554234607":1478686804023,"1022934656538":1509788624816,"1024167803034":1509788625185,"1025628750259":1509788624229,"1024167803043":1509788625185,"1024167803041":1509788625185,"1024167803054":1509788625183,"1022073697746":1509788624416,"1024167803050":1509788625184,"1021511654230":1478686417047,"1024167803051":1509788625184,"1024167803048":1509788625184,"1022073697748":1509788624416,"1024167803049":1509788625184,"1024167803062":1509788625185,"1024167803060":1509788625185,"1024167803058":1509788625183,"1024167803059":1509788625184,"1024167803057":1509788625183,"1022073697729":1509788624416,"1024167803068":1509788625183,"1024167803069":1509788625183,"1024167803066":1509788625183,"1024167803067":1509788625184,"1024167803065":1509788625184,"1022238658371":1509788624947,"1022934656706":1509788624194,"1024946515706":1509788624822,"1022238658372":1509788624931,"1024946515702":1509788624835,"1022245605363":1478686417066,"1025607649183":1509788624229,"1024946515696":1509788624917,"1024946515697":1509788624915,"1024946515699":1509788624915,"1025714609187":1509788624469,"1025714871343":1509788625167,"1022807255388":1490882721865,"1025788139751":1509788624972,"1020955637990":1465470268304,"1024899722651":1509788624334,"1023878917793":1491634246506,"1023530254852":1509788624558,"1023530254850":1509788624558,"1021250161256":1465470268197,"1023530254851":1509788624559,"1018659480061":1478686804016,"1023530254848":1509788624558,"1023530254849":1509788624559,"1025320858840":1509788625099,"1023393942075":1509788624825,"1023152108946":1509788667538,"1022154436643":1478686416982,"1023821245831":1491634246535,"478941567":1444487341705,"1021504969578":1478686804040,"1022400005853":1478686417292,"1010077803452":1491634246534,"1021529741583":1509788624504,"1021529741581":1509788624504,"1021529741580":1509788624504,"1021529741591":1509788624504,"1024184449241":1509788624480,"1021529741590":1509788624504,"1021529741588":1509788624504,"1022002526945":1478686417157,"1021529741587":1509788624504,"1021354623873":1465470268233,"1021529741585":1509788624504,"1021529741596":1509788624504,"1023741678860":1509788624960,"1021529741606":1509788624504,"1022073697944":1509788624924,"1021529741603":1509788624504,"1020294234243":1465470268298,"1021529741615":1509788624504,"1022073697939":1509788624924,"1021529741614":1509788624504,"1022073697938":1509788624924,"1024184449251":1509788624480,"1021529741612":1509788624504,"1022073697942":1509788624924,"1021529741609":1509788624504,"1021529741623":1509788624504,"1022073697931":1509788624924,"1022192054715":1478686416981,"1024184449274":1509788624480,"1022073697929":1509788624924,"1022073697928":1509788624924,"1021529741617":1509788624504,"1021529741616":1509788624504,"1022073697932":1509788624924,"1022073697927":1509788624924,"1021529741626":1509788624504,"1022073697925":1509788624924,"1021990337932":1478686417155,"1022934656262":1509788624419,"1022084707921":1478686417272,"1021685854102":1478686417121,"1024134118784":1509788667503,"1022482587153":1478943089488,"1024134118788":1509788667504,"1000297654506":1478950494932,"1022807255711":1490882721865,"478941928":1444487341705,"1025902170638":1509788667458,"1022044731418":1478686417011,"1025902170637":1509788667463,"1023211614890":1509788624429,"1021362357101":1478686417006,"1021362357098":1478686417006,"1410226806":1509788625019,"1021362357094":1478686417006,"1022447845578":1478686417072,"1024134118729":1509788667504,"1019963798779":1478686804024,"1024134118720":1509788667503,"1023658711218":1509788624325,"1024134118727":1509788667504,"1023658711214":1509788624325,"1023658711212":1509788624325,"1023658711210":1509788624325,"1024134118748":1509788667504,"1024134118738":1509788667504,"1022518762669":1509788624990,"1023658711201":1509788624325,"1021854541066":1509788625012,"1024134118762":1509788667504,"1022214016761":1478686417281,"1024134118764":1509788667504,"1023845363640":1509788624278,"1023845363638":1509788624278,"1023845363639":1509788624278,"1023845363636":1509788624278,"1023845363637":1509788624278,"1023845363634":1509788624278,"1023845363635":1509788624278,"1024134118758":1509788667503,"1023845363633":1509788624278,"1025373942610":1509788624306,"1024134118776":1509788667504,"1024134118778":1509788667504,"1024134118781":1509788667504,"1024134118769":1509788667504,"1024134118772":1509788667504,"742400765":1444487341708,"1025500957389":1509788624205,"1024134118774":1509788667504,"1020822987672":1478686416998,"1015996645427":1465470268314,"1022073697914":1509788624924,"1022092441436":1478686417274,"1012115876067":1478686417223,"1025531496536":1509788624343,"1020939778794":1478686417084,"1021944725132":1478686417144,"1022073697916":1509788624924,"1022073697906":1509788624924,"1022018911028":1478686417011,"1022073697911":1509788624924,"1022073697908":1509788624924,"1023393941815":1509788624199,"1023144637968":1509788625045,"1024793809988":1509788625069,"1021839598684":1478686417257,"1021981555936":1478686417010,"716579948":1444487341734,"1023530254638":1509788625151,"1023530254639":1509788625151,"1023530254636":1509788625151,"1023530254634":1509788625151,"1020148091789":1509788624302,"1023530254646":1509788625151,"478941823":1444487341706,"1025529399371":1509788624344,"1007134602229":1509788624374,"1020987881865":1478686417034,"179831875":1444487341743,"1014683021375":1465470268313,"1024458787180":1509788625029,"1021989813438":1478686417264,"1851023698":1444487341745,"1022064785445":1478686417174,"1025896666064":1509788667459,"1023328406725":1509788624493,"1025896666065":1509788667459,"1014765210456":1478686804024,"1025896666059":1509788667461,"1022807256044":1490882721865,"1025896666057":1509788667465,"1025896666061":1509788667462,"1851023692":1444487341732,"1021529741342":1509788624506,"1021529741341":1509788624506,"1021226043942":1478686417099,"1025896666054":1509788667462,"1021529741337":1509788624506,"1021529741351":1509788624506,"1021529741349":1509788624506,"1021529741347":1509788624506,"1022441947521":1478686417214,"1021529741344":1509788624506,"1021529741359":1509788624506,"1021529741358":1509788624506,"1021529741356":1509788624506,"1009482204691":1480585069074,"1021529741367":1509788624506,"1021529741366":1509788624506,"1021529741363":1509788624506,"1021529741362":1509788624506,"1021529741360":1509788624506,"1013271553122":1478686804024,"1021529741374":1509788624506,"885799926":1444487341749,"154404360":1444487341727,"1021529741369":1509788624506,"1021529741378":1509788624506,"742400774":1444487341708,"810041102":1478686804029,"1021529741376":1509788624506,"1020936108846":1478686417228,"1021801719683":1478686804039,"1020936108854":1478686417228,"1026223431701":1514456869766,"1851023630":1444487341745,"1020936108858":1478686417228,"1022594521327":1480585069076,"1019674126033":1509788625079,"1024167672485":1509788625035,"1022397514811":1478686417291,"1020612488871":1478686417027,"1024205945077":1509788624184,"1024205945082":1509788624184,"1021989813440":1478686417264,"1023117506847":1509788625079,"1021949050759":1509788624354,"1019648829606":1509788624312,"1021288171247":1478686417004,"1023565389352":1491634246523,"1023565389350":1491634246536,"1023565389351":1491634246536,"1022167544457":1509788624439,"1023565389349":1491634246536,"1013067731183":1478686417026,"1012148643768":1478686417025,"1020220049058":1478686804039,"1021969890652":1478686417262,"1024954772326":1509788624354,"1025628488567":1509788624507,"1024205944867":1509788624185,"1008317287211":1478686804023,"1538413591":1491634246519,"1022258056212":1478686417284,"1022258056213":1478686417284,"1022453350823":1478686417215,"1022258056203":1478686417284,"1024262436246":1509788624875,"1022268673199":1478686417067,"1022258056197":1478686417284,"1021356327608":1478686417104,"1020002988992":1509788624281,"1538413688":1491634246519,"812007346":1478950494916,"1011793304739":1478686804062,"1021529741531":1509788624506,"1022073436000":1478686417012,"1011793304736":1478686804062,"1021529741539":1509788624506,"1022579186035":1509788624462,"1011793304729":1478686804062,"1522423129":1478686804029,"1021529741536":1509788624506,"1021529741551":1509788624506,"1724410145":1444487341706,"1021529741550":1509788624506,"1021529741548":1509788624506,"1022470790912":1478686804049,"1025532676481":1509788624340,"1021529741546":1509788624506,"1021529741545":1509788624506,"1021529741544":1509788624506,"1021529741559":1509788624506,"1011793304718":1478686804062,"1021529741557":1509788624506,"1021529741556":1509788624506,"1021529741555":1509788624506,"1023251722645":1509788624430,"1024184449341":1509788624480,"1021529741554":1509788624506,"1021529741553":1509788624506,"1021529741552":1509788624506,"1021529741567":1509788624506,"1021529741564":1509788624506,"1021529741562":1509788624506,"1025063036309":1509788625019,"1021473113191":1478686417109,"1021058657082":1509788624942,"1023606408029":1509788625140,"1024953201428":1509788625202,"1025609489403":1509788624186,"1024953201424":1509788625202,"1024953201425":1509788625202,"1021058657074":1509788624942,"1025609489396":1509788624200,"1025609489397":1509788624204,"1025609489398":1509788624198,"1023606408018":1509788625140,"1023606408012":1509788625140,"1024953201414":1509788625202,"1024953201413":1509788625202,"1020597547171":1478686804032,"1024953201410":1509788625202,"1022263432029":1478686417197,"1024953201411":1509788625202,"1024953201408":1509788625202,"1024953201422":1509788625202,"1024953201423":1509788625202,"1024953201420":1509788625202,"1023606408006":1509788625245,"1024953201421":1509788625202,"1018998051317":1509788624391,"1018998051319":1509788624391,"1024953201416":1509788625202,"1018998051318":1509788624391,"1014253631222":1465470268245,"1025593629410":1509788624198,"1020597547166":1478686804039,"1025593629411":1509788624186,"1025593629408":1509788624201,"1024018775170":1509788667493,"1025593629409":1509788624204,"1026226585344":1514456869774,"1023606408042":1509788625144,"1019851334454":1509788625079,"1025710932464":1509788624306,"1019219173022":1509788624317,"1022146833436":1478686417277,"1020945147323":1478686417229,"1021484516752":1478686417110,"1025609489321":1509788624428,"1025609489323":1509788624425,"1025609489326":1509788624406,"1012140390648":1478686417073,"1024633110610":1509788624225,"714488527":1444487341700,"1024633110611":1509788624225,"1024633110609":1509788624225,"1744861276":1444487341725,"1024633110614":1509788624225,"1103909265":1491634246508,"1024633110612":1509788624225,"1025874250323":1509788667826,"1022021526963":1509788624179,"1022021526962":1509788624181,"1023606407995":1509788625245,"1023946422134":1491634246529,"1021492512047":1509788624816,"1021058657099":1509788624932,"1019284963978":1509788624312,"1021058657094":1509788624930,"1023606408156":1509788625140,"1021606415379":1509788624404,"1024899723429":1509788624334,"1007870458285":1480585069065,"1021606677735":1509788624404,"1021567879767":1509788624867,"1023606408143":1509788624868,"1022081296568":1478686417061,"1021880892565":1478686804069,"1017244469306":1478686804058,"1021369703974":1478686804065,"749091858":1444487341700,"1024686982208":1509788625024,"1007026333487":1478686804023,"1022807258180":1490882721865,"1021469049952":1478686417242,"1020574600919":1509788624386,"1020574600918":1509788624386,"1020294110817":1465470268291,"714488411":1444487341700,"1023509290454":1509788625080,"714488391":1444487341701,"1023606408072":1509788625113,"757087733":1444487341756,"1021622668620":1478686417247,"1014740964220":1480585069071,"1023606408068":1509788625113,"1021096668713":1478686417094,"1010267990178":1478686804033,"1023606408113":1509788625113,"714488422":1444487341701,"761675152":1444487341737,"1022198345683":1509788624928,"1014253631443":1465470268245,"1025907936520":1509788667462,"1021995311693":1509788624466,"1010395402684":1478686804025,"1025679220465":1509788624352,"1025679220467":1509788624350,"1018546501587":1480585069070,"294650038":1444487341735,"4990056513":1509788624155,"1010395402649":1478686804025,"1020574600997":1509788624386,"1020574600996":1509788624386,"1024953201196":1509788624588,"1024953201237":1509788624588,"1024953201234":1509788624589,"1022049707842":1509788624509,"1024953201245":1509788624588,"1024953201240":1509788624588,"1024412127769":1509788624465,"1023741151748":1491634246523,"1023741151751":1491634246523,"1023741151744":1491634246523,"749092351":1444487341700,"1012189018776":1478686416994,"1024953201231":1509788624588,"1021262222926":1478686804039,"1024953201229":1509788624589,"1024953201224":1509788624589,"1024953201270":1509788624588,"1025507382412":1509788624203,"1024195061582":1509788624507,"1024953201276":1509788624588,"478940641":1444487341703,"1024953201273":1509788624588,"1025615387374":1509788625021,"1024953201255":1509788624588,"1024953201252":1509788624588,"1024953201262":1509788624588,"1024953201258":1509788624588,"1024633241973":1509788625026,"1013504993294":1478686804052,"1022110526432":1478686417182,"1021210842508":1465470268194,"1019971529326":1480585069073,"1024953201311":1509788624487,"1019841765930":1509788625079,"1027327795431":1523788103996,"1021210842504":1465470268194,"1014253631323":1465470268245,"1022273918245":1478686417067,"1024953201286":1509788624589,"1024953201285":1509788624589,"1024953201283":1509788624589,"1022897305626":1509788625052,"1022089947196":1478686417273,"4949685912":1509788624156,"1023986137882":1509788624382,"1024953201334":1509788624487,"1023986137883":1509788624382,"1023986137880":1509788624382,"1021350960141":1509788624918,"1023986137881":1509788624382,"1023986137886":1509788624381,"1024953201331":1509788624487,"1023986137884":1509788624382,"1021350960137":1509788624918,"1017244469557":1478686804058,"1023986137885":1509788624382,"1023986137874":1509788624382,"1023986137875":1509788624382,"1024953201340":1509788624487,"1023986137878":1509788624382,"1023986137879":1509788624382,"1020612489341":1478686417027,"1023986137876":1509788624382,"1024953201336":1509788624487,"1023986137877":1509788624382,"1024953201317":1509788624487,"1024953201315":1509788624487,"1021350960153":1509788624918,"1024953201327":1509788624487,"1024953201324":1509788624487,"1021350960146":1509788624918,"1024953201320":1509788624487,"1024953201367":1509788624487,"1024953201364":1509788624487,"1024953201365":1509788624487,"1019666528757":1478686804050,"1019666528759":1478686804050,"1019666528758":1478686804050,"1023845101769":1491634246537,"1024953201371":1509788624487,"1024953201368":1509788624487,"1012420094414":1478686417026,"1017595624534":1478686804053,"1023986137946":1509788624392,"1023986137947":1509788624392,"1023986137945":1509788624392,"1023986137948":1509788624392,"1023986137949":1509788624392,"1024953201406":1509788625202,"1023986137939":1509788624392,"1024953201407":1509788625202,"1024953201405":1509788625202,"1023986137942":1509788624392,"1024953201402":1509788625202,"1023986137943":1509788624392,"1024953201403":1509788625202,"1023986137940":1509788624392,"1023986137941":1509788624392,"1003256842201":1509788624286,"1024953201379":1509788624487,"1024953201376":1509788624487,"1021515056665":1478686417047,"1022081296929":1478686417061,"1022470266140":1478686417219,"1021323565377":1465470268210,"1021616377835":1478686417247,"1021673927293":1478686804032,"4990974830":1509788624155,"1021616377837":1478686417247,"1021955335088":1478686417261,"1016670627006":1478686804018,"1016879435855":1465470268267,"1021616377830":1478686417247,"1025906494991":1509788667463,"1020918669728":1478686417032,"1022204449529":1478686417064,"1025906494994":1509788667460,"940452409":1478950494919,"1025906494995":1509788667459,"1025710932982":1509788624309,"1025524421840":1509788624418,"1025524421841":1509788624418,"1022234596156":1478686417193,"1025524421847":1509788624418,"1025524421844":1509788624418,"1024773098476":1509788625069,"1025524421845":1509788624418,"1025524421803":1509788625099,"1024953200979":1509788624253,"1025524421807":1509788625099,"4954797330":1509788624155,"1024782011245":1509788625069,"1025524421805":1509788625099,"1024953200990":1509788624253,"1024953200988":1509788624253,"1025524421792":1509788625098,"1024953200989":1509788624253,"1024953200987":1509788624253,"1024953200984":1509788624253,"1022046954524":1478686417171,"1025524421797":1509788625098,"1024953200966":1509788624253,"1024953200967":1509788624253,"1025524421819":1509788625099,"1024953200964":1509788624253,"1025524421816":1509788625098,"1024953200965":1509788624253,"1020112179666":1509788625082,"1024953200962":1509788624253,"1025524421822":1509788625099,"1025524421823":1509788625099,"1025524421820":1509788625098,"1025524421821":1509788625098,"1025737277442":1509788625007,"1025524421810":1509788625099,"1024953200975":1509788624253,"1025524421811":1509788625098,"1024953200972":1509788624253,"1025737277446":1509788625084,"1025524421814":1509788625098,"1024953200971":1509788624253,"1024953200968":1509788624253,"1025679613429":1509788624349,"1025524421770":1509788624192,"1025524421771":1509788624193,"1025524421768":1509788624193,"1022288467881":1478686417198,"1025524421769":1509788624192,"1025524421772":1509788624193,"1025524421762":1509788624192,"1025524421760":1509788624193,"1025524421766":1509788624192,"1025524421765":1509788624192,"1024953200997":1509788624253,"1024953200994":1509788624253,"1024953200992":1509788624253,"1025524421789":1509788625098,"1025585765178":1509788624352,"484707998":1478686804029,"1022578394114":1480585069151,"4954797525":1509788624156,"1025524421738":1509788624192,"1025524421737":1509788624192,"1021535373863":1509788624397,"1024205546764":1509788625033,"1021673927396":1478686804032,"1020293979169":1465470268278,"1395802557":1444487341719,"1025524421755":1509788624193,"1021350305606":1478686417239,"1025524421758":1509788624193,"1020819980267":1478686417030,"1025524421745":1509788624192,"1025524421750":1509788624192,"1021259601314":1465470268200,"1024953201079":1509788624892,"1024953201076":1509788624891,"1027092380":1478686804024,"1021259601301":1465470268200,"1024953201087":1509788624891,"478940711":1444487341704,"1023741151743":1491634246523,"1018998051653":1509788624392,"1024953201082":1509788624892,"1024953201083":1509788624892,"1024953201080":1509788624892,"1018998051654":1509788624392,"1022205891175":1478686417013,"1024322858039":1509788667508,"749092454":1444487341699,"1020793503268":1480585069080,"1024953201111":1509788624892,"1024953201108":1509788624892,"1024953201109":1509788624892,"1021673927338":1478686804032,"1024953201107":1509788624891,"1024953201104":1509788624892,"1021328415180":1478686804065,"1024300576560":1509788624292,"1020447327558":1509788625078,"1024953201095":1509788624892,"1025783023444":1509788624297,"1024953201090":1509788624892,"1024953201091":1509788624892,"1017244469828":1478686804058,"1024953201088":1509788624892,"1024953201103":1509788624892,"1024953201100":1509788624892,"1024953201096":1509788624892,"795884945":1491634246504,"1021788091720":1509788624394,"1021154218909":1478686416981,"1025907281602":1509788667457,"1025907281604":1509788667458,"1025907281605":1509788667459,"1021673927313":1478686804032,"1022770426830":1509788624994,"1025907281606":1509788667459,"749092441":1444487341700,"1022204842950":1480585069085,"1022204842951":1480585069085,"1000527816688":1444487341714,"1022204842949":1480585069085,"1022238527936":1478686417194,"1022238527939":1478686417194,"1023561712364":1509788625097,"631387821":1478686804016,"1021013830357":1478686417001,"1022204842964":1480585069085,"1020339585795":1465470268323,"1020824698396":1509788624934,"1020824698399":1509788624934,"1020824698398":1509788624934,"1018998051569":1509788624324,"1018998051568":1509788624324,"1022204842972":1480585069085,"1018998051571":1509788624324,"1022204842973":1480585069085,"1000527816685":1444487341715,"1022204842969":1480585069085,"1021428023831":1478686804026,"1022204842980":1480585069085,"1024783452690":1509788625021,"1020824698401":1509788624934,"1021776688484":1509788624399,"1021988233470":1478686417154,"1022200048642":1478686417064,"1021567879662":1509788624867,"1022204842995":1480585069085,"1024334654657":1509788624997,"1022983552329":1509788625073,"1022204843007":1480585069085,"4990057046":1509788624155,"1022200048654":1478686417064,"1013685819342":1478686804068,"1022204842886":1480585069084,"1013801294057":1478686804028,"1013685819343":1478686804068,"1022204842887":1480585069084,"1013685819340":1478686804068,"1013685819341":1478686804068,"1013685819338":1478686804068,"1013685819339":1478686804068,"1013685819336":1478686804068,"1013685819337":1478686804068,"1022204842894":1480585069084,"1022204842890":1480585069084,"1013685819331":1478686804068,"1022042629569":1478686417268,"1022204842902":1480585069084,"1022204842901":1480585069084,"1022361082562":1478686417289,"1652191535":1444487341718,"1023927154027":1491634246529,"1022204842897":1480585069084,"1022438940072":1480585069104,"1013685819346":1478686804068,"1013685819347":1478686804068,"1013685819344":1478686804068,"1013685819345":1478686804068,"1023820985328":1491634246535,"1016577303346":1478686804065,"1021567879610":1509788624867,"478941159":1444487341706,"397804740":1444487341746,"1022204842930":1480585069085,"1022204842928":1480585069084,"1022204842929":1480585069085,"1021232338340":1478686417235,"1022204842943":1480585069085,"1022204842939":1480585069085,"1023659623757":1509788624849,"1022204842936":1480585069085,"1002004176752":1478686804033,"1024667845020":1509788625096,"1024667845021":1509788625096,"1024667845022":1509788625095,"1019740061273":1509788624313,"1025628233552":1509788624833,"1025628233553":1509788624823,"1024667845012":1509788625095,"1022412464107":1478686417208,"1024667845013":1509788625096,"1025628233556":1509788624745,"1021404562198":1478686417240,"1023577834112":1509788624379,"1023577834113":1509788624379,"1023577834114":1509788624379,"1022353611387":1478686417289,"1023577834115":1509788624379,"1023577834116":1509788624379,"1021015271992":1478686417231,"1023577834117":1509788624379,"1025628233551":1509788624828,"1023577834118":1509788624379,"1023577834119":1509788624379,"1019608331793":1509788625079,"150870882":1444487341741,"1019666529173":1478686804053,"1019666529172":1478686804053,"1020863619966":1509788625078,"1076646794":1444487341739,"1019666529175":1478686804053,"1019666529174":1478686804053,"1019666529177":1478686804053,"1024667845040":1509788625096,"1019666529176":1478686804053,"1024667845032":1509788625095,"1022643276055":1509788624368,"1024667845035":1509788625095,"1022251766188":1478686417066,"1024667845038":1509788625095,"1023782964577":1491634246535,"1024667845039":1509788625095,"1024667845026":1509788625095,"1024667845027":1509788625095,"1024899724185":1509788624334,"478941004":1444487341704,"1024667845081":1509788625096,"1024667845083":1509788625096,"1024667845084":1509788625096,"1024667845086":1509788625096,"1024667845074":1509788625096,"1024667845076":1509788625096,"1018554496430":1509788625080,"1021604712292":1478686416974,"1021038864809":1478686417035,"1024667845108":1509788625096,"1024667845109":1509788625096,"1024667845097":1509788625096,"1009770694680":1491634246513,"1024667845101":1509788625096,"1024667845103":1509788625096,"1024667845088":1509788625096,"1016499715848":1478686804018,"1022081297446":1478686417061,"1024902083588":1509788624946,"1021673927784":1478686804057,"1021673927783":1478686804057,"4956762989":1509788624155,"1025593630442":1509788625088,"1025200793205":1509788624392,"1025200793206":1509788624392,"1025593630440":1509788624425,"1025593630441":1509788624407,"1025593630435":1509788625116,"1021015272839":1478686417231,"1025200793214":1509788624392,"1025200793215":1509788624392,"1022355185116":1478686417203,"1025593630438":1509788624428,"1025593630439":1509788624431,"1023352787028":1509788625072,"1025593630436":1509788625125,"1025593630437":1509788625108,"1022021525991":1509788624180,"1022084967901":1509788624439,"435686861":1491634246504,"1022290825624":1478686417198,"1024002785276":1491634246532,"1021393296236":1478686417042,"1024002785270":1491634246532,"1019145379179":1509788624315,"1665431306":1444487341739,"1022245869088":1478686417066,"1021091424679":1478686417036,"1025896138818":1509788667403,"1024215641198":1509788667496,"1022768854443":1509788624317,"1021374159566":1478686416977,"4990057959":1509788624163,"1023354753238":1509788624533,"1020830202456":1478686417031,"1024215641185":1509788667496,"1021059575711":1509788624933,"1021957563675":1478686417147,"1021673927923":1478686804057,"1024206463748":1509788625033,"1021957563673":1478686417147,"1023782963785":1491634246535,"1022884723936":1509788667503,"1024215641165":1509788667495,"1021673927885":1478686804057,"1024215641167":1509788667496,"1018930145457":1509788624930,"1024215641156":1509788667495,"294651195":1444487341731,"1021871323136":1478686417136,"1024215641183":1509788667495,"1008105333654":1509788624383,"1022089162000":1509788625020,"1020202228967":1465470268243,"1021673927855":1478686804057,"1024215641134":1509788667496,"1019263337722":1509788624314,"1022204843010":1480585069085,"1022065697780":1478686417270,"1022204843008":1480585069085,"1024215641130":1509788667496,"1023628296483":1509788624346,"1001380917971":1478686804059,"1021345061077":1478686804023,"1022229222819":1478686417193,"1024215641150":1509788667496,"1006890679141":1478686804025,"1025200793216":1509788624393,"1024215641144":1509788667496,"1022269200325":1478686804049,"1024215641147":1509788667496,"1021673927856":1478686804057,"1023561057487":1509788625008,"1024215641139":1509788667496,"1020938723517":1478686417084,"1023262599994":1509788624450,"1021673927821":1478686804057,"1021884299522":1478686417257,"1021673927820":1478686804057,"1022229222806":1478686417193,"1023262599987":1509788624450,"1022084967684":1509788624190,"1023262599990":1509788624450,"1023262599991":1509788624450,"1023262599988":1509788624450,"1014683020236":1465470268313,"1565411770":1444487341739,"1001380917992":1478686804059,"1001380917995":1478686804059,"1024215641115":1509788667496,"1024215641109":1509788667496,"1024215641105":1509788667496,"1021652814509":1509788624420,"1009584183813":1478686804030,"4990057576":1509788624155,"1021687559347":1480585069059,"1022768854052":1509788624311,"1022226732171":1478686417281,"4990975080":1509788624155,"1001380918026":1478686804059,"1001380918021":1478686804059,"1017084828468":1444487341760,"1023354753407":1509788624816,"1021652814473":1509788624818,"1019739666672":1509788624173,"849094586":1491634246514,"1022473274861":1478943089531,"1020788653695":1478686416991,"1008664628416":1478686804023,"1022027292748":1478686417164,"1024794070994":1509788624989,"1002623624361":1491634246524,"1021949830480":1478686417145,"1025593630592":1509788624542,"1021949830484":1478686417145,"1025593630596":1509788624524,"1023933575823":1491634246529,"1021968574376":1509788624440,"1020294241265":1465470268299,"1021673927988":1478686804057,"1021673927987":1478686804057,"1021949830468":1478686417145,"1021078579343":1465470268305,"1022081297728":1478686417061,"1022225683695":1478686417192,"1023354753328":1509788624194,"1025569512759":1509788624350,"1004588299193":1444487341762,"1021949044085":1509788624355,"1000990972451":1444487341752,"849094430":1491634246514,"1024798265303":1509788624557,"1010150024384":1478686804015,"1022807257455":1490882721865,"1025513803800":1509788624451,"1024798265286":1509788624557,"1025513803802":1509788624451,"1025589828755":1509788624349,"1024798265290":1509788624557,"1025513803797":1509788624511,"1024798265291":1509788624557,"1025513803798":1509788624510,"1024798265292":1509788624557,"1020818929919":1509788625021,"1025513803817":1509788624435,"1025513803819":1509788624435,"1018618593063":1478686804026,"1025513803808":1509788624435,"1020957466765":1478686417085,"1025609489993":1509788624746,"1025593630590":1509788624540,"1025513803833":1509788624435,"1025593630591":1509788624537,"1023210170700":1509788624847,"1023627641249":1509788624277,"1020744612936":1509788624321,"1025609489987":1509788624828,"1025609489988":1509788624833,"1025609489989":1509788624823,"1021799494316":1478686417130,"1025577639009":1509788624926,"1023407313658":1509788624384,"1021410854392":1478686417007,"1023407313659":1509788624383,"1023407313656":1509788624384,"1023407313657":1509788624384,"1020934660443":1478686417083,"1020934660442":1478686417083,"1025513803849":1509788624455,"1023407313660":1509788624383,"1020845013552":1509788624368,"1023407313654":1509788624384,"1023407313655":1509788624384,"1021441656713":1478686417107,"1023407313653":1509788624384,"1019309213359":1509788624390,"1021015272568":1478686417231,"1023354753468":1509788624419,"1021722424943":1509788625069,"1020850649720":1478686804057,"1022226732148":1478686417281,"1021652814419":1509788624195,"1023606408539":1509788625178,"1023606408533":1509788625178,"1023606408529":1509788625178,"1024661554294":1509788625006,"1024206463368":1509788625033,"1023606408526":1509788625178,"1024686588654":1509788625083,"1023606408516":1509788625178,"1023606408518":1509788625178,"1022807257826":1490882721866,"1008244020930":1478686804028,"245242033":1444487341699,"1024686588616":1509788625083,"1022177372250":1478686417013,"1021779963907":1478686417254,"1025630853774":1509788624359,"1025630853775":1509788624359,"1025630853772":1509788624359,"1025630853773":1509788624359,"1021350960108":1509788624918,"1023606408479":1509788625177,"1023606408468":1509788625144,"1022081298030":1478686417061,"1021350960098":1509788624918,"1021350960126":1509788624918,"1023606408461":1509788625178,"1021350960125":1509788624918,"1021350960123":1509788624918,"1021350960122":1509788624918,"1021350960120":1509788624918,"1018600374245":1509788625017,"1146900998":1444487341726,"1021350960117":1509788624918,"1023606408448":1509788625178,"1025908329044":1509788667443,"1021350960114":1509788624918,"1021350960112":1509788624918,"1023606408508":1509788625178,"1022075793148":1509788624416,"4990058247":1509788624163,"1020447326690":1509788625076,"1023606408503":1509788625177,"1004329156651":1444487341749,"598619586":1444487341736,"1021350960095":1509788624918,"1023606408488":1509788625177,"1020893374317":1478686417079,"1000527815311":1444487341711,"1022200310129":1478686417280,"1021533539913":1478686417245,"4990058478":1509788624163,"1025714865970":1509788624438,"1025714865972":1509788624438,"1025714865974":1509788624438,"1020294240294":1465470268299,"1021063899730":1509788624940,"1025714865964":1509788624438,"1025714865966":1509788624438,"1023008319100":1509788625049,"1025714865967":1509788624438,"1021652814088":1509788624534,"1022354267990":1478686417289,"1022065566110":1478686417174,"1024899725028":1509788624335,"1024375035817":1509788624533,"1012082848503":1478950494940,"1021677860508":1478686417050,"1022261990830":1478686417284,"1021631056834":1509788624396,"1022674864671":1480585069062,"1024292973229":1509788667902,"1024576756615":1509788667500,"1022674864673":1480585069062,"1024576756617":1509788667500,"1025593629754":1509788624833,"1025593629755":1509788624823,"1025593629753":1509788624829,"1022263301564":1478686417067,"1025593629756":1509788624800,"2221707931":1491743595335,"1024576756625":1509788667500,"1024375035797":1509788625101,"1013139830208":1478686804027,"567162672":1478686804024,"1024576756632":1509788667500,"1023946944528":1491634246531,"1023606408284":1509788624827,"1023946944529":1491634246531,"1023946944530":1491634246531,"1021647571230":1509788624396,"1022019035903":1478686417011,"1022037254607":1509788624466,"1021340736327":1465470268224,"1021340736325":1465470268224,"1024461803860":1509788624427,"1023561058052":1509788625008,"1023316743573":1509788624301,"1023606408266":1509788624827,"1022029390407":1509788624461,"1024461803866":1509788624427,"1023606408258":1509788624849,"1004588298728":1444487341762,"1007164352612":1478686804017,"1023606408304":1509788624827,"1022452177189":1478686417215,"4987698811":1509788624163,"1023260240078":1509788624379,"1023260240076":1509788624379,"1023260240077":1509788624379,"1023260240074":1509788624379,"1023260240075":1509788624379,"1023606408297":1509788624827,"1023260240073":1509788624379,"1022372224496":1478686417204,"1021437068727":1509788624398,"1023210171333":1509788624550,"1022492149477":1478943089490,"1023606408215":1509788624847,"1023606408210":1509788624917,"1021830561380":1478686417133,"1023606408203":1509788624917,"1831238270":1444487341720,"1022062682137":1478686417060,"1021811425030":1478686417131,"1614706524":1444487341730,"1020261473245":1478686804026,"1023792007502":1509788624970,"1009004640986":1478686804064,"1020744613511":1509788624321,"1012126626031":1478686417025,"1020875024254":1478686417079,"1002327918837":1478686416993,"1017379092242":1478686804025,"1017379092247":1478686804071,"1023606408412":1509788625178,"1021961627335":1509788624464,"1025091353433":1509788624997,"1023606408401":1509788625177,"1021200094008":1465470268194,"110629131":1491634246518,"1021200094005":1465470268193,"1021200094007":1465470268193,"1021548875329":1478686417047,"1023606408441":1509788625178,"1020400796650":1478686804022,"1022237218132":1509788624301,"1023606408435":1509788625178,"1022237218124":1509788624288,"1023606408426":1509788625178,"1022237218113":1509788624288,"1022406695780":1480585069097,"1022237218116":1509788624288,"1019324023586":1509788624281,"1025630854000":1509788624359,"1022237218107":1509788624288,"1025630854001":1509788624359,"1025524028115":1509788624867,"1022237218108":1509788624288,"1022354923056":1509788624928,"1022354923057":1509788624928,"1022237218110":1509788624288,"1022237218111":1509788624288,"1012126756947":1478686416990,"1023606408334":1509788624846,"1023606408328":1509788624868,"1024215641914":1509788667496,"1022354923052":1509788624928,"1021384120328":1478686417042,"1009770695732":1491634246510,"1022354923053":1509788624928,"1021368916323":1478686416988,"1022354923054":1509788624928,"1022354923055":1509788624928,"1025630853998":1509788624359,"1025630853999":1509788624359,"1022354923050":1509788624928,"1025630853997":1509788624359,"1022354923051":1509788624928,"1022224242264":1509788624938,"1020974506447":1478686417086,"1025078639727":1509788624292,"1022065696968":1478686417175,"1025609489412":1509788624540,"1025609489413":1509788624542,"1025609489414":1509788624537,"1025609489415":1509788624523,"1020497134258":1478686804033,"1023647043317":1509788624442,"1021304165011":1478686417102,"1023647043318":1509788624442,"1023647043319":1509788624442,"1021490548081":1478686417111,"1023647043320":1509788624442,"1023647043323":1509788624442,"1025628624095":1509788624550,"1021596451591":1509788624397,"1021490548078":1478686417111,"1021304165007":1478686417102,"1022092042648":1478686417273,"1001800214279":1478686804023,"1021369964197":1478686417042,"1023260239826":1509788624380,"1021892949328":1478686417258,"1023260239827":1509788624380,"4954799995":1509788624163,"1523729123":1478686417024,"1024460758593":1509788625029,"1024005796697":1491634246515,"1025628624108":1509788624550,"1665432445":1444487341723,"1021014483430":1478686417089,"1021892949314":1478686417258,"1022629380519":1509788624195,"1025628624107":1509788624550,"1019033312179":1509788624388,"1020925619012":1478686417000,"1468420037":1478950494923,"1021892949305":1478686417258,"645676582":1491634246507,"1023210169510":1509788625140,"1025593758376":1509788625125,"1025593758377":1509788625107,"1025593758378":1509788625088,"1020471443549":1478686804033,"1020364622588":1478686804031,"1022430680346":1478686417302,"1020364622590":1478686804031,"1024794067711":1509788624989,"1021721377748":1478686804047,"1025593758375":1509788625115,"1021949044863":1509788624354,"1022780652267":1509788624816,"1025533468384":1509788624347,"1025533468387":1509788624347,"1025533468389":1509788624346,"1025533468396":1509788624346,"1025533468398":1509788624347,"1023260239728":1509788624380,"1523728989":1478686417024,"1023260239726":1509788624379,"1023260239727":1509788624379,"1022780652037":1509788624419,"1025533468402":1509788624346,"1023260239724":1509788624379,"1023260239725":1509788624379,"1023260239723":1509788624379,"1021033882153":1478686416986,"790378371":1444487341722,"1025533468358":1509788624347,"1025533468359":1509788624347,"1025533468360":1509788624347,"1018630910822":1509788625079,"1523729016":1478686417024,"1025533468363":1509788624347,"1021999639474":1478686417011,"1025533468371":1509788624346,"1025533468374":1509788624347,"1025533468375":1509788624347,"1025533468377":1509788624346,"1025533468379":1509788624346,"1021345060027":1478686804023,"1025533468383":1509788624347,"1021490548144":1478686417111,"1025703069845":1509788624455,"1025593889303":1509788625140,"1025593889300":1509788625139,"1021490548141":1478686417111,"1021490548143":1478686417111,"1019169756017":1509788624375,"1022203009084":1478686417190,"1020797826119":1478686417077,"1019958682190":1478686804021,"1021929781192":1478686417142,"1007134598629":1509788624374,"1021485698378":1509788624405,"1024122055277":1509788625086,"1022470395873":1478686417299,"1021490548097":1478686417111,"1021490548103":1478686417111,"1017826173636":1509788624311,"1004588302287":1444487341763,"1020364622747":1478686804034,"1021375338313":1478686417104,"1020364622721":1478686804034,"1022248360763":1478686804048,"1020294109119":1465470268290,"1022234204207":1478686417282,"1021096667101":1478686417094,"1021037552471":1478686417231,"1021467872741":1478686417045,"1022001475027":1478686417157,"1022780652500":1509788624194,"1024284190128":1509788624342,"1020564375498":1478686417026,"1020364622802":1478686804031,"1020364622815":1478686804034,"1012252325711":1478686417073,"1023647043495":1509788624226,"1023647043497":1509788624226,"1020364622799":1478686804026,"1023647043498":1509788624226,"1023647043499":1509788624226,"1023647043502":1509788624226,"1016399577001":1480585069070,"1021970541493":1478686417056,"1025654445123":1509788625004,"1025654445121":1509788625004,"1158569086":1509788625081,"1021020381202":1478686417035,"1021020381201":1478686417035,"896674820":1509788625019,"1021428156488":1478686804026,"1581795121":1491634246520,"1021428156494":1478686804026,"1020364622612":1478686804026,"1523729233":1478686417024,"1021601432921":1478686417246,"1024804422257":1509788625004,"1022127039200":1509788624338,"1022127039202":1509788624338,"1023647043425":1509788624863,"1023647043426":1509788624863,"1023647043427":1509788624863,"1020364622593":1478686804031,"1019287587647":1509788624376,"1024403872320":1509788625070,"1023647043429":1509788624863,"1021452274238":1509788624399,"1019287587586":1509788624376,"1022301707436":1478686417199,"1023647043422":1509788624863,"1024574657584":1509788624925,"1021668030840":1509788624400,"1018468513883":1478686804031,"1026232346910":1514456869770,"1026232346911":1514456869769,"1026225010400":1514456869772,"1018515570020":1509788624426,"1020364622680":1478686804040,"1016552142338":1478686804016,"1024375036088":1509788624194,"1022484285928":1509788624394,"430702708":1491634246508,"1021623452812":1478686417008,"1021955598405":1509788624508,"1020364622707":1478686804031,"1026225010382":1514456869772,"1020364622706":1478686804040,"1021623452805":1478686417008,"1021623452807":1478686417008,"1019287587648":1509788624376,"1022518758364":1509788625075,"1020364622714":1478686804034,"1744859632":1444487341717,"1026225010393":1514456869772,"1026225010394":1514456869772,"1207852554":1444487341707,"1026225010396":1514456869772,"1021396047590":1478686417006,"1026232346913":1514456869770,"1026232346915":1514456869769,"1026232346916":1514456869769,"1020945148930":1478686417229,"1013044659393":1465470268263,"1024789217501":1509788624568,"1009113950473":1478686804054,"1023880625889":1509788624939,"1024789217497":1509788625090,"1017505444582":1478686804016,"1024789217498":1509788624568,"1022880002702":1509788625073,"1025593757888":1509788624542,"1025593757889":1509788624537,"1025593757891":1509788624524,"1021741563496":1509788624403,"1024686329579":1509788624556,"1024686329576":1509788624556,"1024686329574":1509788624556,"1024686329575":1509788624556,"1024686329572":1509788624556,"1024300836838":1509788624281,"1024789217534":1509788624568,"1008105336076":1509788624381,"1022081425926":1480585069079,"1021995444585":1478686417265,"1024789217527":1509788624568,"1020956290940":1478686417085,"1022081425935":1480585069107,"1025067888654":1509788624298,"1021185939886":1465469681395,"1021341652598":1509788624180,"1024789217518":1509788624568,"1024789217512":1509788624568,"1024789217508":1509788624568,"1024789217509":1509788624568,"1024789217510":1509788624568,"1024789217511":1509788624568,"1024789217504":1509788624568,"1024789217506":1509788624568,"1022622172069":1480585069090,"1021603923711":1478686417008,"482870914":1478686804059,"1024540578244":1509788667549,"1004329159691":1444487341756,"1022209039063":1478686417013,"1020447329773":1509788624354,"1019386806961":1509788625077,"1025447615470":1509788624353,"1021831345019":1478686417256,"1025593757887":1509788624540,"1025538579636":1509788624273,"1022054952274":1478686417059,"993796529":1478686417024,"1022240626736":1478686417065,"1022476945947":1478943089315,"1022204844624":1480585069085,"1016854272841":1478686804019,"1014803488079":1478686804064,"1025593757806":1509788624428,"1025593757807":1509788624431,"1024135293308":1509788667494,"1021589242155":1509788624405,"1025593757808":1509788624425,"1025593757810":1509788624407,"1022622171951":1480585069142,"1021989939582":1478686417264,"1021354497886":1478686804040,"1022622171946":1480585069133,"1021981026544":1478686417151,"1023150924464":1509788624978,"1022622171954":1480585069142,"1022622171955":1480585069151,"1021262224834":1478686804039,"1025593757736":1509788624828,"1025593757737":1509788624833,"1025593757738":1509788624823,"1021986138391":1478686417153,"1025593757740":1509788624746,"1021310456031":1478686417005,"1026226583003":1514456869770,"1744859886":1444487341746,"1000528604705":1444487341710,"1022053117185":1478686417172,"1021984958742":1478686417152,"1016623180141":1478686804020,"1015996650506":1465470268314,"1024156790420":1509788667855,"1025162521500":1509788624268,"1022474980270":1478943089486,"1025162521502":1509788624268,"1008732653258":1478686804033,"1523728853":1478686417024,"1025162521494":1509788624269,"1022076576612":1509788624190,"1008107432967":1478686804030,"1019133448948":1509788624314,"1024794067334":1509788624989,"1024055997833":1509788624928,"1022622171898":1480585069142,"1025881325753":1509788667465,"1021961628271":1509788625009,"397806747":1444487341717,"1022033194540":1478686417166,"1025162521521":1509788624268,"1019133448917":1509788624314,"1025538579716":1509788624181,"1025162521505":1509788624268,"1012936002660":1478686416995,"1025162521563":1509788624268,"1021948128127":1478686417144,"1025162521559":1509788624268,"1024899726196":1509788624334,"1021394343019":1478686417105,"1022847892978":1509788624377,"1024412784716":1509788625007,"1021809193748":1478686417131,"1020907661643":1478686417032,"1017808609665":1478686804016,"1019033311367":1509788624374,"1021354497762":1478686804033,"1017808609675":1478686804016,"1021473902338":1509788624816,"1025162521575":1509788624268,"1017808609677":1478686804016,"1017808609655":1478686804016,"1587299606":1444487341747,"1008664363628":1478686804034,"1016517932616":1509788624284,"1023105314465":1509788624551,"1007095537881":1478686804032,"1001644764640":1444487341702,"1020784586949":1478686804071,"1171021411":1478686804033,"1023889539020":1491634246528,"1023889539021":1491634246530,"1021833048742":1509788625069,"1018106745011":1509788625079,"1018106745010":1509788625080,"1008540109562":1478686804064,"1019413283479":1509788624317,"1020220052210":1478686804065,"1021210845133":1465470268195,"1021210845132":1465470268195,"1022286241342":1509788624930,"1024789217543":1509788624568,"1020910413872":1478686417080,"1019332284355":1478686804039,"1024789217538":1509788624568,"1016399707415":1480585069069,"1024789217539":1509788624568,"1021531439898":1509788624401,"714486112":1444487341735,"1021465775885":1478686417108,"1021771053733":1478686417052,"1021771053732":1478686417052,"1022374581934":1478686417290,"1025415488376":1509788624346,"1008056313901":1480585069065,"1010659511546":1509788625017,"1020941608979":1478686417084,"1021626466666":1509788624971,"1022413639744":1509788624923,"1022242463421":1478686417195,"1022501719412":1509788624504,"1021567878815":1509788624454,"1022501719420":1509788624504,"1022501719421":1509788624504,"1020997969055":1478686417034,"1022501719422":1509788624504,"1022501719423":1509788624504,"1022501719416":1509788624504,"1022501719418":1509788624504,"1022501719419":1509788624504,"1022501719399":1509788624504,"1022501719404":1509788624505,"1022501719405":1509788624504,"1013210870946":1478686804015,"1022501719407":1509788624504,"1013210870949":1478686804015,"1013210870948":1478686804015,"1022501719401":1509788624505,"1022501719402":1509788624504,"1018823715374":1465470268247,"1025714867667":1509788624844,"1025714867669":1509788624844,"1013210870943":1478686804015,"1025714867671":1509788624844,"1021011862924":1478686417231,"1021826757895":1478686417133,"1025350346546":1509788625083,"1021567878818":1509788624455,"1024375168277":1509788625031,"1020817748247":1509788625021,"1023431824672":1509788624519,"1022460564224":1478686417016,"1023098235151":1509788625046,"1014666240687":1465470268253,"1021567878731":1509788624453,"1021949832323":1478686417145,"1023106754981":1509788624264,"1020581151534":1480585069077,"1023386999517":1509788625040,"1021567878770":1509788624454,"1024005273382":1491634246533,"1022501719428":1509788624504,"1022501719430":1509788624504,"1022501719424":1509788624504,"1022501719425":1509788624504,"1025671746202":1509788624942,"1021118161713":1465470268312,"1024005273385":1491634246533,"1022413639859":1509788624923,"1019225461426":1509788624354,"1352289347":1478950494922,"1012420093127":1478686417026,"1022828230996":1509788624981,"1022220180750":1478686417192,"1022220180747":1478686417192,"1022208646556":1480585069087,"1025118613544":1509788625022,"1544700161":1491634246533,"1021300758460":1478686416989,"1025715522713":1509788624453,"1018478608323":1509788624372,"1016106223976":1478686804046,"1022454141645":1478686417016,"1025615386286":1509788625021,"1022014581006":1509788625067,"1012672158249":1478686417224,"4954798688":1509788624156,"1025711590654":1509788624308,"1009078430830":1478686804023,"1021240728346":1478686417003,"1019033312948":1509788624388,"1022110394149":1478686417182,"1025900331475":1509788667465,"1025900331473":1509788667457,"1025900331477":1509788667460,"1009770694296":1491634246510,"1025385078831":1509788624821,"1021746674097":1478686417126,"1024381721728":1509788624346,"1021337850138":1478686417005,"1025715522582":1509788624438,"1025715522583":1509788624438,"1019035016775":1509788624287,"1009965349854":1491634246523,"1016681114526":1478686804018,"1020596108595":1478686804071,"1025715522589":1509788624438,"1020596108597":1478686804071,"1025715522586":1509788624438,"1020596108596":1478686804071,"1019035016776":1509788624287,"1020596108599":1478686804071,"1020596108598":1478686804071,"1023153022438":1509788625045,"1004588301154":1444487341762,"1022071858555":1509788624971,"1023603658440":1509788625071,"1021327890111":1465470268218,"1012187313738":1478686417025,"1020064603587":1509788624372,"1013902085137":1478686804071,"1021714038710":1509788624396,"1022314028027":1478686417068,"1012115880935":1478686417223,"1022031620346":1509788624463,"1021567878929":1509788624454,"1021567878931":1509788624455,"231084053":1478686417019,"1023821249968":1491634246535,"1020365148042":1478686804026,"1012476715339":1444487341761,"1024463248346":1509788625029,"1022013925852":1478686417159,"1009839374861":1491634246523,"1021645079513":1478686417248,"1019717514996":1509788624312,"1008105335085":1509788624376,"1021995707738":1509788624463,"1022028082042":1478686417267,"1023617026736":1509788624970,"1025620759841":1509788624970,"1020220053305":1478686804039,"1022028082044":1478686417267,"363858858":1491634246534,"1019369507289":1509788624375,"1019369507290":1509788624375,"1022473277156":1478943089531,"1022473277157":1478943089531,"1021887443958":1509788624465,"363858822":1491634246510,"1022921815115":1509788624293,"583941249":1478686804024,"1022921815129":1509788624293,"1022238792851":1509788624947,"1022238792852":1509788624932,"1022149976666":1509788624439,"1022238792853":1509788624941,"1022238792855":1509788624931,"1022238792856":1509788624931,"1022238792857":1509788624931,"1022921815121":1509788624293,"1022208646881":1480585069087,"1022921815141":1509788624293,"1019082594457":1509788625079,"1021969624241":1478686417056,"1025274849603":1509788624233,"1021156712396":1478686417097,"1179146457":1480585069063,"1021251344682":1478686417100,"1022333688239":1478686417201,"1022077495013":1478686417177,"1523729484":1478686417024,"1025330684983":1509788624526,"1021693460451":1509788624400,"1025330684981":1509788624526,"1025330684978":1509788624526,"1020845142356":1478686417226,"1022208646731":1480585069087,"1022780652627":1509788624533,"1020391885373":1478686804022,"1025714605924":1509788624549,"1021965299673":1509788624464,"1171020564":1478686804033,"1025714605935":1509788624549,"1025714605930":1509788624549,"1025620760011":1509788624932,"1025620760005":1509788624946,"1025620760007":1509788624941,"1021887836995":1478686417054,"1025274849594":1509788624233,"1025274849599":1509788624233,"1021933580775":1478686417055,"1025274849586":1509788624234,"1025274849587":1509788624233,"1024077492689":1509788667463,"1025274849585":1509788624234,"1025274849590":1509788624585,"1000456122428":1478686804064,"1025007466714":1509788624978,"1019287588271":1509788624376,"1021976964474":1478686417056,"1025274849484":1509788624233,"1021832656415":1478686804035,"1023098104479":1509788624433,"1025274849490":1509788624233,"1019287588272":1509788624376,"1021679435556":1478686417050,"1025274849518":1509788624234,"1012140390278":1478686417073,"1323848135":1478950494922,"1021832656417":1478686804035,"1021832656416":1478686804035,"1023062977685":1509788625073,"1021832656418":1478686804035,"1024350920651":1509788624565,"1018513472397":1509788624602,"1021262223446":1478686804039,"1024350920635":1509788624552,"1018513472392":1509788624602,"1018513472389":1509788624603,"1022234336840":1478686417014,"1018546502054":1480585069070,"1024350920622":1509788624564,"1018513472411":1509788624602,"1023888751409":1491634246517,"1018513472406":1509788624602,"1018513472402":1509788624602,"1018513472401":1509788624602,"1018513472428":1509788624602,"1021324088353":1465470268212,"1021324088352":1465470268212,"1021324088354":1465470268213,"1018513472424":1509788624602,"1018513472421":1509788624602,"1018513472418":1509788624602,"1021775509779":1509788624994,"1018513472416":1509788624602,"1021315568827":1478686417238,"1021775509772":1509788624994,"1017927311020":1478686804033,"1021775509774":1509788624994,"1022430810682":1478686417212,"1021775509769":1509788624994,"1021775509768":1509788624994,"1021775509771":1509788624994,"1023617027011":1509788624970,"1021775509764":1509788624994,"1021775509766":1509788624994,"1021447949415":1478686417007,"1016982198192":1478686804042,"1016982198193":1478686804042,"1022012091328":1478686417159,"4990056168":1509788624155,"443418082":1478686804029,"1012115880360":1478686417223,"1004588300615":1444487341762,"1021984173154":1509788624463,"1021197867867":1464448510787,"1020847108162":1478686417226,"1024214984833":1509788625033,"1020975950244":1478686417087,"1022167540390":1509788624300,"1019287588123":1509788624376,"1018513472383":1509788624603,"1022455189577":1478686417297,"1018513472380":1509788624603,"1021735271282":1509788667538,"1019287588124":1509788624376,"1018513472375":1509788624603,"1021661200535":1478686804046,"1022430810869":1509788624385,"1018513472368":1509788624603,"1024660245933":1509788624531,"1024660245934":1509788624531,"1009210287792":1480585069067,"1009210287793":1480585069067,"1024660245931":1509788624531,"1024660245924":1509788624531,"1021047514120":1478686417092,"1024660245926":1509788624531,"1024660245927":1509788624531,"1024660245922":1509788624531,"1025671746029":1509788624942,"1022780652865":1509788625101,"1009210287778":1480585069067,"1021492513416":1509788624853,"1009210287788":1480585069067,"1009210287789":1480585069067,"1021492513412":1509788624853,"1024660245936":1509788624531,"1021492513411":1509788624853,"1024660245937":1509788624531,"1021492513408":1509788624853,"1020305117673":1478686804026,"1025628623678":1509788624846,"1024660245916":1509788624531,"1024660245918":1509788624531,"1023098104444":1509788624424,"1025628623660":1509788624846,"1024660245911":1509788624531,"1024660245904":1509788624531,"1024660245906":1509788624531,"1024660245907":1509788624531,"1253468851":1444487341753,"1018267186591":1478686804018,"4918215981":1509788624157,"1026226835203":1514456869769,"1017895247792":1465470268262,"1021500126959":1478686417007,"1023030071698":1509788625048,"1023021944855":1509788625049,"1019728645211":1509788624313,"1019728645210":1509788624315,"1018604947793":1478686804024,"1025615391669":1509788625021,"1008666474995":1478686804030,"1023926486546":1491634246528,"1023926486547":1491634246530,"267136976":1491634246534,"1025560471684":1509788625021,"1022237221558":1478686417194,"1022427016647":1478686417070,"1011572451029":1478686416993,"1021680074836":1478686804032,"1019053761754":1509788624313,"1006370975982":1478686804032,"1019560870423":1509788624317,"1022150761588":1478686417063,"1020905034432":1478686416999,"1022195458032":1478686417189,"1021419778337":1478686417043,"1023076340845":1509788624419,"1025806104253":1509788667463,"1021419778350":1478686417043,"1001059922843":1478686417022,"1024680440829":1509788624489,"1020076269834":1509788624170,"1024680440808":1509788624434,"1158571454":1509788625081,"1021484266860":1478686417046,"1021554391351":1478686417048,"1021169033807":1478686417234,"1725842962":1444487341705,"1023076340793":1509788625100,"1024640987490":1509788667538,"1021479154905":1478686417243,"1158571474":1509788625081,"1012321129278":1478686804062,"1012140116046":1478686416994,"1021715071731":1509788624817,"1023889654931":1491634246528,"1020807777506":1478686416998,"1021715071725":1509788624533,"1021393956412":1478686417105,"1021681910041":1509788624396,"4918215725":1509788624157,"1025615391381":1509788625021,"1023561330912":1509788625097,"1021454512793":1478686417107,"1022205895115":1478686417191,"1022438944748":1480585069104,"1024637710555":1509788667502,"1021393956383":1478686417105,"1024690140548":1509788624486,"742001950":1444487341751,"1024690140547":1509788624485,"1002452174605":1491634246516,"1025680141960":1509788624350,"1023561330886":1509788625097,"1025147440713":1509788624456,"1022447857510":1480585069121,"1652179799":1444487341718,"1002452174601":1491634246516,"4980214262":1509788624157,"1019941640320":1509788624930,"1002452174614":1491634246516,"1023561330909":1509788625097,"1023561330910":1509788625098,"1002452436744":1491634246509,"1008294355674":1480585069074,"1020964411362":1478686417085,"1158571060":1509788625081,"1021715071776":1509788624194,"1007022659309":1478686804015,"1019963398946":1478686804021,"1019963398945":1478686804032,"1023561330862":1509788625097,"1025147440673":1509788624511,"1018805490723":1509788624928,"1000990977561":1444487341750,"1022356367510":1478686804071,"1022356367511":1478686804071,"1025147440680":1509788624512,"1025616177884":1509788624929,"1025147440685":1509788624466,"1023561330878":1509788625097,"1022489145511":1478943089489,"1023561330872":1509788625097,"1025438966100":1509788624293,"1023561330874":1509788625097,"1023927404386":1491634246529,"1025147440698":1509788624441,"1021474043182":1509788624816,"1023561330871":1509788625098,"1025909521741":1509788667458,"1021606165963":1509788624404,"1023561330866":1509788625097,"1023561330830":1509788625097,"1524267966":1444487341754,"1023561330824":1509788624531,"1023485832478":1509788624252,"1024512403502":1509788625028,"1524267945":1444487341742,"1022037252018":1509788624462,"1019315253876":1509788625079,"1025874131783":1509788667833,"1022977904552":1509788625050,"1021445469045":1478686417044,"1021599350144":1478686417115,"1023561330834":1509788625098,"1023561330835":1509788624531,"1025406967403":1509788624466,"1021845228503":1480585069082,"2024692004":1491822860485,"1158571140":1509788625081,"1021845228505":1480585069082,"1022277068054":1478686417067,"1021845228506":1480585069082,"849089299":1491634246514,"1021845228485":1480585069082,"1021845228487":1480585069082,"1025524164474":1509788625143,"1004330350512":1444487341753,"1024690140478":1509788624485,"1021845228489":1480585069082,"1025406967414":1509788624507,"1021845228491":1480585069082,"1018553567220":1478686804022,"1021845228535":1480585069082,"1021845228543":1480585069083,"1021845228539":1480585069083,"1021327239834":1478686417103,"1021845228538":1480585069083,"1021616258117":1478686417116,"1021616258115":1478686417116,"1025592847177":1509788624930,"1024690140518":1509788624485,"1024690140519":1509788624485,"1207854650":1444487341708,"1022872782558":1509788625073,"1022065694461":1478686417270,"1024690140521":1509788624485,"1024690140523":1509788624485,"1021693706376":1480585069067,"1021057735410":1478686417036,"1024690140531":1509788624485,"1014129508320":1478686804019,"1024690140541":1509788624485,"1024690140537":1509788624485,"1021845228468":1480585069082,"1024690140485":1509788624486,"1024781367479":1509788624437,"1022237221661":1478686417194,"1021497373946":1478686417046,"1021845228478":1480585069082,"1021845228472":1480585069082,"1021845228474":1480585069082,"1024690140491":1509788624486,"1019596522927":1509788624942,"1024690140503":1509788624486,"1021845228449":1480585069082,"1024690140496":1509788624486,"1024690140499":1509788624486,"1024690140508":1509788624485,"1024690140509":1509788624485,"1022017328621":1478686417160,"1021845228462":1480585069082,"1024690140511":1509788624485,"1001800212199":1478686804029,"1021845228456":1480585069082,"1011772601165":1478686804024,"1023288173140":1509788624354,"1022384547889":1478686417205,"1024690140839":1509788624890,"1024690140832":1509788624890,"1021016316859":1478686417001,"1024690140844":1509788624890,"1022156005339":1509788624958,"1024147083528":1509788625035,"1024690140847":1509788624890,"1024690140855":1509788624890,"1024690140848":1509788624890,"1012980316330":1465470268318,"1024953845499":1509788625140,"1022097021771":1509788624190,"1024690140804":1509788624890,"1024690140801":1509788624890,"1024690140812":1509788624890,"1024690140813":1509788624890,"1020993246519":1478686417230,"1024690140815":1509788624890,"1024690140810":1509788624890,"1021137969741":1478686417096,"1023853084857":1491634246515,"1024690140822":1509788624890,"1024690140823":1509788624890,"1021907094705":1478686417140,"1024690140816":1509788624890,"1021920857570":1509788625009,"1017050885664":1478686804016,"1024690140828":1509788624890,"1024690140826":1509788624890,"1004588287114":1444487341762,"1021368528096":1478686417042,"1158571853":1509788625081,"1008207699834":1478686804064,"1021352669153":1465470268226,"1023734872550":1509788624969,"1021465261739":1478686417300,"1021847586917":1509788624423,"1020768716857":1478686417076,"1021887303563":1478686417137,"1024460629010":1509788625029,"1025628499639":1509788625242,"1103782829":1478686804033,"1021352669149":1465470268225,"1023996872827":1509788624509,"1021352669151":1465470268226,"1021262226789":1478686804039,"1025715008502":1509788625137,"1025715008500":1509788625137,"1025715008501":1509788625137,"1025715008498":1509788625137,"1025715008496":1509788625137,"1025715008497":1509788625137,"1022770545546":1509788625074,"1025715008267":1509788624549,"1020161074224":1465470268316,"1025715008261":1509788624549,"1025715008258":1509788624549,"1020219665335":1509788624287,"1021555047183":1509788624397,"1025715008256":1509788624549,"1019674118963":1509788625077,"1020219665334":1509788624287,"1021770122306":1509788624919,"1021602496062":1509788624408,"1021888352052":1509788624465,"1025855912892":1509788667402,"1010863341147":1478686804049,"1021519787303":1478686417047,"1837518623":1491634246514,"4892918023":1509788624156,"1021019200314":1478686417035,"1024264788149":1509788624490,"1019675560741":1464448510786,"1021686891284":1509788624400,"1021655055678":1509788624400,"1008828334211":1478686804071,"2470228361":1517735696525,"1001059922317":1478686417022,"1022438812749":1480585069100,"1021693182970":1478686417249,"1023254207640":1509788624376,"1023097837387":1509788625046,"1024781368220":1509788625177,"1025676209450":1509788624296,"1021994914204":1478686417011,"1021770122291":1509788624919,"1021770122290":1509788624919,"1021770122289":1509788624919,"1021770122295":1509788624919,"1021770122294":1509788624919,"1021770122293":1509788624919,"1021770122292":1509788624919,"1021770122299":1509788624919,"1021770122298":1509788624919,"1021770122297":1509788624919,"1021770122296":1509788624919,"1021770122303":1509788624919,"1025616177534":1509788624929,"1024781368248":1509788625176,"1024781368251":1509788625176,"1022952214184":1509788625051,"1021770122278":1509788624919,"1024781368227":1509788625177,"1020945143558":1478686417033,"1021770122281":1509788624919,"1021770122280":1509788624919,"1021770122286":1509788624919,"1023881529332":1509788625095,"1021466572751":1478686417108,"1021385174180":1478686417105,"1022447463803":1478686804071,"2024692645":1491822860484,"1022447463804":1478686804071,"1022447463805":1478686804071,"1023881529313":1509788625095,"1023881529320":1509788625095,"1021665147955":1478686416975,"1023881529300":1509788625095,"1022234206754":1478686417065,"1023881529298":1509788625095,"1022622186176":1509788625061,"1023881529296":1509788625095,"1023881529297":1509788625095,"1021665147961":1478686416975,"1023881529309":1509788625095,"1025078626480":1509788624292,"1023881529307":1509788625095,"1023881529304":1509788625095,"1023881529294":1509788625095,"1023881529295":1509788625095,"1023881529292":1509788625095,"1023881529293":1509788625095,"1013367624386":1444487341759,"1025044679372":1509788624569,"1021630676567":1509788624401,"1010091953554":1491634246522,"1019841761476":1509788625080,"1021989277898":1478686417155,"1024953845661":1509788624550,"1024553299902":1509788624279,"1024953845662":1509788624550,"1021466572733":1478686417108,"1024953845658":1509788624550,"1018882300297":1509788624941,"1024737588363":1509788625021,"1006370976522":1478686804032,"1025650519750":1509788624435,"1023820055334":1509788624393,"1025514595892":1509788624340,"1021881536443":1509788624496,"1010091953521":1491634246522,"1022447463881":1478686804064,"1022447463882":1478686804054,"1022081162142":1478686417272,"1022447463883":1478686804054,"1022447463884":1478686804054,"1022447463885":1478686804054,"1022447463886":1478686804054,"1023485833133":1509788624905,"1021770253674":1478686417009,"1022838310601":1509788624426,"1025715008064":1509788625167,"1008105329907":1509788624391,"1022279690134":1478686417014,"1016483055639":1478686804031,"1016483055640":1478686804031,"1024953845504":1509788625140,"1025084786899":1509788624293,"1016075825620":1509788624944,"1020436461021":1480585069076,"628885132":1491634246534,"1018490126763":1478686804066,"1025084786885":1509788624293,"1024292970382":1509788667902,"1018490126764":1478686804066,"1024292968562":1509788667903,"1024292968565":1509788667903,"1024292968568":1509788667902,"1024681096999":1509788624489,"1024292968572":1509788667902,"1021246628842":1478686417003,"1021246628841":1478686417003,"1024292968544":1509788667902,"1001059923754":1478686417022,"1024292968547":1509788667903,"1024292968548":1509788667903,"1024292968550":1509788667902,"1024292968554":1509788667903,"1024292968559":1509788667902,"1025098287186":1509788624293,"1022192573346":1478686417301,"1024292968531":1509788667902,"1021493833997":1509788624398,"1024292968535":1509788667903,"1022122450943":1478686417013,"1021723461551":1509788624395,"1024292968518":1509788667902,"1024292968523":1509788667903,"1024689352848":1509788624566,"1021680075845":1478686804057,"1021259342696":1465470268199,"1024680310544":1509788625025,"1020462677234":1465470268258,"1021500387986":1478686804033,"1024280518486":1509788625082,"1025429398765":1509788625171,"1025429398762":1509788625171,"1019723401458":1478686804021,"1022253606812":1478686417014,"4856349968":1509788624157,"1023146466511":1509788625072,"1023947590793":1491634246532,"1023452147228":1509788625082,"1021791486748":1478686417052,"1023821235225":1491634246535,"1021596467059":1509788624419,"1010863339696":1478686804049,"1025884356585":1509788667467,"1018486195945":1480585069063,"1022049964680":1478686417059,"1021680075908":1478686804057,"1021174671033":1478686417098,"1023076339808":1509788624533,"1022037250653":1509788624462,"327563043":1444487341750,"1021038993130":1478686417232,"1021646535352":1509788624396,"1021680075963":1478686804057,"1018468893985":1509788624427,"1022239450731":1478686417283,"1021051182916":1478686417036,"1025616310080":1509788624929,"1020918667074":1478686417032,"1020934000733":1478686417228,"1021680075985":1478686804057,"1016881276650":1478686804063,"1004588286486":1444487341761,"1020936097922":1465470268183,"1023989665416":1509788625037,"1018447922233":1509788624933,"1023889653896":1491634246528,"1023889653897":1491634246528,"1024292968579":1509788667903,"1024292968580":1509788667903,"1021445732080":1478686417107,"1021393300435":1478686417043,"1024689352744":1509788624551,"1023889653895":1491634246528,"1021502616487":1509788625004,"1021502616486":1509788625004,"1021402215860":1478686417240,"1021556620386":1478686416978,"1021556620388":1478686416978,"1024661829476":1509788625026,"1021402215855":1478686417240,"1021680076076":1478686804057,"1020781825695":1478686417029,"1020781825693":1478686417029,"1021051969200":1478686804059,"1022238664687":1509788624931,"1020867548591":1478686417227,"1020781825679":1478686417029,"1025514594490":1509788624341,"1022053372550":1509788625066,"1021984691892":1478686417152,"1019988826541":1509788624375,"1024910591191":1509788624276,"1023076340131":1509788624816,"1022944872946":1509788625074,"1021680076116":1478686804057,"1024672970487":1509788624434,"1025341300373":1509788624506,"1025341300374":1509788624506,"1025341300375":1509788624506,"1020462677465":1465470268259,"1025341300382":1509788624506,"1022812094943":1509788624198,"1025341300383":1509788624506,"1025341300376":1509788624506,"1025341300377":1509788624506,"1020934001131":1478686417228,"1025341300379":1509788624506,"1009744493799":1491634246512,"1022675007932":1509788625058,"1020294245161":1465470268299,"1019121659149":1509788624314,"1020111005234":1509788625081,"1019723401532":1478686804021,"1021818358867":1478686417132,"1014953044641":1509788624467,"1025909127604":1509788667463,"1019841762835":1509788625080,"1022486787500":1478943089489,"1022327923238":1478686417200,"1023878645438":1491634246506,"1005797247774":1480585069074,"1021596466894":1509788624817,"1010386737796":1509788624277,"1020219665625":1509788624286,"1019082466048":1509788625079,"1020219665627":1509788624286,"1020219665626":1509788624286,"1021551770675":1478686417047,"1021112392195":1478686417095,"1020219665629":1509788624286,"1020219665628":1509788624286,"1021068220781":1478686417002,"1022418889193":1478686417293,"1008901341747":1478686804030,"1011418552354":1478686804025,"1021551770669":1478686417047,"1023830804475":1509788624434,"1022474729152":1478943089486,"1022474729154":1478943089486,"1021845228608":1480585069083,"1022204847839":1480585069085,"1025712912308":1509788624306,"1021909321851":1478686417259,"1021989017018":1478686417154,"1021299322081":1478686417041,"1158570793":1509788625081,"1021299322095":1478686417041,"1022036988155":1478686417267,"1021845228561":1480585069083,"1021845228563":1480585069083,"1021845228562":1480585069083,"1023431962601":1509788624516,"1023431962606":1509788624516,"1022956145234":1509788625018,"1023431962604":1509788624516,"1021845228549":1480585069083,"1023431962610":1509788624516,"1021647059028":1509788624396,"1023431962608":1509788624516,"1021845228550":1480585069083,"1021845228546":1480585069083,"1021845228557":1480585069083,"1022238794904":1509788624932,"1025627581085":1509788624186,"1022898736947":1509788624402,"1021845228559":1480585069083,"1021845228558":1480585069083,"1025627581081":1509788624200,"1021845228555":1480585069083,"1025627581082":1509788624204,"1025627581083":1509788624197,"1021845228597":1480585069083,"1021437998334":1478686417107,"1021337987827":1465470268219,"1021845228599":1480585069083,"1021845228598":1480585069083,"1021337987829":1465470268220,"1007198840628":1478686804032,"1017108166358":1478686804058,"1021845228593":1480585069083,"1021337987828":1465470268220,"1021845228595":1480585069083,"1021337987830":1465470268220,"1021845228594":1480585069083,"1021845228605":1480585069083,"1021845228606":1480585069083,"1023485831680":1509788624586,"1021845228600":1480585069083,"1021845228603":1480585069083,"1021845228602":1480585069083,"1019674120139":1509788625077,"1021845228589":1480585069083,"1021987444134":1478686417057,"1021845228591":1480585069083,"1022474729134":1478943089486,"1020792049055":1478686804057,"1021496325003":1478686417046,"1008901341525":1478686804034,"1020462677553":1465470268259,"404373129":1478686804029,"1020987347418":1478686417088,"4980215419":1509788624158,"1025330682933":1509788624408,"1025330682930":1509788624426,"1025330682928":1509788624429,"1025330682929":1509788624432,"1009304000887":1478686804024,"1025513939748":1509788624296,"1020929413754":1478686417033,"1021727917463":1478686417123,"1017379079854":1478686804016,"1018604949437":1478686804024,"1021721363837":1478686804047,"1018630376741":1465470268320,"1021987575047":1478686417057,"1022498977722":1509788624940,"1021860957601":1509788624992,"1025630595660":1509788624309,"1158570993":1509788625081,"1008730176233":1478686804034,"1022390840533":1478686417206,"1021710091599":1478686417250,"1012104331770":1478686417025,"1018651610023":1478686804018,"1023076340713":1509788624194,"1022399753230":1478686417207,"1015449930307":1478686804029,"1023989665091":1509788625071,"1158570532":1509788625081,"1158570556":1509788625081,"1023946407982":1491634246531,"1023946407983":1491634246531,"1022242334130":1478686417066,"1026232342496":1514456869770,"1020954186289":1478686417085,"1021959525927":1509788624898,"1021959525926":1509788624897,"1009109750798":1465470268239,"1022483642221":1478943089488,"1025513939654":1509788624295,"1021959525928":1509788624898,"1021445338433":1478686417107,"1021959525931":1509788624898,"1024680440842":1509788624590,"1871333593":1444487341709,"1158570589":1509788625081,"1021632248255":1509788624400,"1024680440846":1509788624426,"1008002962970":1478686804030,"1021754393338":1478686416972,"1022377209308":1478686804069,"1021754393340":1478686416972,"1021959525893":1509788624898,"1021959525892":1509788624898,"1021959525895":1509788624898,"1021959525891":1509788624898,"1021354633968":1465470268235,"1022014837598":1478686417266,"1021959525890":1509788624897,"1021959525901":1509788624898,"1021959525900":1509788624898,"1021959525903":1509788624898,"1022898212601":1509788624402,"1021959525902":1509788624898,"1889425392":1478950494928,"1021959525899":1509788624898,"1021959525908":1509788624898,"1021959525911":1509788624897,"1021959525906":1509788624898,"1021354633966":1465470268235,"1021959525916":1509788624898,"1021354633965":1465470268234,"1021959525918":1509788624898,"1021959525912":1509788624897,"1021959525914":1509788624898,"1021622549017":1478686417117,"1025908210573":1509788667459,"1024300571250":1509788624298,"1021626219208":1478686417008,"1022215202744":1478686417281,"1022204847956":1480585069085,"1023173861015":1509788625043,"1022486001552":1478943089489,"1025908472728":1509788667449,"1022095580905":1509788624190,"1025330683188":1509788624525,"1025330683189":1509788624526,"1025330683184":1509788624526,"1022987995537":1509788625050,"1025288999096":1509788624286,"1025330683193":1509788624525,"1524268394":1444487341730,"1019841762324":1509788625080,"1025330683183":1509788624526,"1025330683181":1509788624526,"1025330683179":1509788624526,"1024452370767":1509788667888,"1025628367642":1509788624828,"1025628367643":1509788624832,"1025628367644":1509788624823,"1025628367645":1509788624746,"1017108166517":1478686804058,"1018245821199":1509788625078,"1652180407":1444487341753,"1009326106528":1478686804024,"1025616178271":1509788624929,"1022085094950":1509788624281,"1020462677868":1465470268259,"1022234207952":1478686417065,"1021590830265":1478686417114,"1021693707911":1480585172193,"1021613636571":1478686417049,"1025513939541":1509788624295,"1022354927126":1509788624928,"1022390971457":1478686417291,"1020294113627":1465470268291,"1022265926865":1478686417197,"1158570740":1509788625081,"447230633":1509788625020,"1019937968613":1465470268276,"1022037253827":1509788624462,"945557594":1444487341756,"1000922162047":1478686417021,"402665483":1478686804029,"1004588289733":1444487341763,"1020072995305":1465470268257,"1021040955953":1478686416992,"1017108166820":1478686804058,"1019963527781":1509788624319,"1019963527780":1509788624319,"1024066078700":1509788667495,"1010013569323":1491634246521,"1020565567198":1478686417026,"1024782676322":1509788625020,"1010013569320":1491634246526,"1020565567194":1478686417026,"1010013569325":1491634246521,"1010013569324":1491634246526,"1024341333799":1509788624335,"1020462674155":1465470268258,"1020989185801":1478686417230,"1022455195564":1478686417297,"1020989185800":1478686417230,"1022117466693":1478686417183,"1022117466689":1478686417183,"1019173692400":1509788624317,"4995154394":1509788667394,"1021820846534":1478686417053,"1021977221643":1478686417056,"1025560469683":1509788625021,"4994630092":1509788667393,"1022012742691":1478686417159,"1015591492970":1478686804016,"1023931993972":1491634246530,"1023931993973":1491634246530,"1023931993974":1491634246530,"1023931993970":1491634246529,"1024528917192":1509788625027,"1023931993976":1491634246530,"1017108166691":1478686804058,"1010002690210":1491634246524,"1010002690213":1491634246524,"1010002690215":1491634246524,"1025044676890":1509788624569,"1024165043376":1509788624931,"1025044676899":1509788624569,"1025715009836":1509788624845,"1021287915982":1478686417101,"302004902":1491634246506,"1021710093038":1478686417250,"1022059667398":1509788625065,"1021710093035":1478686417250,"1021710093034":1478686417250,"1021778120442":1480585069060,"1024274486238":1509788624328,"1025715009848":1509788624844,"1025715009849":1509788624844,"1025715009847":1509788624844,"1016670756380":1478686804042,"1025715009840":1509788624844,"1021240864414":1465470268197,"1022200960960":1478686417190,"1023186965149":1509788625083,"1020741189828":1478686417224,"1019761280681":1509788625076,"1025444997484":1509788624369,"1015449929135":1478686804029,"1024206856003":1509788625020,"1021718481695":1478686417250,"1022238272023":1478686416978,"1022097019316":1478686417181,"1022097019311":1478686417181,"1021240864417":1465470268197,"1022116287246":1478686417183,"1021320028800":1478686417102,"1022065696312":1478686417175,"1024557491589":1509788625026,"1022073557430":1478686417176,"1021369706396":1478686804048,"1021369706398":1478686804048,"1021369706393":1478686804048,"1021369706392":1478686804048,"1021369706395":1478686804048,"1021369706394":1478686804048,"1022396867180":1478686417206,"1021369706389":1478686804048,"1016845887817":1509788624367,"1021369706391":1478686804048,"1021369706390":1478686804048,"1017975549408":1478686804023,"1025615389374":1509788625021,"1021369706412":1478686804048,"1021369706408":1478686804048,"1021369706411":1478686804048,"1021369706410":1478686804048,"1021369706405":1478686804048,"1021369706404":1478686804048,"1021369706407":1478686804048,"1021369706406":1478686804048,"1021369706401":1478686804048,"1021328417323":1478686804065,"1021369706403":1478686804048,"1021369706402":1478686804048,"1008091045690":1478686804028,"1024420916714":1509788625031,"1652181818":1444487341732,"1019925647841":1509788624931,"1000922161713":1478686417021,"1019925647847":1509788624930,"1019925647845":1509788624922,"1019925647844":1509788624942,"1652181808":1444487341722,"1019925647859":1509788624922,"1020780774137":1478686417076,"1019925647856":1509788624930,"1573680280":1491634246509,"1022352695617":1478686417203,"1019925647860":1509788624931,"1022392410849":1478686417206,"1021697509479":1509788624507,"1025044676838":1509788624569,"1021908928259":1478686417259,"1021697509482":1509788624507,"1021697509481":1509788624507,"1021697509480":1509788624507,"1025044676850":1509788624569,"1025044676849":1509788624569,"1021212028256":1509788624453,"1019925647833":1509788624922,"1019925647839":1509788624921,"1019925647838":1509788624922,"1021472734694":1478686417007,"1017108166958":1478686804058,"1021737487627":1478686417251,"1008046873862":1480585069065,"1021737487630":1478686417251,"1018888590115":1509788624302,"1020662156651":1478686804035,"1021472734678":1478686417007,"1022087975010":1478686417179,"1020817212494":1478686417030,"1021587944037":1509788625020,"1025628235051":1509788624523,"1012635069657":1478686804024,"1025628235048":1509788624537,"1025628235049":1509788624540,"1023927406540":1491634246529,"1025628235046":1509788624542,"1021739716225":1478686417253,"1024586720455":1509788624501,"1021812589088":1478686417132,"1024586720453":1509788624501,"1024586720451":1509788624501,"1024586720448":1509788624500,"1019602292725":1480585069067,"1022517590070":1509788624604,"1000922161507":1478686417021,"1022043413626":1478686417011,"1024586720495":1509788624491,"4980212465":1509788624158,"1024586720485":1509788624490,"1001249846752":1444487341749,"1016301652625":1480585069066,"1024586720509":1509788624490,"1024341857630":1509788624276,"1024586720502":1509788624491,"1024586720503":1509788624490,"147989224":1444487341753,"1019760362659":1509788624366,"1024586720500":1509788624490,"1024586720499":1509788624491,"1024586720497":1509788624491,"1020859024732":1509788624390,"1020859024729":1509788624390,"1020859024728":1509788624390,"245245144":1444487341734,"1020859024731":1509788624390,"1020859024730":1509788624390,"1020859024726":1509788624390,"1019325611563":1478686804058,"1019330985569":1509788624323,"1019330985568":1509788624323,"1024586720415":1509788624501,"1024586720413":1509788624500,"1023544026432":1509788667497,"1022453359683":1478686417215,"1024586720431":1509788624500,"1024586720428":1509788624500,"1024586720429":1509788624500,"1025750530548":1509788624306,"1024586720427":1509788624500,"1024586720424":1509788624500,"1024586720425":1509788624500,"1024586720421":1509788624500,"1024586720418":1509788624500,"1024586720416":1509788624501,"1024586720442":1509788624500,"1024586720440":1509788624500,"1019574897139":1509788624314,"1021260393800":1478686417237,"1021574311942":1509788624401,"1024586720437":1509788624500,"1024586720432":1509788624500,"1024586720433":1509788624500,"1024586720334":1509788624604,"1024586720332":1509788624604,"1024586720331":1509788624552,"1024586720328":1509788624604,"1024586720326":1509788624604,"1019330985659":1509788624323,"1024586720325":1509788624604,"1022455194997":1478686417216,"1009269921609":1509788624374,"1024586720321":1509788624604,"1022438941795":1480585069104,"1022438941792":1480585069104,"1022438941793":1480585069104,"1022438941798":1480585069104,"1024586720346":1509788624604,"1022438941799":1480585069104,"1024586720347":1509788624604,"1022438941796":1480585069104,"1024528785620":1509788624183,"1022438941797":1480585069104,"1022438941802":1480585069104,"1024586720343":1509788624604,"1016670755898":1478686804063,"1019433742475":1478686804070,"1024586720340":1509788624604,"1021727394244":1478686417051,"1019433742474":1478686804070,"1022438941801":1480585069104,"1022438941806":1480585069104,"1024586720338":1509788624604,"1022438941807":1480585069104,"1022438941804":1480585069104,"1022438941805":1480585069104,"1016558421462":1478686804063,"1021964245916":1478686417056,"1019325611718":1478686804058,"1022438941779":1480585069104,"1025313772345":1509788624930,"1021554389805":1478686417048,"1007839907256":1509788624389,"1023994380447":1491634246523,"1022873177524":1509788625052,"1019325611714":1478686804058,"1022438941783":1480585069104,"1022438941780":1480585069104,"1024586720360":1509788624604,"1024586720358":1509788624604,"1022438941787":1480585069104,"1024586720359":1509788624604,"1022438941790":1480585069104,"1024586720355":1509788624604,"1024586720352":1509788624604,"1025561780834":1509788624338,"1022234209203":1478686417065,"4980212332":1509788624158,"1025609490755":1509788625088,"1024558409308":1509788667888,"1025609490750":1509788625116,"1025609490751":1509788625125,"1020699511887":1478686804039,"1021262228953":1478686804039,"1371962121":1478686804054,"1012297014182":1478686417026,"1019325611655":1478686804058,"1022027816852":1478686417164,"1022043413633":1478686417011,"1022733071789":1509788624181,"1019325611663":1478686804058,"1019325611662":1478686804058,"1023454240935":1509788625071,"1019325611661":1478686804058,"1019325611660":1478686804058,"1019596525238":1509788624959,"1019325611659":1478686804058,"1019325611658":1478686804058,"1019325611657":1478686804058,"1019325611656":1478686804058,"1019325611665":1478686804058,"1019325611664":1478686804058,"1024586720313":1509788624604,"1021901587456":1509788624982,"1021901587459":1509788624981,"1021901587458":1509788624982,"1022096757671":1478686417181,"1021901587460":1509788624981,"1022200960001":1478686417190,"1021354108573":1465469681399,"4980212701":1509788624158,"1021091681828":1478686417094,"1019325611887":1478686804058,"1019325611886":1478686804058,"1019325611885":1478686804058,"1019325611894":1478686804058,"1019330985760":1509788624323,"1019325611893":1478686804058,"1022678415262":1509788624462,"1019325611892":1478686804058,"1019325611891":1478686804058,"1019325611890":1478686804058,"1019325611889":1478686804058,"1019325611888":1478686804058,"1024529310019":1509788625027,"1022208650156":1480585069087,"1021354632894":1465470268234,"1019330985757":1509788624323,"1019330985756":1509788624323,"1019330985759":1509788624323,"1019330985758":1509788624323,"1021714942240":1509788625083,"1020294112749":1465470268291,"1000922161202":1478686417021,"1024265441619":1509788625032,"4968547178":1509788624158,"1021354632903":1465470268234,"1021354632902":1465470268234,"1021354632901":1465470268234,"1021354632898":1465470268234,"1024672970992":1509788624544,"4995154656":1509788667393,"818551724":1444487341742,"1021984168075":1478686417263,"1020616411879":1478686417075,"1371962039":1478686804054,"1025896675243":1509788667465,"1025896675241":1509788667458,"1017371872140":1478686804018,"1024662878524":1509788624430,"1019325611805":1478686804058,"1020862569392":1478686417227,"1001009068893":1478686804029,"1025896675237":1509788667461,"1022058748935":1475218613699,"1020605926316":1478686417075,"1025791688379":1509788624466,"1021069006643":1478686417093,"1024680311024":1509788624590,"1022097019644":1509788624416,"1025791688375":1509788624511,"1025791688369":1509788624511,"1022736217219":1509788667874,"1024586720527":1509788624491,"1024586720522":1509788624490,"1024586720523":1509788624490,"1024586720521":1509788624490,"1025791688411":1509788624507,"1022184838609":1478686417187,"1024586720514":1509788624490,"1024586720515":1509788624490,"1025791688401":1509788624507,"1024586720512":1509788624490,"1021778120090":1480585069060,"1016670756209":1478686804063,"1016670756211":1478686804042,"1025791688399":1509788624441,"1025791688392":1509788624423,"1021345064915":1478686804023,"1025791688395":1509788624441,"1025791688389":1509788624466,"1022439073066":1478686417214,"1024586720532":1509788624491,"1008688361907":1478686804030,"1024586720531":1509788624491,"1021655315541":1509788624272,"1211786213":1444487341750,"1540648971":1478686417020,"1025791688387":1509788624466,"1024586720529":1509788624491,"1025796799823":1509788624200,"1024663271861":1509788625003,"1025712912988":1509788624308,"1016928202420":1478686804032,"1025796799827":1509788624185,"1025796799825":1509788624197,"1024017449180":1509788624610,"1021519657909":1478686417113,"1022220185077":1478686417192,"1022280476751":1478686417285,"1018918342818":1509788624366,"1024223761537":1509788625243,"1023796343804":1509788625038,"1022215203894":1509788624959,"1021975780942":1478686417150,"1021757671770":1478686417126,"1025616177061":1509788624929,"4980212962":1509788624158,"1021185814471":1478686417003,"1022465549081":1478686417299,"1025900343495":1509788667461,"1022465549079":1478686417299,"1025900343497":1509788667458,"1021554390494":1478686417048,"1022388873112":1478686417290,"1021989543894":1478686417155,"1021989543892":1478686417155,"1021989543890":1478686417155,"1025834415358":1509788667836,"1024133324676":1509788624416,"1024133324672":1509788624416,"1024133324673":1509788624416,"1020890226085":1478686417032,"1024133324669":1509788624416,"1023196796716":1509788624461,"1025628233803":1509788625088,"1021345063062":1478686804023,"1024133324642":1509788624416,"1025628233794":1509788625124,"1025628233795":1509788625107,"1024133324655":1509788624416,"1025628233793":1509788625115,"1022370522695":1478686804065,"1021618352508":1478686417117,"1024133324626":1509788624416,"1009979231028":1478686804030,"1025557064629":1509788624344,"1024133324633":1509788624416,"1025100382434":1509788624181,"1024133324611":1509788624416,"1004605459215":1478686417222,"1024133324596":1509788624416,"1004605459213":1478686417222,"1021860956033":1509788624992,"1012695754096":1478686804024,"1024133324605":1509788624416,"1158572482":1509788625081,"1021346636064":1478686417041,"1004605459202":1478686417222,"1021920854808":1509788625009,"228204879":1444487341718,"1004605459220":1478686417222,"1004605459218":1478686417222,"1004605459217":1478686417222,"1004605459216":1478686417222,"1470659407":1478686804024,"1022435795432":1478686417071,"1022041315944":1478686417268,"1021710093993":1478686417250,"1021710093992":1478686417250,"1021482826012":1509788624398,"1022200959985":1478686417190,"1021618090288":1478686417117,"4994893127":1509788667394,"1015242313019":1480585069068,"1024586720206":1509788624906,"1024586720207":1509788624906,"1024586720205":1509788624906,"1019841765024":1509788625079,"1024586720200":1509788624906,"1022316391212":1478686417200,"1024586720223":1509788624906,"1018953864093":1478686804045,"1024653311972":1509788624942,"1018953864092":1478686804045,"1024653311973":1509788624940,"1018953864091":1478686804045,"1018953864090":1478686804045,"1018953864089":1478686804045,"1018953864088":1478686804045,"1024653311969":1509788624281,"1018953864087":1478686804045,"1024653311982":1509788624930,"1018953864086":1478686804045,"1018953864085":1478686804045,"1024653311980":1509788624930,"1018953864084":1478686804045,"1024586720213":1509788624906,"1024586720210":1509788624906,"1024586720211":1509788624906,"1024586720208":1509788624906,"1025834415503":1509788667836,"1001020210364":1478686804054,"1001020210367":1478686804054,"1001020210361":1478686804054,"1001020210357":1478686804054,"1022241419152":1509788624932,"1001020210353":1478686804054,"1001020210352":1478686804054,"1021700526043":1478686804046,"1001020210355":1478686804054,"1024586720224":1509788624906,"1024586720225":1509788624906,"1004605459199":1478686417222,"1021774973781":1478686804047,"1022021523687":1509788624181,"1004605459198":1478686417222,"1001020210350":1478686804054,"1022241419147":1509788625019,"1021981810436":1509788624871,"1022241419149":1509788624930,"1230267491":1444487341720,"1022241419151":1509788624931,"1001020210341":1478686804054,"1021636572060":1478686417049,"1021188828751":1465470268190,"1001020210338":1478686804054,"1024653311945":1509788624930,"1024653311934":1509788624930,"1021325010455":1465470268213,"1020931774951":1478686417083,"1024653311930":1509788624169,"1021325010454":1465470268213,"1024653311931":1509788624930,"1021325010453":1465470268213,"1722567679":1444487341726,"1024653311909":1509788624971,"1020581163737":1480585069077,"295582920":1478686804032,"1022687588695":1509788624402,"1024586720174":1509788624906,"1022503042146":1509788624441,"1024586720172":1509788624906,"1024586720173":1509788624906,"1024586720168":1509788624906,"1024586720167":1509788624906,"1004588288931":1444487341762,"1024586720164":1509788624906,"1023959516474":1509788625071,"1021688859872":1478686417121,"1024586720165":1509788624906,"1024586720162":1509788624906,"1024586720163":1509788624906,"1012592996001":1478686804020,"1018953864179":1478686804045,"1018953864178":1478686804045,"1024653311883":1509788624428,"1022108292873":1478686417301,"1021721366078":1478686804047,"1019710293520":1509788624940,"1024869577620":1509788624940,"1025796799268":1509788624431,"1025796799267":1509788624425,"1024869577628":1509788624942,"1025796799265":1509788624428,"1024653311844":1509788624959,"1022952735173":1509788625051,"1023175169201":1509788625043,"1024013911732":1509788667884,"1023855448013":1491634246537,"1019448555165":1478686804021,"1021516774010":1478686417113,"1015875939251":1480585069075,"1158572216":1509788625081,"1015242312824":1480585069068,"1021900144813":1478686416980,"1012366481558":1478686804052,"1017770728190":1478686804022,"1021805249877":1478686417052,"1022440252206":1478686417071,"1022097020077":1509788624416,"1024678870666":1509788667888,"1016873152333":1509788624171,"1020966902605":1478686417086,"1024179067706":1509788624614,"1023671433582":1509788625104,"1021920592377":1509788624465,"1025629414019":1509788625083,"1010044503455":1480585069062,"1025541335514":1509788625083,"4980213487":1509788624156,"1024782284575":1509788624456,"1020228183175":1509788625076,"1021301810426":1478686417238,"1023535243742":1509788624388,"1023535243743":1509788624388,"1023535243740":1509788624388,"1023535243741":1509788624388,"1022073558775":1478686417176,"1025787755279":1509788624517,"1022418887262":1478686417293,"1025732050129":1509788624942,"1022048262220":1478686417171,"1023535243746":1509788624388,"1023535243744":1509788624388,"4994893763":1509788667393,"1023535243745":1509788624388,"1021881533070":1509788624433,"1021579162802":1478686417008,"1021881533067":1509788624508,"1024586326128":1509788624998,"621022094":1478686417019,"1015242444618":1480585069068,"1019225465075":1509788625077,"1024586326116":1509788624999,"1021166152770":1478686417097,"1023979964300":1509788624176,"1023979964301":1509788624176,"1025532684539":1509788624343,"1023979964292":1509788624178,"1021680864924":1478686417120,"1022733070807":1509788624181,"1023979964294":1509788624177,"1024586326122":1509788625002,"1023979964295":1509788624176,"1024586326101":1509788625001,"1021354631986":1465470268234,"1024586326110":1509788625005,"1019127424760":1465470268272,"1020752988100":1478686416996,"1021606687445":1509788624397,"1024586326092":1509788624999,"1019127424749":1465470268320,"1024341856731":1509788624273,"1024005785040":1491634246523,"1024146693580":1509788667505,"1021016315768":1478686417001,"1024146693571":1509788667505,"1024146693575":1509788667505,"1024146693595":1509788667505,"1023349254760":1509788624346,"1022266584546":1478686417197,"1024146693586":1509788667505,"1023349254766":1509788624434,"1016400087079":1480585069069,"1024146693601":1509788667505,"1024146693602":1509788667505,"1018938266482":1509788624314,"1017639525899":1478686804034,"1024146693606":1509788667505,"1022370522134":1478686804039,"1022370522135":1478686804039,"1022054947110":1478686417059,"1022370522133":1478686804039,"1021833561112":1509788625069,"1022370522138":1478686804039,"1022370522139":1478686804039,"1022370522136":1478686804039,"1022370522137":1478686804039,"1019386296260":1509788624312,"1019386296257":1509788624312,"1024789231064":1509788624568,"1024789231057":1509788625090,"1024789231053":1509788625090,"1024789231054":1509788625090,"1024789231048":1509788625090,"1024789231049":1509788625090,"1024264918277":1509788624420,"1025676206303":1509788624296,"1023535243452":1509788624439,"1021166153211":1478686417097,"4980213750":1509788624157,"1002303418926":1478950494935,"1008037043224":1478686804064,"1020683520724":1478686417224,"1021212027730":1509788624453,"1025890907255":1509788667403,"1025890907252":1509788667403,"1025736768784":1508316495865,"1024412003340":1509788624462,"1525446075":1478950494925,"1021907091931":1478686417140,"1021659639845":1478686417120,"1024789231037":1509788625090,"1021606687496":1509788624397,"1024789231034":1509788624458,"1020719040536":1478686416996,"1021848503658":1478686417135,"1001503064507":1444487341711,"1021848503656":1478686417135,"1020294111708":1465470268291,"1025508174490":1509788624308,"1022416003883":1480585069075,"1019386296248":1509788624317,"1021409165096":1478686417043,"1021894378188":1478686417138,"1021668806484":1509788624400,"1023520956902":1509788625071,"1011307272675":1509788625018,"1019724710683":1478686804053,"1022460829739":1478686417016,"1012503974580":1478686804017,"4995155470":1509788667393,"1021692530372":1478686417050,"1018953863480":1478686804050,"1025508436548":1509788624297,"1623084803":1478686804068,"1021692530366":1478686417050,"1022754951117":1509788624183,"1024226252697":1509788667467,"1022220185128":1478686417192,"1022220185118":1478686417192,"1024797095330":1509788625020,"1021688335939":1478686804039,"1021655314554":1509788624272,"1019186799454":1509788624316,"1011593685179":1478686417220,"1025296730268":1509788624199,"1023842865444":1509788624357,"1025296730269":1509788624209,"1023842865445":1509788624357,"1025296730271":1509788624209,"1023842865440":1509788624357,"1025296730266":1509788624197,"1025538586164":1509788624311,"1023842865442":1509788624357,"1023842865443":1509788624357,"1021575096955":1478686804067,"1021575096954":1478686804067,"1004588291781":1444487341762,"1025296730256":1509788624228,"1014142480248":1465470268245,"1010000468061":1478686804064,"1025296730259":1509788624269,"1024256658058":1509788625032,"1024070672289":1491634246533,"1025296730255":1509788624228,"1025296730248":1509788624269,"1025296730249":1509788624271,"1021757412743":1509788624194,"1025296730251":1509788624271,"1021847591471":1509788624536,"1021672870074":1509788624396,"1022364498282":1480585069075,"1024781363583":1509788624231,"1022319146554":1478686416978,"1024136201092":1509788625085,"1023761607730":1509788624565,"1021873151165":1478686804069,"1023842865431":1509788624357,"1025296730281":1509788624213,"1021575096901":1478686804067,"1021575096900":1478686804067,"1023842865436":1509788624357,"1023842865437":1509788624357,"1023842865438":1509788624357,"1022318097981":1509788624290,"1023842865439":1509788624357,"1025296730272":1509788624209,"1023842865432":1509788624357,"1023842865433":1509788624357,"1025296730274":1509788624209,"1023842865434":1509788624357,"1025296730275":1509788624209,"1023842865435":1509788624357,"1024848866670":1509788624931,"1021418988031":1509788624817,"1025296730334":1509788625244,"1022318097986":1509788624290,"1021078572462":1465470268323,"1022318097987":1509788624290,"1023106221380":1509788624462,"1024365080652":1509788624919,"1022318097996":1509788624311,"1024848866661":1509788624941,"1021778122264":1480585069060,"1024848866657":1509788625019,"1019417881269":1509788624316,"1020821806339":1478686417078,"1614303333":1478686417017,"1025296730365":1509788625133,"1020780387272":1478686417029,"1020780387275":1478686417029,"1016355394308":1465470268253,"1025296730359":1509788625144,"1025910828425":1509788667579,"1001098978979":1478686417022,"1296071980":1478686804049,"1023407847261":1509788624367,"1025441722761":1509788624294,"1025296730351":1509788625166,"1021848246911":1478686417009,"1012108531395":1478686416993,"1025676214150":1509788624296,"1024848866644":1509788624946,"1025296730342":1509788625246,"1021575096847":1478686804067,"1021575096846":1478686804067,"1025296730337":1509788625246,"1022204850246":1480585069085,"1025284802513":1509788624290,"1025284802516":1509788624290,"1025284802517":1509788624290,"1022095575502":1509788624943,"1021379149460":1478686804033,"4904588510":1509788624158,"1025052940681":1509788667843,"1021281499516":1478686417237,"1025702420702":1509788624511,"1025702420703":1509788624466,"1021345070230":1478686804023,"1025702420699":1509788624511,"1021873150999":1478686804069,"1017374363761":1465470268269,"1025296730173":1509788624865,"1017374363763":1465470268269,"1021964632479":1478686417148,"1025296730168":1509788624917,"1025062902473":1509788624292,"1025702420713":1509788624507,"1025702420710":1509788624441,"1025296730167":1509788624917,"1025702420706":1509788624466,"1023878648748":1491634246506,"1025296730163":1509788624916,"1017374363753":1465470268269,"1025702420727":1509788624455,"1022065690507":1478686417175,"1024781363605":1509788624231,"1022067787730":1478686417060,"1024781363600":1509788624231,"1025296730200":1509788624868,"1851022993":1444487341729,"1024781363601":1509788624231,"1021575097019":1478686804067,"1025296730196":1509788624840,"1025296730197":1509788624840,"1024781363614":1509788624231,"1025296730198":1509788624840,"1851023000":1444487341719,"1023861478084":1491634246533,"1023628305698":1509788624928,"1021575097020":1478686804067,"1021152784718":1478686417037,"1021091941870":1478686417094,"1021091941869":1478686417094,"1025296730190":1509788624840,"1851022983":1444487341752,"1024781363591":1509788624231,"1024781363586":1509788624231,"1025296730186":1509788624821,"1024136201086":1509788625085,"1024781363587":1509788624231,"1025296730187":1509788624825,"1024136201073":1509788625086,"1851022990":1444487341733,"1024781363598":1509788624231,"1018918341747":1509788624366,"1022382717687":1478686417015,"1022406179869":1478686417207,"1025296730176":1509788624865,"1024781363595":1509788624231,"1024781363637":1509788624231,"1024781363638":1509788624231,"1001098978858":1478686417022,"1024781363633":1509788624231,"1024781363635":1509788624231,"1024781363644":1509788624231,"1022827304261":1509788624587,"1022030038458":1478686417165,"1022433574351":1478686417302,"1020261481555":1478686804049,"1024781363640":1509788624231,"1020978824980":1478686416982,"1024781363642":1509788624231,"1022238667308":1509788624947,"1022238667309":1509788624932,"1024781363620":1509788624231,"1024781363621":1509788624231,"1851023008":1444487341727,"1022217302268":1478686417192,"1021809973382":1509788624394,"1024781363618":1509788624231,"1024781363619":1509788624231,"1024781363628":1509788624231,"1024960140401":1509788624169,"1024781363626":1509788624231,"1025611725534":1509788624521,"1025611725532":1509788624521,"1025611725533":1509788624521,"1016355394165":1465470268253,"1021140595060":1478686417096,"1024136200841":1509788625085,"1024136200843":1509788625085,"1020832554900":1478686417226,"1018740473953":1509788624334,"1012105648126":1478686416993,"1021847591702":1509788624821,"1024136200836":1509788625085,"1024136200838":1509788625084,"1021943005473":1478686417143,"1020293988331":1465470268279,"1021925842476":1478686804046,"1019782520435":1509788624391,"1019782520434":1509788624391,"1025453781113":1509788624942,"1019782520436":1509788624391,"1025453781119":1509788624971,"1025453781060":1509788624971,"1025453781063":1509788624971,"1025453781065":1509788624942,"1025453781067":1509788624933,"1018559731559":1478686804015,"1014775444695":1478686804024,"1025453781072":1509788624971,"1021943005456":1478686417143,"1025453781075":1509788624931,"1021372071711":1478686417006,"1020879470771":1478686417227,"1010002696521":1491634246524,"1010002696524":1491634246524,"1021256857282":1478686417040,"1021315447363":1478686417005,"1025296730380":1509788625133,"1019596527055":1509788624940,"1019782520504":1509788624391,"1025296730377":1509788625133,"1021225792699":1478686417235,"1025296730369":1509788625133,"1023320159215":1509788624289,"1019759583009":1509788624283,"1017168978613":1478686804022,"1021315447392":1478686417005,"1021873151292":1478686804069,"1025296730410":1509788625140,"1006370971954":1478686804032,"463481440":1491634246534,"1008558728161":1478686804034,"1025296730463":1509788624610,"1008825717660":1480585069066,"1025438970311":1509788624293,"1025296730458":1509788624565,"1020136699335":1480585069064,"1025296730452":1509788624613,"143800667":1444487341747,"1025296730453":1509788624613,"1022491893857":1478943089254,"1025296730455":1509788624565,"1021235099515":1478686417099,"1022081288682":1478686417301,"1025296730450":1509788624611,"1025883826756":1509788667406,"1018897893889":1509788624314,"1019159673769":1509788624315,"1025296730482":1509788624550,"1024689087781":1509788624551,"1021778122662":1480585069060,"1025296730479":1509788624546,"1025296730472":1509788624546,"1025296730473":1509788624546,"1022095575219":1509788624944,"1025296730471":1509788624546,"1021950738451":1478686417261,"1012164630688":1478686416994,"1025296730467":1509788624538,"1020581293453":1478686417027,"1001544745554":1478686804029,"1022255706585":1478686417066,"1022369741594":1478686417069,"1020394645153":1509788624386,"1023487540834":1509788624318,"1022994816449":1509788625223,"1023487540832":1509788624318,"1023487540833":1509788624318,"1023487540838":1509788624318,"1023487540839":1509788624318,"1023487540836":1509788624318,"1023487540837":1509788624318,"1020751551357":1478686417028,"1023487540843":1509788624318,"1023487540840":1509788624318,"1023487540841":1509788624318,"1023487540846":1509788624318,"1023487540844":1509788624318,"1021714550813":1509788624396,"1025073650153":1509788625007,"1023487540823":1509788624372,"1023487540826":1509788624318,"1020949333910":1478686417033,"1023487540827":1509788624318,"1023487540824":1509788624372,"1023487540825":1509788624318,"1019838611935":1478686804015,"1011618462703":1478686804068,"1023487540830":1509788624318,"1011618462702":1478686804068,"1023487540831":1509788624318,"1021225662217":1478686417039,"1023487540828":1509788624318,"1011618462700":1478686804068,"1023487540829":1509788624318,"946735701":1444487341744,"1024305024901":1509788624277,"946735663":1444487341748,"1021618352030":1478686417117,"1744590269":1491634246506,"1024781363989":1509788624567,"1022994816402":1509788625223,"1024781363991":1509788624567,"1022994816403":1509788625223,"1022994816404":1509788625223,"1024781363985":1509788624567,"1021235754190":1509788624942,"1022994816408":1509788625223,"1022994816409":1509788625223,"1022994816411":1509788625223,"1024781363992":1509788624567,"1024781363993":1509788624567,"1022994816414":1509788625223,"1024926716122":1509788624530,"1022994816388":1509788625223,"1024926716125":1509788624530,"1022994816392":1509788625224,"1022994816395":1509788625224,"1022994816396":1509788625223,"1022994816397":1509788625223,"1022994816399":1509788625223,"1024926716137":1509788624415,"1024926716141":1509788624529,"1022994816440":1509788625223,"1022994816441":1509788625223,"1024926716132":1509788624530,"1025100389951":1509788624181,"1022994816417":1509788625223,"1024926716159":1509788624416,"1024781364001":1509788624567,"1024926716146":1509788624530,"1022994816426":1509788625223,"1022994816428":1509788625223,"1024781364009":1509788624567,"1022994816430":1509788625223,"1000457297265":1491634246516,"1024381858683":1509788624301,"1024926716149":1509788624529,"1021999497600":1478686417265,"1458594935":1491634246509,"1022074997260":1478686417061,"1013892391634":1478686804028,"1022074997258":1478686417061,"1022074997257":1478686417061,"1022425055035":1478686417210,"1023821501173":1491634246536,"1022077749977":1478686416973,"1021817314112":1478686417053,"1003127618909":1478686804054,"1020172088509":1465470268312,"1019448420743":1509788624316,"1002627941144":1491634246510,"4894494982":1509788624158,"1001375798512":1478686417024,"1022111828147":1509788624439,"1025100390035":1509788624173,"1025909518035":1509788667464,"1000216253350":1444487341751,"1016316597013":1480585069073,"1025773725407":1509788624303,"1022460968272":1478686417298,"1010943152848":1509788625017,"1022377080919":1478686417204,"1021817314110":1478686417053,"1022111828140":1509788624439,"1015868208197":1465470268264,"1022095575958":1509788624943,"1665159584":1478686804054,"1022094003072":1478686417274,"1019634275569":1509788624940,"1024479769647":1509788625070,"1020719043702":1478686416996,"1024689088475":1509788624847,"1025322682881":1509788624305,"1022065689634":1478686417175,"1024781363789":1509788624467,"1023627912968":1509788625084,"1022022436538":1478686417301,"1021570771347":1478686804050,"1024781363825":1509788624457,"1016606130615":1465470268237,"139869052":1444487341724,"1020842253617":1478686416998,"1000526104539":1444487341712,"1021200103324":1465470268194,"1021939729281":1478686417055,"1211792128":1444487341724,"1000526104532":1444487341713,"1000526104533":1444487341714,"1024781363817":1509788624456,"1000526104535":1444487341715,"1025100390163":1509788624273,"1019263476598":1509788624315,"1021350575746":1478686417005,"1022193749189":1478686417189,"1024781363714":1509788624250,"1002627941110":1491634246514,"1024782412403":1509788625021,"1023623194431":1509788624279,"1020272099177":1465470268247,"1020777764996":1478686417076,"1020777764995":1478686417076,"1021778122031":1480585069060,"1022961917660":1509788624426,"1021665275025":1478686417120,"1021665275029":1478686417120,"1021655706637":1509788624996,"1024136200228":1509788625086,"1017048530867":1478686804049,"1024926716186":1509788624530,"1024136200251":1509788625085,"1021575096807":1478686804067,"1024926716190":1509788624415,"1021575096806":1478686804067,"1012536609942":1478686417026,"1021061007543":1478686804045,"1021061007542":1478686804045,"1015589389973":1478686804065,"1022074604335":1478686417176,"1021061007549":1478686804045,"1021061007548":1478686804045,"1021061007547":1478686804045,"1021061007546":1478686804045,"1024781363961":1509788624567,"1021061007545":1478686804045,"1021061007544":1478686804045,"1023878647990":1491634246506,"1024926716210":1509788624529,"1024926716208":1509788624530,"1024781363944":1509788624567,"1024926716212":1509788624530,"1024313151106":1509788624926,"1024781363947":1509788624567,"1021575096754":1478686804067,"1021575096753":1478686804067,"1024781363862":1509788624457,"1021575096752":1478686804067,"1024156387154":1509788667500,"1021035448670":1478686417035,"1024781363868":1509788624456,"1024781363871":1509788624457,"1024156387160":1509788667500,"1021939729273":1478686417055,"1019838611517":1478686804015,"1024781363866":1509788624456,"1024156387141":1509788667500,"1024156387142":1509788667500,"1024781363847":1509788624457,"1024781363840":1509788624457,"1024781363842":1509788624457,"1024156387138":1509788667500,"1024156387139":1509788667500,"1024156387148":1509788667500,"1024781363853":1509788624456,"1067322436":1444487341724,"1024781363854":1509788624457,"1024781363848":1509788624457,"1024781363849":1509788624457,"1024156387145":1509788667500,"1023409026270":1491730251594,"1025736761762":1508316495865,"1024781363893":1509788624456,"1021757412978":1509788624533,"1024156387191":1509788667500,"1003806295177":1478686417220,"1024926716271":1509788624415,"1003806295179":1478686417220,"1003806295178":1478686417220,"1024781363891":1509788624456,"1024926716258":1509788624416,"1003806295174":1478686417220,"1024781363896":1509788624457,"1024095962083":1509788624517,"1024781363898":1509788624457,"1003806295170":1478686417220,"1024926716283":1509788624416,"1024156387173":1509788667500,"1024156387175":1509788667500,"1024156387168":1509788667500,"1024781363874":1509788624457,"1024156387171":1509788667500,"1024781363884":1509788624456,"1724929322":1444487341746,"1003806295191":1478686417220,"1024781363887":1509788624456,"1024156387183":1509788667500,"1010002697165":1491634246524,"1024781363880":1509788624457,"1024781363881":1509788624457,"1024156387177":1509788667500,"1004588291383":1444487341762,"1024781363882":1509788624456,"1003806295186":1478686417220,"1021020769657":1509788624931,"1021020769656":1509788624971,"1021873150093":1478686804048,"1021873150092":1478686804048,"1014775443900":1478686804024,"1021873150091":1478686804048,"1021873150090":1478686804048,"1021873150089":1478686804048,"1021873150088":1478686804048,"1021020769662":1509788624930,"1021873150087":1478686804048,"1021020769649":1509788624946,"1021873150086":1478686804048,"1021873150085":1478686804048,"1021020769651":1509788624933,"1021873150084":1478686804048,"1022869771055":1509788625100,"1021873150083":1478686804048,"1021873150082":1478686804048,"1021873150081":1478686804048,"1021020769655":1509788624931,"1021873150080":1478686804048,"1021020769654":1509788624971,"1021020769643":1509788624933,"1021020769642":1509788624942,"1021020769645":1509788624933,"1025747380149":1509788624290,"1020833995400":1478686416980,"1022438816469":1480585069100,"1016119337382":1478686804040,"1018559730208":1478686804015,"1020293986949":1465470268278,"1021981672988":1478686417151,"1021570772638":1478686804040,"1022071852263":1478686417060,"1021655706553":1509788624990,"1021140595820":1478686417096,"1021873150159":1478686804048,"1021873150158":1478686804048,"1021873150157":1478686804048,"1021873150156":1478686804048,"1021873150155":1478686804048,"1021140595739":1478686417096,"1021873150169":1478686804048,"1021873150168":1478686804048,"1021873150167":1478686804048,"1021873150166":1478686804048,"1021873150165":1478686804048,"1021873150164":1478686804048,"1021873150163":1478686804048,"1021873150162":1478686804048,"1021873150161":1478686804048,"1021873150160":1478686804048,"557061462":1444487341737,"1022733069089":1509788624181,"1022097018147":1478686417181,"1022097018146":1478686417181,"1022097018145":1478686417181,"1010025373353":1491634246527,"1022097018153":1478686417181,"1020815776049":1478686417078,"1016119337223":1478686804040,"1023797652337":1509788625082,"1024401389425":1509788624228,"197148503":1444487341706,"1017590241642":1478686804022,"1022379572963":1478686417204,"1020805028092":1478686417077,"1016400089711":1480585069069,"1025907288201":1509788667464,"1025907288203":1509788667458,"1025907288204":1509788667460,"1019037120268":1509788624314,"1011030577737":1478686804030,"1010077800821":1491634246535,"1021428032992":1478686804026,"1020622706144":1509788624354,"1019759581789":1509788624280,"1021987309314":1509788624441,"1084519493":1444487341728,"1025629288523":1509788624746,"1025629288520":1509788624822,"1025629288521":1509788624832,"942804190":1478686804024,"1025629288519":1509788624828,"1025406962436":1509788624456,"1023626731753":1509788624552,"1001375797951":1478686417024,"1021873150079":1478686804047,"1021020769673":1509788624933,"1010025373228":1491634246522,"1020795459644":1478686416987,"1010025373224":1491634246527,"1020815776078":1478686417078,"1025406962414":1509788624511,"1025406962412":1509788624511,"1022428985445":1478686417016,"1022193748610":1478686417189,"1025406962424":1509788624507,"1022219269375":1478686417192,"1025406962416":1509788624466,"1025406962422":1509788624441,"1025406962423":1509788624441,"1025406962420":1509788624466,"1025406962421":1509788624423,"1706315922":1491634246517,"1021935142358":1478686417055,"1022428985438":1478686417016,"1010023538633":1491634246516,"1022428985431":1478686417016,"1022421514434":1478686417210,"1022428985390":1478686417016,"1022428985391":1478686417016,"1021778121503":1480585069060,"1023305872492":1509788625041,"557061243":1444487341736,"1016355395132":1465470268254,"1022360698056":1478686417203,"1004769297750":1478686804064,"1022994815621":1509788624198,"1022428985405":1478686417016,"1022428985399":1478686417016,"1021143741797":1478686417002,"1022021910735":1478686417163,"1022303024004":1478686417287,"1022181559106":1478686417187,"1025890905694":1509788667403,"1022428985374":1478686417016,"1008172306012":1478686804032,"1000060022184":1478686804046,"1022400151128":1478686417292,"1019759582202":1509788624281,"1021992552173":1478686417011,"1022341823806":1478686417202,"1021570772796":1478686804040,"1010025373521":1491634246527,"1010025373519":1491634246527,"1019527583209":1509788624312,"1021911686097":1509788624465,"1019290740482":1509788625018,"1010025373509":1491634246522,"1019290740480":1509788625018,"1010025373507":1491634246527,"1022044193755":1509788624399,"748296496":1478950494916,"1021631064234":1478686417119,"1001375798151":1478686417024,"1024085214495":1509788667549,"1021656754762":1478686416974,"1022038033152":1478686417301,"1022478263623":1478943089536,"1024554612998":1509788624927,"1025609629206":1509788624537,"1025609629204":1509788624540,"1025609629205":1509788624542,"946736521":1444487341744,"1025712907335":1509788624306,"1025609629209":1509788624523,"1022454151701":1478686417216,"1020772785185":1478686417076,"1021778120784":1480585069060,"1016877741120":1478686804019,"1021920467414":1478686417054,"1012105646286":1478686416993,"1024596555844":1509788624932,"1016681103400":1478686804018,"1024689087205":1509788624214,"1021553471372":1478686417048,"1016355394896":1465470268253,"1015159089891":1478686804029,"1020772785183":1478686417076,"1020744605619":1509788624389,"1001375797259":1478686417024,"1006370973377":1478686804032,"1015212173823":1480585069074,"1021847592045":1509788624197,"1003806294276":1478686417220,"1018797753235":1478686804038,"1018797753237":1478686804038,"1003806294272":1478686417220,"1018797753236":1478686804038,"1018797753238":1478686804038,"1019759581418":1509788624311,"1021873150719":1478686804069,"1022258460101":1478686417067,"1022463064346":1480585069117,"1015242053452":1480585069068,"1025186367413":1509788624515,"1025186367415":1509788624515,"1025186367417":1509788624515,"1025186367418":1509788624515,"1025529409585":1509788624340,"1025186367423":1509788624514,"1022994815296":1509788624599,"1025773724313":1509788624289,"1022994815303":1509788624599,"1008105324976":1509788624390,"1022994815305":1509788624598,"1022994815307":1509788624599,"814876174":1444487341726,"1025186367405":1509788624514,"1025186367407":1509788624515,"1018918341133":1509788624366,"1018797753169":1478686804057,"1018797753168":1478686804057,"1018797753170":1478686804057,"1004588290148":1444487341762,"1021945366259":1478686417010,"1024134497654":1509788624430,"268838579":1509788625080,"1211793037":1444487341729,"1024134497653":1509788624430,"1024134497658":1509788624430,"1024134497657":1509788624430,"1022204851832":1480585069085,"1024134497660":1509788624430,"1022994815248":1509788624599,"1019950157803":1465470268276,"1021262361045":1478686417101,"1021821116263":1480585069080,"1022994815253":1509788624599,"1019739659039":1509788624173,"1021830815738":1478686417133,"1021830815743":1478686417133,"1022994815263":1509788624599,"1023472074126":1509788625039,"1023320159389":1509788624289,"1022994815236":1509788624599,"1022240896118":1478686417283,"1022994815241":1509788624599,"1021575097513":1478686804050,"1020622706669":1509788625080,"1022994815245":1509788624599,"1309440210":1491634246534,"1022994815246":1509788624599,"1021570772048":1478686804050,"1020786417040":1509788624372,"1025186367441":1509788624515,"1025186367442":1509788624515,"1021570772050":1478686804050,"1022994815286":1509788624599,"1084520012":1444487341728,"1019759581295":1509788624311,"1024054155367":1509788624957,"1022369742846":1478686417015,"1022994815292":1509788624599,"1025186367424":1509788624514,"1025186367425":1509788624514,"1025186367427":1509788624515,"1025186367429":1509788624515,"1025186367430":1509788624514,"1022994815270":1509788624599,"1025186367431":1509788624515,"1309440245":1491634246534,"1025186367433":1509788624514,"1211793094":1444487341736,"1018797753093":1478686804057,"1211793092":1444487341730,"1018797753094":1478686804057,"1022994815279":1509788624599,"1021778121044":1480585069060,"1018797753085":1478686804057,"1023126536435":1509788625079,"1018797753086":1478686804057,"1010025373136":1491634246522,"1010025373133":1491634246521,"1024653305316":1509788624935,"1026223429714":1514456869766,"1022152592123":1478686417185,"1021873150865":1478686804069,"1025710941934":1509788624178,"1022994815223":1509788624599,"1309440293":1491634246534,"1022994815225":1509788624599,"1022994815228":1509788624599,"1022994815230":1509788624599,"1309440318":1491634246534,"1023463161086":1509788625039,"1022994815213":1509788624598,"1022329892941":1478686417068,"1023320159497":1509788624289,"1025201571182":1509788624933,"1022956936024":1509788624562,"1022956936030":1509788624562,"1022956936031":1509788624562,"1022956936029":1509788624562,"1016355394622":1465470268253,"1021909457208":1478686417140,"1020842121565":1478686417078,"1022272746430":1478686417067,"384311684":1491634246524,"1022994815139":1509788624538,"1022956936033":1509788624562,"1025765204942":1509788625083,"1019675565583":1464448510786,"1003806294244":1478686417220,"1023600649255":1509788624318,"1016594990770":1480585069075,"1023600649257":1509788624318,"1003806294259":1478686417220,"1021774844405":1509788624395,"1022859546732":1509788624973,"1019145256594":1509788624318,"1019145256593":1509788624318,"1003806294234":1478686417220,"1019145256592":1509788624318,"1020220063374":1478686804039,"1022956936146":1509788625155,"1022030168721":1478686417011,"1020768722337":1478686417225,"1023394344994":1509788625039,"1022956936144":1509788625155,"1022956936145":1509788625155,"1021900151511":1478686417139,"1022956936153":1509788625155,"1010011479641":1491634246525,"1010011479646":1491634246525,"1010011479645":1491634246525,"1010011479644":1491634246525,"1010011479639":1491634246525,"1022956936142":1509788625155,"1025539895804":1509788624496,"1025539895805":1509788624496,"1025539895802":1509788624495,"1025539895803":1509788624495,"1025539895800":1509788624495,"1025539895801":1509788624495,"1025539895798":1509788624495,"1025539895796":1509788624495,"1025539895794":1509788624495,"1025539895795":1509788624495,"1021611011009":1478686416985,"1022170286363":1509788624924,"1025539895790":1509788624495,"1025539895791":1509788624495,"1025539895788":1509788624495,"1025539895789":1509788624495,"1025539895786":1509788624495,"1025539895787":1509788624495,"1025539895784":1509788624495,"1025539895785":1509788624495,"1025539895783":1509788624495,"1020622706378":1509788625080,"1022030037678":1478686417165,"1023196925019":1509788625043,"1025637545004":1509788624336,"1020136700947":1480585069063,"1022748530785":1509788624427,"1022045245036":1509788624195,"1015601974867":1465470268257,"1022192306091":1478686417064,"1025385989395":1509788624508,"1021502615195":1509788625004,"1021502615194":1509788625004,"1021502615196":1509788625004,"1021502615199":1509788625004,"1021502615198":1509788625004,"1022457690006":1478686417217,"1022323867622":1478686417288,"1025385989494":1509788624508,"1001059920713":1478686417022,"1023839852804":1509788624349,"1024725003824":1509788624290,"1025385989547":1509788624508,"1024735227541":1509788667505,"1025771891880":1509788624518,"1022241421883":1478686417066,"1024937728865":1509788624462,"1024725003832":1509788624290,"1025771891876":1509788624521,"1019841760055":1509788625080,"1025300005079":1509788625083,"1019358899918":1465470268242,"1021901592156":1509788624981,"1022238538350":1478686417194,"1025771891864":1509788624521,"1018918339615":1509788624366,"1022045245071":1509788624534,"1021659244418":1478686417009,"1021743783065":1509788624395,"1023281625189":1509788624345,"1004588293674":1444487341762,"1021514936077":1509788624447,"1021514936076":1509788624447,"1021514936078":1509788624447,"158347648":1444487341706,"1024725003840":1509788624290,"1024725003843":1509788624289,"1021514936080":1509788624447,"1024725003847":1509788624289,"1022018374936":1478686417161,"1022438946803":1480585069090,"1022438946800":1480585069090,"1022438946801":1480585069090,"1022438946807":1480585069090,"1022438946804":1480585069090,"1022956934420":1509788624194,"1022438946805":1480585069090,"1022438946810":1480585069090,"1025006804684":1509788625006,"1022438946809":1480585069090,"1022438946786":1480585069090,"1022438946784":1480585069090,"1025516043384":1509788624335,"1022438946791":1480585069090,"1022438946788":1480585069090,"1022438946789":1480585069090,"1025516043378":1509788624340,"1022438946795":1480585069090,"1022438946792":1480585069090,"1020999664035":1478686417230,"1015912247526":1480585069075,"1022438946796":1480585069090,"1021860958821":1509788624992,"1021021028438":1478686417035,"1022438946783":1480585069090,"1022438946780":1480585069090,"1023628307648":1509788624928,"1022438946781":1480585069090,"1022438946754":1480585069105,"1022438946755":1480585069105,"1025532034983":1509788624296,"1022438946752":1480585069104,"1025532034980":1509788624296,"1022467257873":1478686417017,"1022438946753":1480585069105,"1022438946756":1480585069105,"1022438946757":1480585069105,"1025532034986":1509788624296,"1025532034987":1509788624296,"1022438946739":1480585069104,"1022438946737":1480585069104,"1022438946740":1480585069104,"1022438946746":1480585069104,"1022438946747":1480585069104,"1022438946745":1480585069104,"1022438946750":1480585069104,"1022438946751":1480585069104,"1022438946749":1480585069104,"1015601975076":1465470268257,"1022438946726":1480585069104,"1022438946727":1480585069104,"1012538181191":1478686417026,"1022438946725":1480585069104,"1021177297759":1478686417234,"1022438946728":1480585069104,"1022438946732":1480585069104,"1006370974167":1478686804032,"1022037249961":1509788624462,"1024374651108":1509788625084,"1021426854053":1509788624398,"1021674838526":1478686417050,"1021398018427":1478686417106,"1022045245390":1509788624420,"1025711466575":1509788624309,"1020923382439":1478686417000,"1020923382438":1478686416999,"1024997236728":1509788625020,"1020923382461":1478686417000,"1021838414635":1478686804066,"1024572699711":1509788667536,"1020923382455":1478686417000,"1026507684334":1515854751199,"1025385989260":1509788624508,"1021813510558":1478686417132,"1022489667683":1478943089315,"1022158357582":1478686416980,"1022107239289":1478686417063,"1024572699750":1509788667537,"1022038691689":1478686417168,"1024572699744":1509788667536,"1010314117700":1509788624372,"1024572699746":1509788667536,"1012728394364":1478686417074,"1019384193314":1509788624933,"1022038691685":1478686417168,"1024572699757":1509788667536,"1022038691687":1478686417168,"1025913578514":1509791302207,"1021638403906":1509788624400,"1024572699759":1509788667536,"1025385989351":1509788624508,"1024572699754":1509788667536,"1023096130677":1509788625047,"1026232338688":1514456869770,"1016465232700":1478686804046,"1024572699771":1509788667536,"1024572699717":1509788667536,"1024572699713":1509788667537,"1022093344903":1478686417063,"1022045245346":1509788624819,"1020801357184":1478686417225,"1005662904107":1480585069065,"1024572699732":1509788667537,"1022038691679":1478686417168,"1024572699735":1509788667537,"1021860958896":1509788624992,"1010295243607":1491634246528,"1012323224121":1478686417074,"1021783760409":1478686417128,"1010295243611":1491634246528,"1010295243610":1491634246523,"1015308246021":1478686804067,"1024572699739":1509788667536,"1369205649":1509788624310,"1024778871671":1509788625219,"1011972220101":1478686804064,"1024778871658":1509788625219,"1024778871659":1509788625219,"1369205647":1509788624310,"1024778871661":1509788625219,"1023938026883":1509788625086,"1024778871652":1509788625219,"1024211307790":1509788624587,"1024778871642":1509788625219,"1024778871643":1509788625219,"1004605464045":1478686417222,"1021688208276":1509788624396,"1004605464041":1478686417222,"1024778871645":1509788625219,"1021860958573":1509788624992,"1024211307783":1509788624587,"1024778871632":1509788625220,"1024778871633":1509788625220,"1024778871638":1509788625219,"1024778871636":1509788625219,"1024211307777":1509788624586,"1021188569419":1465470268188,"1021188569418":1465470268188,"1013115967668":1478686804030,"1024778871631":1509788625218,"1022416139800":1480585069075,"1022416139801":1480585069075,"1024211307799":1509788624586,"1024211307796":1509788624587,"1024211307797":1509788624587,"1369205667":1509788624310,"1021715208272":1509788624395,"1021779958899":1478686417254,"1024778871586":1509788624259,"1024778871584":1509788624260,"1024778871585":1509788624260,"1024263864401":1509788667833,"1024778871589":1509788624260,"1024778871578":1509788624260,"1024778871579":1509788624259,"1024778871580":1509788624259,"1000952707040":1478686804023,"1024778871571":1509788624260,"1024778871568":1509788624260,"1021774978057":1478686804032,"1024778871575":1509788624260,"1024778871562":1509788624260,"1015356874082":1465470268263,"1024778871560":1509788624260,"1009762967565":1478686804025,"1021776944188":1478686417128,"1024778871565":1509788624260,"1024778871552":1509788624260,"1009921169774":1480585069071,"330312141":1478686417023,"1024778871559":1509788624260,"1024778871557":1509788624260,"1021875508756":1509788624521,"1022758624069":1509788624990,"1369205534":1509788624310,"1011458655690":1478686804039,"1018215409712":1509788625019,"1023502743535":1509788624943,"1021225271203":1478686417235,"1019019687988":1509788624312,"1025773727376":1509788624289,"1130265025":1444487341736,"1009670041418":1491634246519,"1369205549":1509788624310,"1022487046818":1478943089489,"1369205546":1509788624310,"1021776157888":1509788625010,"849086497":1491634246514,"1020394647150":1509788624324,"1369205599":1509788624310,"1022253480228":1509788624277,"1022253480229":1509788624277,"1022253480232":1509788624277,"1022253480233":1509788624277,"1369205589":1509788624310,"1022253480235":1509788624277,"1001059920347":1478686417022,"1369205628":1509788624310,"1020408147740":1509788624392,"1010756251596":1509788624276,"1020408147737":1509788624392,"1020408147739":1509788624392,"1020408147738":1509788624392,"1369205622":1509788624310,"1023938026866":1509788625086,"1024778871697":1509788625218,"1024778871688":1509788625219,"1023938026859":1509788625086,"1369205609":1509788624310,"1022238799925":1509788624947,"1024778871695":1509788625218,"1022238799926":1509788624932,"1024778871692":1509788625218,"1021379146986":1478686804033,"1024778871693":1509788625219,"1023938026848":1509788625086,"1022238799929":1509788624941,"1369205606":1509788624310,"1022238799930":1509788624930,"1024778871681":1509788625219,"1369205600":1509788624310,"1024778871686":1509788625218,"1024778871687":1509788625218,"1369205602":1509788624310,"1024778871418":1509788624597,"1024778871422":1509788624596,"1024778871423":1509788624597,"1025044681351":1509788624870,"1025044681348":1509788624870,"1024778871421":1509788624597,"1024778871411":1509788624597,"1025550908541":1509788624305,"1024778871414":1509788624596,"1025044681359":1509788624870,"1025044681356":1509788624870,"1022146955081":1478686416973,"1025044681362":1509788624870,"1022246009185":1478686417018,"1024778871401":1509788624597,"1024778871406":1509788624597,"1025044681365":1509788624870,"1008105327664":1509788624390,"1024778871394":1509788624596,"1025044681370":1509788624870,"1024778871395":1509788624596,"1024778871392":1509788624597,"1025044681368":1509788624870,"1025044681375":1509788624870,"1024778871396":1509788624596,"1025044681372":1509788624870,"1025044681379":1509788624870,"1652185438":1444487341734,"1024778871390":1509788624597,"1025044681382":1509788624870,"1019759580576":1509788624281,"1024778871391":1509788624597,"1025044681381":1509788624870,"1024778871378":1509788624597,"1025044681386":1509788624870,"1024778871376":1509788624597,"1025044681384":1509788624870,"1025044681385":1509788624870,"1024778871383":1509788624597,"1024778871370":1509788624596,"1024300566221":1509788624298,"1021661733908":1509788624420,"1025385989659":1509788624508,"1021301813643":1478686417238,"1021513755951":1478686417112,"1024778871374":1509788624597,"1024778871375":1509788624597,"1017398221436":1478686804053,"1021372855614":1478686417042,"1021393302637":1478686417043,"1025044681422":1509788624569,"1021185816778":1478686417003,"1025044681423":1509788624569,"1025044681420":1509788624569,"1025044681421":1509788624569,"1025044681426":1509788624569,"1019324035021":1509788624301,"1025044681424":1509788624569,"745674529":1444487341724,"1025044681430":1509788624569,"1025044681431":1509788624569,"1025044681429":1509788624569,"1025044681435":1509788624569,"1022413518636":1478686417208,"1023734735085":1509788624970,"1024879404071":1509788625023,"1025565455301":1509788624337,"1025044681439":1509788624569,"1025044681437":1509788624569,"1025044681442":1509788624569,"1022063594547":1478686417060,"1025044681441":1509788624569,"1022063594548":1478686417060,"1369205497":1509788624311,"1021021028893":1478686417035,"1021602883371":1478686416982,"1024778871547":1509788624260,"1024778871545":1509788624260,"1021394089148":1478686417105,"1024778871549":1509788624260,"1021394089138":1478686417105,"1024778871540":1509788624259,"1016950357397":1478686804031,"372125118":1444487341704,"1021680343962":1478686804034,"1014525070618":1478686804062,"1025909516214":1509788667459,"1025909516212":1509788667402,"1014775447067":1478686804024,"1025909516213":1509788667458,"1025909516210":1509788667463,"1023405882614":1509788625003,"1025909516208":1509788667465,"1021287789119":1478686417101,"1025909516216":1509788667463,"1023946415265":1491634246531,"1025909516207":1509788667461,"1021858861221":1478686417053,"1024211307758":1509788624586,"1024211307752":1509788624587,"1024211307753":1509788624586,"1024211307751":1509788624587,"1024350534441":1509788625030,"1024211307745":1509788624587,"1021051306076":1478686417036,"1022428853940":1478686417070,"1024211307763":1509788624586,"1016495771887":1509788624941,"1024211307718":1509788624586,"1024211307742":1509788624587,"1025044681331":1509788624870,"1024211307741":1509788624587,"1787711864":1478686804015,"1024211307736":1509788624587,"1025044681333":1509788624870,"1024778871424":1509788624596,"1024778871425":1509788624596,"1025044681337":1509788624870,"1022073684807":1478686417060,"1024211307730":1509788624587,"1025044681341":1509788624870,"1022027024739":1478686417163,"1021041346080":1509788624971,"1021041346086":1509788624971,"1021041346084":1509788624971,"1024517912289":1509788624224,"1024517912290":1509788624224,"1021041346089":1509788624971,"1024517912291":1509788624224,"1024517912292":1509788624224,"1021041346095":1509788624971,"1021041346093":1509788624971,"1024517912295":1509788624224,"1025524562680":1509788667537,"1023999367137":1509788625017,"1021041346097":1509788624971,"1025524562682":1509788667537,"1025524562685":1509788667537,"1025100386374":1509788624181,"1025524562687":1509788667537,"1025524562673":1509788667537,"1024926719633":1509788624530,"1025524562675":1509788667537,"1023853092502":1491634246515,"1025524562678":1509788667537,"1021041346057":1509788624971,"1021041346062":1509788624971,"1021041346067":1509788624971,"1022438814405":1480585069100,"1021041346066":1509788624971,"1021041346064":1509788624971,"1022438814401":1480585069100,"1910918609":1444487341734,"1021041346068":1509788624971,"1021041346074":1509788624971,"1021041346078":1509788624971,"1312191094":1478686416992,"1022438814390":1480585069100,"1022339200135":1478686417069,"1023924525568":1509788624960,"1023450183370":1509788625082,"1022438814396":1480585069100,"1022096098568":1478686417012,"1022438814399":1480585069100,"1022438814393":1480585069100,"1024442284324":1509788624925,"1022438814372":1480585069100,"1022663862072":1509788624330,"712250912":1509788625020,"1011209882738":1478686804022,"1022276417755":1480585069095,"1022438814381":1480585069100,"1022438814377":1480585069100,"1021142301792":1478686417234,"1022438814356":1480585069100,"1024926719722":1509788624530,"1230271797":1444487341725,"1022438814352":1480585069100,"1025017551688":1509788625006,"1011593689903":1478686417220,"1021659243298":1478686417009,"1022438814362":1480585069100,"1023409027950":1491730251594,"1024798008888":1509788625175,"1025270647419":1509788624813,"1022438814336":1480585069100,"1021661733713":1509788624534,"1025270647423":1509788624814,"1013075338082":1478686804025,"1022438814339":1480585069100,"1021791492881":1478686417129,"1022438814348":1480585069100,"1022438814349":1480585069100,"1022663862035":1509788624330,"1022438814344":1480585069100,"1022438814347":1480585069100,"1023838412264":1509788624358,"1025270647434":1509788624813,"1023253021388":1509788625042,"1025276152658":1509788625017,"1017048527033":1478686804040,"1025270647436":1509788624813,"1022438814332":1480585069100,"1025270647426":1509788624814,"1021814166713":1478686417132,"1022068704363":1478686417060,"1022438814328":1480585069100,"1021928985559":1509788624466,"1022518898307":1509788625075,"1023838412262":1509788624358,"1023838412263":1509788624358,"1025270647429":1509788624814,"1021622673673":1478686417247,"1025270647450":1509788624813,"1025270647454":1509788624813,"1025270647455":1509788624814,"1025270647452":1509788624813,"1019416438158":1509788624314,"1025270647453":1509788624813,"1021661733823":1509788624195,"1025270647440":1509788624813,"1019049441369":1509788624283,"1025424161861":1509788625017,"1021693189607":1478686417249,"1025424161862":1509788625017,"1021693189606":1478686417249,"1021693189603":1478686417249,"1024926719522":1509788624530,"1025270647458":1509788624813,"1025270647459":1509788624813,"1023838412226":1509788624358,"1023838412227":1509788624358,"1025270647457":1509788624813,"1023838412228":1509788624358,"1023838412229":1509788624358,"1019448551325":1478686804021,"1023838412230":1509788624358,"1025270647460":1509788624814,"1021981413002":1478686417056,"1020815773964":1478686417078,"1025270647499":1509788624192,"1025270647496":1509788624192,"1025270647497":1509788624192,"1025270647502":1509788624192,"1021979315870":1478686417010,"1025270647490":1509788624192,"1025270647494":1509788624192,"1022352045261":1478686417289,"1023878914003":1491634246506,"1025270647495":1509788624192,"1022326881104":1478686417288,"1021929772025":1478686417142,"1025270647516":1509788624192,"1025270647517":1509788624192,"1022487964991":1478943089489,"1025270647511":1509788624192,"1004588292649":1444487341762,"1025270647528":1509788624192,"512238190":1478686417019,"1025270647532":1509788624192,"1025270647523":1509788624192,"1025270647520":1509788624192,"1025270647524":1509788624192,"1025270647525":1509788624192,"1008825851567":1480585069066,"1023846014439":1491634246537,"1021887697237":1478686417137,"1023838412176":1509788624358,"1021887697236":1478686417137,"1023838412177":1509788624358,"1001059921857":1478686417022,"1023838412178":1509788624358,"1021661733850":1509788624818,"1004605463247":1478686417222,"1004605463246":1478686417222,"1019219964881":1509788624317,"1010091955140":1491634246522,"1022219140328":1478686417064,"1024425769325":1509788624612,"1022071981532":1478686417012,"1022071981534":1478686417012,"1025270647579":1509788625128,"1025270647582":1509788625104,"1004605463258":1478686417222,"1025270647570":1509788625243,"1022567000138":1509788624836,"1004605463250":1478686417222,"1004605463249":1478686417222,"1024425769336":1509788624612,"1004605463248":1478686417222,"1025270647573":1509788625171,"1024991861640":1509788624210,"1025270647593":1509788625243,"1019526536524":1478686804031,"1025902305601":1509788667448,"1023397755526":1509788624516,"1025270647590":1509788625171,"1021399199201":1478686417106,"1021399199200":1478686417106,"1024546748002":1509788624959,"1021974990764":1478686417150,"1021604192765":1478686417300,"1021994913282":1478686417011,"1021559497750":1478686417245,"1017379085603":1478686804023,"1021559497746":1478686417245,"1025270647642":1509788624433,"1025270647643":1509788624433,"1025270647640":1509788624461,"1025270647641":1509788624424,"1025270647646":1509788624426,"1025270647644":1509788624424,"1021559497738":1478686417245,"1025270647645":1509788624507,"1025270647634":1509788624508,"1023745745333":1509788624835,"1021408636163":1478686417043,"1022343656924":1478686417069,"1025270647638":1509788624461,"1021611925856":1509788624404,"1025270647639":1509788624461,"1025270647636":1509788624508,"1025270647637":1509788624508,"1025270647659":1509788624508,"1020802142469":1478686417225,"1025270647649":1509788624461,"1025270647654":1509788624506,"1025344571091":1509788624294,"1022208654847":1480585069087,"1019463491927":1509788624353,"1025270647689":1509788625099,"960758976":1491634246534,"1024528791499":1509788625070,"1026226836102":1514456869768,"1025270647686":1509788625099,"1025270647685":1509788625099,"1022304598886":1478686417068,"1021262232199":1478686804039,"1024363118001":1509788624926,"1025270647705":1509788625099,"1001059921582":1478686417022,"1021906703128":1478686417140,"1025270647698":1509788625099,"1025270647702":1509788625099,"960759001":1491634246534,"1025270647723":1509788625099,"1025270647720":1509788625099,"1021407849955":1478686417240,"1025270647713":1509788625099,"1025270647718":1509788625099,"1025270647736":1509788625099,"1004769299888":1478686804064,"1025597175559":1509788624363,"1007839910574":1509788624374,"1020824555704":1509788624934,"1021551502435":1509788624397,"1023959651732":1509788624442,"1025270647728":1509788625099,"1023959651733":1509788624442,"1023959651730":1509788624442,"1025270647734":1509788625099,"1023959651731":1509788624442,"1025270647732":1509788625099,"1023959651729":1509788624442,"1025270647733":1509788625099,"1025270647759":1509788624532,"1024076960406":1509788624517,"1022014835188":1509788625075,"1024425769385":1509788624548,"1023959651839":1509788624861,"1025270647774":1509788624532,"1025270647775":1509788624532,"1020855489167":1478686416999,"1018568120914":1478686804040,"1025270647761":1509788624532,"1025270647787":1509788624532,"1024425769348":1509788624544,"1023020240334":1509788624990,"1024425769358":1509788624543,"1025524562689":1509788667537,"1024425769352":1509788624543,"1025034458569":1509788625090,"1024425769371":1509788624543,"1025874782198":1509788667715,"1022339200711":1478686417288,"1025865213116":1509788667836,"1022339200707":1478686417288,"1021498288364":1478686417046,"1022484819517":1478943089532,"1024333464043":1509788625031,"313928871":1491634246534,"1021173496912":1478686417038,"1021950217729":1478686417145,"1025865213100":1509788667831,"1022787329049":1509788624379,"1013043093734":1478686804028,"1024912039753":1509788624926,"1021852833261":1478686416974,"1023959651842":1509788624861,"1023959651843":1509788624861,"1023959651840":1509788624861,"313928857":1491634246534,"1023959651841":1509788624862,"1021852833267":1478686416974,"1016355396955":1465470268254,"1021852833270":1478686416974,"1025584723786":1509788625019,"1001059921152":1478686417022,"1022827305875":1509788624587,"1025513814989":1509788624451,"1025513814990":1509788624451,"165427098":1478686417023,"1829262148":1444487341746,"1021073457688":1478686417232,"1003833690014":1478686804051,"1025513815006":1509788624435,"1012903635825":1478686417074,"1025513814996":1509788624435,"1003833690001":1478686804051,"1023838412554":1509788624357,"1025513815022":1509788624434,"1023838412555":1509788624357,"1025513815017":1509788624435,"1017905867":1444487341761,"1021138501149":1478686416986,"1021139287585":1478686417096,"1025513815013":1509788624435,"1021173496877":1478686417038,"1025399619599":1509788624294,"1009744488427":1491634246512,"1003833690038":1478686804051,"1022217436797":1478686417192,"1018988756504":1509788624314,"1022481149643":1478943089488,"1021018933021":1509788624970,"1019246571955":1509788624316,"1025890903480":1509788667403,"1022610777663":1509788625161,"1023262589268":1509788625042,"1547330215":1478950494925,"1025890903471":1509788667403,"1023959651982":1509788624226,"1023959651978":1509788624226,"1023959651979":1509788624226,"746459865":1444487341727,"1023959651977":1509788624226,"1023959651975":1509788624226,"1021906833442":1478686417054,"1022040786979":1478686416987,"1021040952458":1478686417092,"1014847010779":1478686804028,"1022932555230":1509788625018,"1025711337340":1509788624345,"1022385337549":1478686417069,"1025865213041":1509788667833,"4955445646":1509788624159,"1022081287924":1478686417061,"1024912039865":1509788624926,"1023959652091":1509788624564,"1023959652088":1509788624564,"1023959652089":1509788624564,"1001059921378":1478686417022,"1023959652087":1509788624564,"1022748532389":1509788624467,"1837519706":1491634246516,"1021817706276":1478686417132,"1023959652083":1509788624564,"1837519704":1491634246516,"1017411066975":1509788624334,"1018918994503":1509788624317,"1024939433260":1509788625135,"1019637946656":1509788624313,"1020980136227":1478686417034,"1837519713":1491634246516,"1021069001331":1478686417093,"1021437996147":1478686417007,"1025865213001":1509788667465,"1021153705877":1478686417300,"1022610777676":1509788625161,"1363570619":1491634246524,"1022610777673":1509788625161,"1022610777674":1509788625161,"1022610777675":1509788625161,"1008116729752":1478686804028,"1021894382145":1509788624466,"1020790871069":1478686417077,"1023838412412":1509788624357,"1023838412413":1509788624357,"1023838412414":1509788624357,"1023838412415":1509788624357,"1009042640978":1478686804061,"1022476562351":1478943089315,"1009042640980":1478686804061,"1023838412360":1509788624358,"1023838412361":1509788624358,"1022956933939":1509788625101,"1023838412362":1509788624358,"1829524005":1478686804033,"1019220357507":1509788625020,"1023838412358":1509788624357,"1023838412359":1509788624358,"1008289381730":1509788624310,"1025516436050":1509788624341,"1016339275089":1478686804031,"1021262231598":1478686804039,"1022480494392":1478943089488,"1023838412328":1509788624357,"1023838412324":1509788624358,"1022480494389":1478943089488,"1023838412325":1509788624358,"1023838412326":1509788624358,"1023838412327":1509788624358,"1021778123017":1480585069060,"1023838412296":1509788624358,"1022350210909":1478686417015,"1023838412297":1509788624358,"1023838412295":1509788624358,"1018907198469":1509788625019,"1019315252340":1509788625079,"1022208655349":1480585069087,"1023838412307":1509788624358,"1023838412308":1509788624358,"1021514934425":1509788624419,"1023838412309":1509788624358,"1023838412310":1509788624358,"1021445729677":1478686417107,"1023838412512":1509788624357,"1023838412513":1509788624357,"1023838412514":1509788624357,"1022956934047":1509788624533,"1008601590322":1478686804030,"1013075337349":1478686804025,"1023838412536":1509788624357,"1014775446063":1478686804024,"1000237751715":1444487341762,"491004632":1444487341723,"1023838412535":1509788624357,"1022238670179":1509788624947,"1025431896006":1509788624176,"1023927409034":1491634246529,"785650021":1491634246513,"1023838412510":1509788624357,"1015319779997":1465470268246,"1023838412511":1509788624357,"1021575095748":1509788624405,"1022155735656":1478686417277,"1025412857971":1509788624201,"1021079093799":1478686417002,"1025412857972":1509788624205,"1025412857975":1509788625126,"1025412857976":1509788625109,"1025412857977":1509788624186,"1023932258363":1491634246531,"1022320064569":1478686417288,"1023838412473":1509788624357,"1023838412474":1509788624357,"1023838412475":1509788624357,"1023838412476":1509788624357,"1023838412471":1509788624357,"1024912039563":1509788624926,"1019817905899":1465470268275,"1023838412416":1509788624357,"1022861514826":1509788625053,"1023838412417":1509788624357,"1008833715258":1480585069066,"1025900321920":1509788667457,"1014803466219":1478686804064,"1000526099680":1444487341712,"1000526099682":1444487341713,"1019717626639":1509788625079,"1023307546882":1509788625041,"1005662791380":1480585069065,"1024579259735":1509788624959,"1020975707666":1478686417001,"1716266604":1444487341737,"1022921566782":1509788624293,"1000526099677":1444487341725,"1025485472612":1509788624425,"1019953690925":1509788624319,"1019953690924":1509788624319,"1019953690923":1509788624319,"1019953690922":1509788624319,"1019953690921":1509788624319,"1025485472610":1509788624429,"1025485472611":1509788624431,"1025011410910":1509788624180,"1025011410911":1509788624180,"1025011410908":1509788624180,"1025011410909":1509788624180,"1023994374778":1491634246518,"1022869137252":1509788625151,"1021380825015":1478686416991,"1021914164844":1509788624509,"1022349035641":1478686417069,"1021296150856":1478686417041,"1022028199185":1478686417164,"1018404166959":1509788625019,"1024771021201":1509788667537,"1022869137226":1509788625151,"1024846257427":1509788624949,"1022869137227":1509788625151,"1022869137225":1509788625151,"1022869137223":1509788625151,"1024552783000":1509788624185,"1024491178221":1509788625028,"1008738540805":1444487341761,"1025015473975":1509788625006,"1023702342140":1509788624225,"1023702342137":1509788624225,"1021397209236":1509788624394,"1025011410912":1509788624180,"1023702342138":1509788624225,"1023702342139":1509788624225,"1022451404476":1478686417296,"4994787644":1509788667395,"1002491619660":1478950494936,"1022492168501":1478943089490,"1021789775632":1509788624394,"1021647822464":1509788624396,"1020995762250":1478686417001,"1020910826334":1509788624971,"1004790788705":1480585069067,"401495893":1444487341737,"1005786131885":1480585069074,"1022101862954":1478686417275,"1010024737285":1491634246527,"1018513482761":1509788625227,"1018513482759":1509788625227,"1022277600346":1478686417197,"1018513482754":1509788625227,"1018513482752":1509788625227,"1019525210188":1509788625077,"1018513482781":1509788625227,"1000777204418":1478686417018,"1018513482780":1509788625227,"1021902106151":1509788624402,"1018513482776":1509788625227,"1011607324751":1478686417018,"1018513482772":1509788625227,"1018513482787":1509788625227,"1018513482786":1509788625227,"1022254138136":1509788624363,"1018513482785":1509788625227,"1018513482784":1509788625227,"1022380362368":1478686417205,"1022101862937":1478686417275,"1022406052925":1478686417070,"1025900321919":1509788667462,"1022116674313":1478686417183,"1024327827288":1509788625086,"1024327827280":1509788625086,"1021867372008":1509788624394,"1009854210557":1491634246520,"1022482731339":1478943089488,"1024518179780":1509788624219,"1024518179781":1509788624219,"1021959123021":1478686417010,"1024518179782":1509788624219,"4994787476":1509788667395,"1022400154118":1478686417292,"1024518179779":1509788624219,"1024518179784":1509788624219,"1024501532876":1509788625070,"1021485552789":1478686417110,"1022038030318":1478686417301,"1021648477995":1509788624396,"1021489222737":1478686417243,"1018513352177":1509788624602,"1025612876517":1509788625018,"1021861079556":1509788624434,"1021861079566":1509788624435,"1021861079575":1509788624451,"1021861079581":1509788624452,"4972898610":1509788624159,"1021346090312":1478686417005,"1020993009247":1478686417001,"1022208655854":1480585069087,"1019028308827":1509788624314,"1020993009255":1478686417001,"1012834144285":1478686417026,"1024077344320":1509788624521,"923301475":1491634246505,"210259428":1478686804029,"1010396299735":1478686804068,"1021183296196":1478686804018,"1021861079605":1509788624427,"1010396299727":1478686804068,"1024926737407":1509788624189,"1020294254556":1465470268299,"1021861079600":1509788624440,"1021739312637":1478686417124,"1025746571989":1509788624393,"1022733737531":1509788624827,"1025612876504":1509788625018,"1024926737399":1509788624189,"1021346090389":1478686417005,"1022117723032":1478686417276,"1021822150710":1509788624989,"1021941690654":1478686417143,"1024518179695":1509788624855,"1024518179700":1509788624855,"1024518179698":1509788624855,"1024518179699":1509788624855,"4994787360":1509788667395,"1024518179704":1509788624855,"1021867371897":1509788624399,"1022919469966":1509788625018,"1024341065267":1509788624437,"1288834422":1509788625018,"1020956046576":1478686417033,"1021900664646":1478686417259,"1021900664645":1478686417259,"1024273037875":1509788624176,"1022953680279":1509788624291,"1024273037876":1509788624176,"4997146733":1509788667395,"1011618465793":1478686804061,"1011618465792":1478686804061,"1020102886388":1509788624369,"1020665718095":1478686417075,"1022226350165":1478686417013,"1024912056481":1509788624926,"1021803932031":1478686417255,"1022561113178":1509788624375,"1022561113177":1509788624375,"1022561113174":1509788624375,"1022561113175":1509788624375,"1021816383538":1478686417300,"1022561113173":1509788624375,"1021313583617":1465469681398,"1022600697540":1509788625062,"1124336381":1509788625016,"1013075452183":1478686804066,"1025772000808":1509788624844,"1021795673384":1478686417255,"1025772000809":1509788624844,"1024370459607":1509788624926,"1024517785824":1509788624450,"1024517785825":1509788624450,"1024517785828":1509788624450,"1013075452667":1478686804066,"1019600840207":1509788624971,"1022182734881":1478686417187,"1024370459592":1509788624926,"1018513483477":1509788625228,"1024992273538":1509788624278,"1024093467248":1509788624523,"228216759":1444487341737,"1020293991553":1465470268279,"1025796379898":1509788624274,"1018513483519":1509788625228,"1020436861976":1478686804027,"1024517785823":1509788624450,"1024517785821":1509788624450,"1018513483508":1509788625228,"1021427880715":1478686804026,"1003271804160":1478686416993,"1025078651359":1509788624178,"1026226564470":1514456869770,"1001461016859":1478686417022,"1026226564475":1514456869770,"1014152979096":1478686804071,"1021347139517":1478686417005,"1021347139519":1478686417005,"1021081747328":1478686417094,"1026226564460":1514456869770,"1021975507148":1478686417263,"1021287238597":1465470268201,"1020073132971":1465470268321,"1021483587494":1478686417007,"1021629210452":1478686417049,"1024640078785":1509788667536,"1022953680451":1509788624291,"1016848876143":1478686804046,"1022120343939":1478686417183,"1008664615811":1478686804030,"1018513483448":1509788625228,"1025078651360":1509788624335,"1022733737408":1509788624827,"1021739312647":1478686417124,"1020323353193":1509788625078,"4997147484":1509788667395,"1021739312655":1478686417124,"1021739312663":1478686417124,"1026226564514":1514456869770,"1012651295942":1509788625017,"1021739312659":1478686417124,"1026226564519":1514456869769,"1022025316096":1478686417163,"1019210502105":1509788625077,"1023354996472":1509788625156,"1023354996473":1509788625156,"1022425714462":1478686417016,"1023354996474":1509788625156,"1026226564499":1514456869768,"1021788595473":1478686417129,"1023354996477":1509788625156,"1026226564504":1514456869770,"1023901705998":1509788625038,"1023354996471":1509788625156,"1020800462382":1478686417077,"1025098313415":1509788624292,"1022003164789":1478686417266,"1022073813619":1478686417060,"1025524008919":1509788624612,"1025524008920":1509788624543,"1024545704330":1509788667848,"1021576124557":1509788624405,"1017120854787":1478686804067,"1024992273522":1509788624279,"1021893849003":1478686417138,"1024992273529":1509788624279,"1021893849005":1478686417138,"1024992273533":1509788624278,"1025524008946":1509788624548,"1025524008947":1509788624867,"1025524008949":1509788624612,"1021447278859":1509788624432,"1023453431954":1509788625008,"1022301587442":1478686417199,"1025524008929":1509788624566,"1025710920504":1509788624305,"1019688003635":1509788624315,"1022733737026":1509788624539,"1831611937":1491634246507,"1001328500781":1444487341701,"1025077340333":1509788624309,"1019862202186":1509788624389,"1022598599784":1509788624437,"1023702342318":1509788624450,"1023702342319":1509788624450,"4994787995":1509788667395,"1020294122906":1465470268291,"1023702342320":1509788624450,"1023702342321":1509788624450,"1023702342322":1509788624450,"1024187184515":1509788624502,"1024187184512":1509788624502,"1024352371705":1509788624927,"1021501674902":1478686416975,"1024198718632":1509788667890,"1010268928793":1478686804055,"1022073420780":1478686417176,"1025118367328":1509788625022,"1022723382426":1509788625058,"1022467918929":1478686417072,"1023000472584":1509788624426,"1022256627881":1478686417067,"1020212202229":1478686804066,"1016634472371":1478686804069,"1018513483598":1509788625228,"1024187184444":1509788625231,"1025485471967":1509788625125,"1024187184445":1509788625231,"1024187184443":1509788625231,"1000216240870":1444487341750,"1023702342146":1509788624225,"1018513483592":1509788625228,"1020969416161":1478686417229,"1023538105542":1509788625002,"1023538105543":1509788625002,"1024187184439":1509788625231,"1023538105540":1509788625002,"1023538105541":1509788625002,"1024187184437":1509788625231,"1023538105539":1509788625002,"1024187184435":1509788625231,"1018513483585":1509788625228,"1024187184430":1509788625231,"1022169496944":1509788624924,"1024187184431":1509788625231,"1024187184428":1509788625231,"1024187184426":1509788625230,"4994787875":1509788667395,"1024187184422":1509788625230,"1024988734817":1509788667503,"1018513483604":1509788625228,"1016263531894":1458304307281,"1024988734820":1509788667503,"1024187184419":1509788625230,"1024187184416":1509788625231,"1024187184414":1509788625230,"1024187184415":1509788625231,"1024988734809":1509788667503,"1016190917372":1509788624944,"1024988734810":1509788667503,"1024988734811":1509788667503,"1024988734812":1509788667503,"1025569623037":1509788624349,"1024187184411":1509788625231,"1023097206288":1509788625016,"1024187184408":1509788625231,"1024988734814":1509788667503,"1024988734815":1509788667503,"1024187184407":1509788625231,"1020969416131":1478686417229,"1024187184403":1509788625231,"1018513483617":1509788625227,"1024187184401":1509788625230,"1020969416152":1478686417229,"1018513483637":1509788625228,"1018513483636":1509788625227,"1021126048906":1478686417233,"1025485471971":1509788625089,"1024187184511":1509788624502,"1024938270776":1509788667503,"1024187184509":1509788624502,"1024187184506":1509788624502,"1018513483531":1509788625228,"1023354996638":1509788624559,"1024187184505":1509788624502,"1024187184502":1509788624502,"1024187184503":1509788624502,"1024187184500":1509788624501,"1024187184501":1509788624501,"1024187184498":1509788624501,"1024370459166":1509788624927,"1024187184496":1509788624501,"1024187184494":1509788624501,"1023702342228":1509788624862,"1023702342229":1509788624862,"1024187184492":1509788624501,"1024187184493":1509788624501,"1018513483548":1509788625228,"1024187184490":1509788624502,"1023702342225":1509788624862,"1023702342226":1509788624862,"1024187184489":1509788624501,"1023702342227":1509788624862,"1020969416112":1478686417229,"1021485160054":1478686804065,"1024187184487":1509788624501,"1017403056836":1478686804020,"1022401464533":1478686417292,"1022401464531":1478686417292,"1024187184480":1509788624501,"1024187184478":1509788624502,"1018513483567":1509788625228,"1024187184479":1509788624501,"1024187184476":1509788624501,"1024187184477":1509788624502,"1022220059162":1478686417192,"1023657252272":1509788667538,"1020314307696":1478686804026,"1018220007842":1465470268270,"1018513483553":1509788625227,"1010025392432":1491634246527,"1024370459170":1509788624927,"1025428849480":1509788624407,"1018513483578":1509788625228,"1010025392424":1491634246527,"1025428849476":1509788624426,"1023354996640":1509788624559,"1022076959644":1509788624439,"1023354996641":1509788624560,"1023354996642":1509788624559,"1024187184452":1509788625231,"1024187184450":1509788625231,"1025428849474":1509788624429,"1022253482015":1509788624277,"1025428849475":1509788624431,"1023354996647":1509788624559,"1024187184449":1509788625231,"1021924780951":1478686417141,"1022341696689":1478686417202,"1019929574517":1509788624932,"1004769293339":1478686804064,"1021921110991":1509788624465,"1022328718202":1478686417201,"1021443741189":1478686417241,"1007916738655":1478686804032,"1945647054":1478686417024,"1018513481975":1509788625226,"1716265585":1444487341736,"1018513481970":1509788625226,"1007840453421":1509788624392,"1022736620405":1509788624301,"1023569171926":1509788624516,"1024187183868":1509788624909,"1019260965912":1509788624313,"1024187183867":1509788624909,"1024187183863":1509788624909,"1024187183861":1509788624908,"1021985208241":1478686417153,"1023569171929":1509788624516,"1024187183859":1509788624909,"1022179195395":1478686417278,"1024187183856":1509788624909,"1021985208242":1478686417153,"1024187183854":1509788624908,"1024187183852":1509788624909,"1024187183851":1509788624909,"1024187183849":1509788624909,"1022445505079":1478686417016,"1024187183847":1509788624909,"1020447085524":1478686804047,"1024187183845":1509788624908,"1023569171914":1509788624516,"1022445505073":1478686417016,"1023076364437":1509788625152,"1023076364432":1509788625152,"1021796852561":1509788624394,"1022125195253":1478686417183,"1020294253272":1465470268299,"1023076364429":1509788625152,"1023076364430":1509788625152,"1023076364431":1509788625152,"1024187183676":1509788624606,"1024187183674":1509788624605,"1024557238326":1509788625026,"1024187183673":1509788624605,"1024187183670":1509788624605,"1024187183666":1509788624605,"1023076364388":1509788624447,"1024187183662":1509788624605,"1023076364389":1509788624447,"1023076364390":1509788624447,"1023076364391":1509788624447,"1022478930948":1478943089224,"1024187183658":1509788624605,"1024187183656":1509788624605,"1024187183657":1509788624605,"1023076364392":1509788624447,"1021758448064":1478686417051,"1024187183644":1509788624605,"1021251846932":1478686417236,"1022381674239":1478686417290,"1024187183642":1509788624605,"1022458612480":1478686417016,"1024187183640":1509788624605,"1018513350759":1509788624499,"1024187183636":1509788624605,"1024187183634":1509788624606,"1021173466862":1465470268186,"1024187183632":1509788624605,"1021953488238":1478686417146,"1024187183633":1509788624606,"1021173466865":1465470268186,"1000476030302":1478950494933,"1021173466864":1465470268186,"1023987953197":1509788624229,"1021704840704":1478686417050,"1019169738607":1509788624375,"1022161238438":1478686417063,"1020136702151":1480585069064,"1024518180396":1509788624560,"1024518180397":1509788624560,"324949908":1491634246534,"1024518180398":1509788624560,"1020294122082":1465470268291,"1009593242706":1509788624372,"1024518180394":1509788624560,"1020709495588":1509788624934,"1022041698897":1478686417170,"4994788708":1509788667395,"1024518180403":1509788624560,"1784295043":1444487341731,"1021914163928":1509788624467,"1187381796":1491634246518,"1021821627738":1478686417009,"1023242697247":1509788624462,"1024187183688":1509788624606,"1024187183686":1509788624606,"1024187183687":1509788624606,"1024187183684":1509788624605,"1024187183685":1509788624605,"1024187183683":1509788624605,"1024187183681":1509788624606,"1022075911573":1509788624393,"1024187184063":1509788624265,"1024187184060":1509788624265,"1024187184061":1509788624265,"1022075911574":1509788624393,"1024187184058":1509788624264,"1022075911569":1509788624393,"1024187184059":1509788624265,"1024187184056":1509788624265,"1022075911571":1509788624393,"1024187184057":1509788624265,"1021908134813":1478686417140,"1024187184054":1509788624265,"1024187184055":1509788624265,"1022246012792":1478686417066,"1024187184052":1509788624264,"1022075911577":1509788624393,"1022075911576":1509788624393,"1021154985079":1478686417002,"1443500804":1491634246515,"1022567141408":1509788624867,"1022075911578":1509788624393,"4994788519":1509788667395,"1021427881000":1478686804065,"1021207675261":1478686804050,"4997147891":1509788667395,"1023566681232":1491634246536,"1025882496671":1509788667465,"1687822772":1444487341737,"1016857658547":1509788624976,"1019826288574":1509788624959,"1021706151857":1478686417009,"1023566681224":1491634246536,"1021908134816":1478686417140,"1016670647187":1478686804018,"1021908134818":1478686417140,"1023566681222":1491634246536,"1023566681223":1491634246536,"1025900583387":1509788667461,"1022454155943":1478686417302,"1016406139706":1478686804016,"1021506130747":1509788624401,"1024146421337":1509788625102,"1018513482134":1509788625226,"1022454155952":1478686417302,"1021142009155":1478686417096,"1024187184090":1509788624265,"1024187184089":1509788624265,"1024187184086":1509788624265,"1024187184084":1509788624265,"1024187184083":1509788624265,"1024187184080":1509788624265,"1024187184076":1509788624265,"1020436861788":1478686804027,"1024187184070":1509788624265,"1024187184071":1509788624265,"1024187184068":1509788624265,"1024187184066":1509788624265,"1020709495447":1509788624934,"1022977403814":1509788625050,"1024187184067":1509788624265,"1022428596462":1478686417294,"1024187184064":1509788624265,"1021432469362":1478686804027,"1021048192607":1478686417232,"1021048192606":1478686417232,"1018513482058":1509788625226,"1018513482053":1509788625226,"1017564147436":1478686804020,"1018513482078":1509788625226,"1020261484845":1478686804026,"1011783489415":1478686804027,"1021777585097":1478686417052,"1021207675329":1478686804050,"1021700515680":1478686804046,"1021502853925":1478686417244,"1018513482071":1509788625226,"1021502853924":1478686417244,"1018513482064":1509788625226,"1018513482089":1509788625226,"1024187183890":1509788624909,"1018513482083":1509788625226,"1021795672708":1478686417255,"1024187183891":1509788624909,"1020994977097":1478686417088,"1024187183889":1509788624909,"1024187183885":1509788624909,"1024187183883":1509788624909,"1024187183880":1509788624909,"1018513482104":1509788625226,"1024187183878":1509788624909,"1024187183879":1509788624909,"1024187183876":1509788624909,"1024187183877":1509788624909,"1018513482097":1509788625226,"1021935531336":1478686417055,"1024187183873":1509788624909,"1021739311429":1478686417124,"1021739311425":1478686417124,"1017241967984":1478686804025,"1021428012274":1478686804026,"1021427881203":1478686804026,"1021207675292":1478686804050,"1022341827958":1478686417202,"1020102887417":1509788624369,"1008662650331":1478686804034,"1022255187466":1478686417284,"1023987953491":1509788624230,"1010386500254":1509788624276,"1020802034103":1478686417077,"1021207675265":1478686804050,"976912364":1478950494919,"1025019142879":1509788624825,"1021482405929":1478686417110,"1021739311450":1478686417124,"1021739311460":1478686417124,"1018513482030":1509788625226,"1021207675319":1478686804050,"1021264432403":1478686417237,"1016396308726":1478686804017,"1023829877765":1509788667494,"1018513482047":1509788625226,"1018513482045":1509788625226,"1022064374482":1478686417270,"1018513482040":1509788625226,"1021207675310":1478686804050,"4942488421":1509788624159,"1023834596445":1491634246536,"1025505133108":1509788624338,"1025505133110":1509788624340,"1022465689938":1478686417016,"1019015464171":1509788624361,"1022465689939":1478686417017,"1018335092576":1478686804022,"1025771999803":1509788624453,"4997148620":1509788667397,"898790321":1491634246511,"1019778443586":1509788625078,"4994789249":1509788667397,"1022208657072":1480585069087,"1500520214":1478950494923,"1024786619523":1509788624512,"1187381430":1491634246519,"1022149311044":1480585069075,"1021631699809":1509788624420,"1025514963949":1509788624337,"1021569440978":1509788624397,"1024723570906":1509788667888,"1019164363904":1509788624316,"1000966735913":1478686417021,"1022487058067":1478943089489,"1024926737421":1509788624189,"1022988544183":1509788625073,"1024926737410":1509788624189,"1024926737415":1509788624189,"1024926737434":1509788624189,"1024926737432":1509788624189,"1021482406753":1478686417110,"1024926737438":1509788624189,"1024926737436":1509788624189,"1024926737424":1509788624189,"1024926737430":1509788624189,"1024926737431":1509788624189,"1024926737428":1509788624189,"1024926737429":1509788624189,"1024926737451":1509788624189,"1014229787264":1478686804071,"1019728243397":1509788624315,"1017564147139":1478686804020,"1019728243396":1509788624317,"1025593085013":1509788624929,"1024926737443":1509788624189,"1024926737440":1509788624189,"1019728243405":1509788624315,"1024926737441":1509788624189,"1024926737446":1509788624189,"1024926737444":1509788624189,"1022438819910":1480585069078,"1022438819911":1480585069078,"1024926737458":1509788624189,"1024926737456":1509788624189,"1024926737457":1509788624189,"1022438819892":1480585069077,"1008870269808":1509788624372,"1022438819893":1480585069077,"1022438819894":1480585069077,"1022438819895":1480585069077,"1022438819888":1480585069077,"1022438819889":1480585069077,"1019204995953":1478686804020,"1024926737485":1509788624530,"1022438819902":1480585069078,"1022438819896":1480585069078,"1022438819899":1480585069078,"1024926737496":1509788624530,"1024926737497":1509788624530,"1024926737502":1509788624530,"1022438819884":1480585069077,"1022438819885":1480585069077,"1022438819887":1480585069077,"1024926737489":1509788624530,"1022438819881":1480585069077,"1022438819883":1480585069077,"1019759568986":1509788624280,"1018513351186":1509788624499,"1022438819860":1480585069104,"1024926737515":1509788624530,"1023018563237":1509788625049,"1022438819858":1480585069104,"1018883898429":1509788624287,"1022438819859":1480585069104,"1024926737504":1509788624530,"1024926737505":1509788624530,"1019527177871":1509788624316,"1024926737511":1509788624530,"1024926737508":1509788624530,"1009505160489":1478686804071,"1022438819845":1480585069104,"1022438819846":1480585069104,"1022438819847":1480585069104,"1022438819840":1480585069104,"1022438819842":1480585069104,"1022438819843":1480585069104,"1019527177876":1509788624317,"1022438819852":1480585069104,"1022438819855":1480585069104,"1022438819848":1480585069104,"1022438819849":1480585069104,"1022438819850":1480585069104,"1022984087690":1509788625050,"1023540725795":1509788624183,"4976832430":1509788624161,"1018546512378":1480585069070,"1020849481916":1478686417031,"1021789380764":1509788624993,"1025561890743":1509788624344,"1016758598720":1478686804031,"1018513482730":1509788625227,"1020780801165":1478686417225,"1025679198455":1509788624350,"1025679198457":1509788624350,"1022208657314":1480585069087,"1021370075557":1509788624441,"1018513482747":1509788625227,"1011593691248":1478686417220,"4972900188":1509788624161,"1017151264036":1478686804053,"1018513482741":1509788625227,"1018513482738":1509788625227,"1023233522347":1509788667538,"1011618467463":1478686804061,"1187381634":1491634246519,"1011618467467":1478686804061,"1187381646":1491634246519,"1011618467466":1478686804061,"1022598598663":1509788624462,"1011618467465":1478686804061,"1020878321333":1509788624934,"1011618467468":1478686804061,"1021789380830":1509788624993,"1016758598712":1478686804023,"1009839528084":1491634246520,"1009710813434":1480585069062,"1020770839858":1478686417225,"1025180366365":1509788624213,"1024837999220":1509788624948,"1025628474178":1509788624186,"1025628474176":1509788624197,"1021921372168":1478686417010,"1187381601":1491634246519,"1022043664841":1509788625076,"1021247914079":1478686417003,"1020790500487":1478686416997,"1023748742001":1491634246536,"1019166067799":1478686804020,"1021789380667":1509788624993,"1021188408524":1478686417038,"1187381619":1491634246519,"1024154546952":1509788667409,"4994788875":1509788667397,"1021929629931":1478686417142,"1022108548426":1478686417182,"1018087624189":1509788624362,"1023786359123":1509788624300,"1021729744109":1478686417124,"1022166743767":1478686417186,"1021729744103":1478686417124,"1021729744102":1478686417124,"4997148223":1509788667397,"1008738540175":1444487341761,"1187381539":1491634246519,"1187381537":1491634246519,"1025628474174":1509788624200,"1025628474175":1509788624204,"1021992285286":1478686417155,"1023900525096":1491634246510,"1022438819573":1480585069102,"1022438819574":1480585069102,"1022438819575":1480585069102,"1021432470263":1478686804065,"1022438819568":1480585069102,"1022438819569":1480585069102,"1023219889216":1509788625018,"1022438819580":1480585069102,"1020966403767":1478686417001,"1020908599813":1478686417080,"1022438819576":1480585069102,"1022438819578":1480585069102,"1021209513014":1478686417099,"1022438819579":1480585069102,"1024411487055":1509788624818,"1022438819556":1480585069102,"1024136199096":1509788624490,"1024136199097":1509788624490,"1024411487058":1509788624420,"1022303686390":1478686417199,"1022438819552":1480585069102,"1024452251367":1509788667888,"1022438819554":1480585069102,"1022438819564":1480585069102,"1022438819565":1480585069102,"1022438819566":1480585069102,"1024452251368":1509788667888,"1022438819560":1480585069102,"1022438819562":1480585069102,"1024136199094":1509788624489,"1022438819563":1480585069102,"1017809646301":1509788624286,"1024136199095":1509788624490,"1019261229178":1509788624301,"1016547042851":1509788624367,"1016547042853":1509788624367,"1022438819548":1480585069102,"1015240337871":1480585069068,"1022438819551":1480585069102,"1020781192079":1478686416997,"1022438819546":1480585069102,"1022438819547":1480585069102,"1024846255428":1509788624949,"1021599061212":1478686416989,"1015496587395":1478686804032,"1024136199146":1509788624489,"1022328196904":1478686417201,"1024136199148":1509788624490,"1024136199149":1509788624489,"1024136199150":1509788624489,"1024136199142":1509788624490,"1021276881018":1478686417040,"1022501476712":1509788624538,"1016263530169":1458304307281,"1022438819488":1480585069102,"1022438819489":1480585069102,"1022438819490":1480585069102,"1022438819476":1480585069102,"1021225241929":1509788624170,"1024136199112":1509788624490,"1024136199113":1509788624490,"1022438819478":1480585069102,"1024136199115":1509788624490,"1022438819474":1480585069102,"1024136199118":1509788624490,"1022438819475":1480585069102,"1024136199119":1509788624490,"1022438819484":1480585069102,"1024136199106":1509788624490,"1022438819487":1480585069102,"1022438819480":1480585069102,"1025604485704":1509788625242,"1022438819481":1480585069102,"4985872704":1509788624160,"1024136199111":1509788624490,"1022438819460":1480585069102,"1022438819461":1480585069102,"5001732688":1509788667396,"1021056971557":1478686417001,"1022438819456":1480585069102,"1022438819457":1480585069102,"1022438819458":1480585069102,"1024136199134":1509788624490,"1022438819459":1480585069102,"1024136199135":1509788624490,"1024136199120":1509788624490,"1022438819469":1480585069102,"1025497533694":1509788624367,"1024136199122":1509788624489,"1022438819464":1480585069102,"1024136199125":1509788624490,"1022438819466":1480585069102,"1024584762988":1509788624960,"5001732769":1509788667396,"1021262204823":1478686804039,"1021848232590":1509788624854,"1022438819453":1480585069102,"1019884486077":1478686804070,"1019884486076":1478686804070,"1022438819455":1480585069102,"1022438819428":1480585069102,"1022438819429":1480585069102,"1022438819430":1480585069102,"1018335089147":1478686804022,"1022438819426":1480585069102,"1021848232594":1509788624854,"1021848232593":1509788624854,"1022428595467":1478686417294,"1021432470127":1478686804065,"1021848232599":1509788624854,"1021981670058":1509788625068,"1018513353837":1509788624262,"1008531446112":1478686804015,"1022476965932":1478943089487,"1022438819408":1480585069102,"1022438819410":1480585069102,"1022438819420":1480585069102,"1018925577463":1509788624316,"1022438819421":1480585069102,"1022438819422":1480585069102,"1022438819416":1480585069102,"1022438819418":1480585069102,"1022438819419":1480585069102,"1022438819397":1480585069101,"1022438819399":1480585069101,"1022438819392":1480585069101,"1022438819394":1480585069101,"1022438819395":1480585069101,"1022438819404":1480585069101,"1022438819405":1480585069101,"1024803787588":1509788625136,"1023702339896":1509788624419,"1022438819402":1480585069101,"1025529384448":1509788624342,"1023453430456":1509788625008,"1016936435210":1478686804042,"1016936435208":1478686804042,"1016936435209":1478686804042,"1022438819389":1480585069101,"1025289285669":1509788624335,"1025884590937":1509788667467,"1022438819386":1480585069101,"1001959063899":1478686417023,"1021413595339":1509788624508,"1022234872262":1478686417065,"1022438819350":1480585069101,"1022438819344":1480585069101,"1022438819356":1480585069101,"1022438819357":1480585069101,"1022438819358":1480585069101,"1022438819359":1480585069101,"1012146561189":1478686417073,"1022438819353":1480585069101,"1022438819333":1480585069101,"1022438819334":1480585069101,"1022438819335":1480585069101,"1025289285661":1509788624343,"134627570":1444487341745,"1022438819328":1480585069101,"1022438819329":1480585069101,"1022438819330":1480585069101,"1021543747803":1509788624401,"1022438819340":1480585069101,"1022438819342":1480585069101,"1022438819336":1480585069101,"1022438819337":1480585069101,"1022438819338":1480585069101,"1022438819829":1480585069104,"1022438819830":1480585069104,"1022438819831":1480585069104,"1022438819825":1480585069104,"1024463392558":1509788624428,"1022438819827":1480585069104,"1022438819836":1480585069104,"1022438819837":1480585069104,"1022438819838":1480585069104,"1022192301716":1478686417279,"1001959063696":1478686417023,"5001732865":1509788667396,"1021260631596":1465470268201,"1022438819780":1480585069104,"1022438819781":1480585069104,"1024411486833":1509788625101,"1023924514676":1509788624948,"1022438819783":1480585069104,"1022438819776":1480585069104,"1022438819777":1480585069104,"1021685311717":1509788624396,"4848511429":1509788624160,"1022438819784":1480585069104,"1022438819786":1480585069104,"1022438819787":1480585069104,"1021610071321":1509788624401,"1022438819765":1480585069103,"1022438819766":1480585069103,"1022438819767":1480585069104,"1453858797":1478950494923,"1022438819761":1480585069103,"1022438819762":1480585069103,"1022438819763":1480585069103,"1024411486727":1509788624534,"1022438819772":1480585069104,"1022438819774":1480585069104,"1021386327805":1478686417006,"1022438819748":1480585069103,"1022438819750":1480585069103,"1001959063765":1478686417023,"1022438819757":1480585069103,"1022438819758":1480585069103,"1022438819759":1480585069103,"1007443827168":1480585069069,"1022438819754":1480585069103,"1022438819733":1480585069103,"1000966735823":1478686417021,"1022438819734":1480585069103,"1022438819735":1480585069103,"1021928056353":1478686417142,"1022438819728":1480585069103,"1022438819731":1480585069103,"1021682035068":1478686417120,"1021644674905":1478686417119,"1022438819717":1480585069103,"1025527549864":1509788624469,"1303381187":1444487341716,"1022438819719":1480585069103,"1022438819712":1480585069103,"1009710685935":1480585069062,"1022438819715":1480585069103,"1025839501658":1509788667844,"1020613814470":1478686417027,"1022438819727":1480585069103,"1022438819720":1480585069103,"1023702339832":1509788624819,"1022438819721":1480585069103,"1022438819723":1480585069103,"1025796382635":1509788624274,"1023165755395":1509788625044,"1022438819699":1480585069103,"1022477359360":1478943089230,"1022438819709":1480585069103,"1022438819710":1480585069103,"1022438819705":1480585069103,"1022438819686":1480585069103,"1021560000705":1509788624397,"1025331491836":1509788625098,"1022438819683":1480585069103,"1021682035083":1478686417121,"1022438819692":1480585069103,"1022438819693":1480585069103,"1022438819695":1480585069103,"1020959980677":1478686417033,"1010295010097":1491634246528,"1024411486947":1509788624195,"1022438819666":1480585069103,"1022438819667":1480585069103,"1001681433":1444487341727,"1022459135502":1478686417217,"1022438819652":1480585069103,"1022438819653":1480585069103,"1022438819654":1480585069103,"1022438819655":1480585069103,"1025237253563":1509788624268,"1022438819648":1480585069103,"1022438819649":1480585069103,"1022438819650":1480585069103,"1022438819651":1480585069103,"1022459135494":1478686417217,"1022438819660":1480585069103,"1022438819661":1480585069103,"1022438819662":1480585069103,"1022438819663":1480585069103,"1022438819656":1480585069103,"1025237253556":1509788624268,"1020640291766":1478686417028,"1022438819657":1480585069103,"1024226898430":1509788625070,"1022438819659":1480585069103,"1021314892337":1465470268207,"1025797562210":1509788625114,"1021314892336":1465470268207,"1025797562211":1509788625123,"1021314892339":1465470268207,"1025237253578":1509788624268,"1021314892338":1465470268207,"1023702339655":1509788624195,"1025797562212":1509788625105,"1022461101639":1478686417217,"1022438819644":1480585069103,"1022438819645":1480585069103,"1025797562219":1509788625086,"1022438819646":1480585069103,"1022438819647":1480585069103,"1024144456417":1509788624276,"1022438819643":1480585069103,"1022435935440":1478686417016,"1022438819621":1480585069103,"1022438819623":1480585069103,"1022093340857":1478686417063,"1022438819618":1480585069103,"1026505066828":1515854751199,"1021314892333":1465470268207,"1022438819624":1480585069103,"1021314892335":1465470268207,"1022438819604":1480585069103,"1025270153171":1509788624855,"286677236":1478686804029,"1022438819606":1480585069103,"1025270153168":1509788624856,"1022438819607":1480585069103,"1025270153169":1509788624856,"1022438819600":1480585069102,"1022438819601":1480585069102,"1022438819603":1480585069103,"1022438819612":1480585069103,"1022438819613":1480585069103,"1022438819614":1480585069103,"1022438819608":1480585069103,"1022438819609":1480585069103,"1022438819610":1480585069103,"1016396442856":1478686804017,"1022438819596":1480585069102,"1022438819597":1480585069102,"1022438819598":1480585069102,"1022438819592":1480585069102,"1025270153166":1509788624855,"1022438819593":1480585069102,"1025270153167":1509788624856,"1022438819595":1480585069102,"1022052842998":1478686804049,"1001681328":1444487341749,"1022382719018":1478686417205,"1018644554009":1478686804022,"1021336520321":1478686417041,"1025289026841":1509788624286,"1021602207454":1478686417008,"1518604427":1491634246518,"1020929965777":1478686417082,"1021757927287":1509788624395,"1021700516054":1509788624177,"1023521064017":1509788624417,"1022146950769":1478686416973,"1022434363144":1478686417212,"1023521064002":1509788624417,"1022434363145":1478686417212,"1021602207459":1478686417008,"1023521064007":1509788624417,"1023521064005":1509788624417,"1023521064010":1509788624417,"1023521064011":1509788624417,"1023521064008":1509788624417,"1023521064009":1509788624417,"1023521064012":1509788624417,"1023521063990":1509788624417,"1025628604048":1509788624428,"1025628604050":1509788624425,"1023521063994":1509788624417,"1023521063995":1509788624417,"1023521063992":1509788624417,"1023521063998":1509788624417,"1021727648022":1478686417051,"1022065687932":1478686417270,"1023521063996":1509788624417,"1021441513494":1478686417044,"1016396443466":1478686804017,"1025331490879":1509788625098,"1019287705854":1509788625080,"1025428851427":1509788625089,"1024586335381":1509788624409,"1023751624405":1509788624926,"1025428851421":1509788625117,"1001681366":1444487341728,"1025428851422":1509788625126,"1025428851423":1509788625109,"1022418503267":1478686417209,"1021742853657":1478686804047,"1022204857004":1480585069085,"1012130049312":1478686416994,"102779990":1491634246515,"1021218689014":1465470268196,"1023521064162":1509788624812,"1023521064166":1509788624812,"1007164339667":1478686804032,"1022239590476":1478686417194,"1018146079817":1478686804026,"1023521064170":1509788624812,"1023521064171":1509788624812,"4994786089":1509788667396,"1021432469587":1478686804028,"1023521064147":1509788624812,"271735440":1478686804050,"1023521064144":1509788624813,"1024462212350":1509788624528,"1023521064151":1509788624812,"1023521064155":1509788624812,"1023521064152":1509788624812,"1019106430267":1478686804065,"1023521064159":1509788624812,"1019227145455":1509788625078,"1007393883935":1478686804030,"1013038880649":1478686804028,"1023521064128":1509788624813,"4994917133":1509788667396,"1010093810709":1491634246528,"1023521064132":1509788624813,"1022111559874":1478686417182,"1023521064137":1509788624813,"1021290644365":1478686417040,"1023521064120":1509788624812,"1023521064127":1509788624813,"1023521064125":1509788624812,"1004848201646":1478686804052,"1009744499524":1491634246512,"1022454940961":1478686417216,"1022244046927":1478686417283,"1019525081698":1509788625078,"1008586628722":1478686804030,"1018513354279":1509788624263,"1012538340856":1478686804049,"1023950594607":1509788667501,"1025783799445":1509788624389,"5001732384":1509788667395,"1022463067237":1509788625065,"1022438819324":1480585069101,"1022438819326":1480585069101,"1022438819327":1480585069101,"1025504350007":1509788624295,"1021432470012":1478686804026,"1022438819323":1480585069101,"1026232335305":1514456869770,"1022019026667":1478686417058,"1022019026669":1478686417058,"1022438819296":1480585069101,"1026232335308":1514456869769,"1022019026668":1478686417058,"1025783799425":1509788624389,"1025783799427":1509788624389,"1026232335301":1514456869770,"1025783799434":1509788624389,"1025344598205":1509788624307,"1026232335303":1514456869770,"1016396312124":1478686804017,"1022438819285":1480585069101,"1024584762829":1509788624960,"1022438819287":1480585069101,"1021289071193":1478686417040,"1022438819293":1480585069101,"1022438819294":1480585069101,"1022438819291":1480585069101,"1022438819271":1480585069101,"1022438819264":1480585069101,"1022438819265":1480585069101,"1022438819267":1480585069101,"1022438819276":1480585069101,"1021651883237":1478686417120,"1022438819279":1480585069101,"1022438819272":1480585069101,"1022438819275":1480585069101,"1022438819252":1480585069101,"1022438819253":1480585069101,"1022438819254":1480585069101,"1021906167295":1478686417139,"1022438819260":1480585069101,"1022438819262":1480585069101,"1022438819256":1480585069101,"1018927806325":1509788624315,"1022438819258":1480585069101,"1022438819259":1480585069101,"1018513354626":1509788624263,"1023960032103":1509788625071,"1022438819236":1480585069101,"1024462212362":1509788624528,"1022047862128":1478686417059,"1024462212363":1509788624529,"1024462212360":1509788624528,"1022438819232":1480585069101,"1024462212366":1509788624529,"1022438819233":1480585069101,"4997145230":1509788667396,"1024462212364":1509788624529,"1024462212365":1509788624529,"1024462212354":1509788624529,"1025300034323":1509788624307,"1024462212352":1509788624529,"1024462212353":1509788624529,"1024462212358":1509788624528,"1025902417727":1509788667460,"1024462212356":1509788624529,"1022438819220":1480585069101,"1022438819221":1480585069101,"1024462212408":1509788624827,"1022438819216":1480585069101,"1022438819218":1480585069101,"1022438819219":1480585069101,"1022438819228":1480585069101,"1022438819230":1480585069101,"1025504350038":1509788624295,"1024496419642":1509788625028,"1022438819231":1480585069101,"1022438819224":1480585069101,"1022438819225":1480585069101,"1024668915845":1509788625025,"1008675099170":1478686804030,"1025504350028":1509788624295,"1022438819205":1480585069100,"1008675099168":1478686804020,"1022438819207":1480585069100,"1024846255621":1509788624949,"1022438819212":1480585069100,"1022438819213":1480585069100,"1021980883289":1478686417151,"1022438819214":1480585069100,"1025504350022":1509788624295,"1022438819215":1480585069101,"1022438819209":1480585069100,"1022438819210":1480585069100,"1022438819211":1480585069100,"1012127165470":1478686417223,"1021989140529":1478686417155,"1022438819172":1480585069100,"1021018829322":1478686417090,"1022438819173":1480585069100,"1022438819174":1480585069100,"1022438819169":1480585069100,"1022438819181":1480585069100,"1024444518097":1509788625030,"1022438819182":1480585069100,"1023927266720":1491634246529,"1022438819178":1480585069100,"1022438819179":1480585069100,"1873683468":1444487341751,"1021639562553":1478686417119,"1022438819159":1480585069100,"1025783799351":1509788624388,"1021639562559":1478686417119,"1022438819152":1480585069100,"1022438819153":1480585069100,"1022438819155":1480585069100,"1025783799356":1509788624388,"1022438819165":1480585069100,"1025783799357":1509788624388,"1022438819166":1480585069100,"1025783799358":1509788624388,"1022438819167":1480585069100,"1025783799359":1509788624388,"1022438819160":1480585069100,"1025783799352":1509788624388,"1022438819161":1480585069100,"1025783799353":1509788624388,"1025783799354":1509788624388,"1022438819163":1480585069100,"1025783799355":1509788624388,"1000144148065":1478686804029,"1000144148067":1478686804029,"1022438819149":1480585069100,"1021976951237":1478686417301,"1022438819150":1480585069100,"1022438819151":1480585069100,"1025180367569":1509788624213,"1022438819147":1480585069100,"1018513354507":1509788624263,"1148981173":1478686804051,"1022238673160":1509788624947,"1025783799360":1509788624388,"4994785888":1509788667396,"1024735239628":1509788667506,"1021639562561":1478686417119,"1021639562565":1478686417119,"1024735239627":1509788667506,"1025783799415":1509788624389,"5001732546":1509788667396,"4985873099":1509788624160,"1021765529331":1478686417300,"1021674171267":1478686804034,"1025783799416":1509788624389,"1025783799417":1509788624389,"1022292807288":1478686417068,"1016936435004":1478686804059,"1016936435002":1478686804059,"1016936435003":1478686804059,"1016936435000":1478686804058,"1016936435001":1478686804059,"1018517679992":1480585069070,"1016936434998":1478686804058,"1016936434999":1478686804058,"1016936434996":1478686804058,"1016936434997":1478686804058,"1016936434994":1478686804058,"1012155606467":1478686416987,"1017318117383":1465470268237,"1021254470502":1478686417004,"1002640260836":1478686804051,"1002640260833":1478686804051,"1002640260832":1478686804051,"1021254339450":1478686417039,"1023791862329":1509788624177,"1002640260813":1478686804051,"1002640260814":1478686804051,"1023354996861":1509788624220,"1024681107208":1509788624435,"1023354996849":1509788624220,"1023354996851":1509788624220,"1023354996852":1509788624220,"1023354996853":1509788624220,"1021892403531":1478686417138,"1001461016444":1478686417022,"1002640260829":1478686804051,"1002640260828":1478686804051,"1002640260825":1478686804051,"1002640260824":1478686804051,"1021616230858":1509788624311,"1002640260826":1478686804051,"1002640260821":1478686804051,"1002640260820":1478686804051,"1002640260823":1478686804051,"1002640260816":1478686804051,"1002640260819":1478686804051,"1025797561058":1509788624827,"1025797561059":1509788624831,"1024462211609":1509788624988,"1024462211614":1509788624988,"1025797561060":1509788624822,"1009957235336":1478686804064,"1025797561061":1509788624616,"1021045569451":1478686417092,"4994786786":1509788667394,"1022208658650":1480585069087,"1022235266378":1478686417193,"1022501477725":1509788624538,"1018146079417":1478686804026,"1021774572039":1509788625010,"1021432471192":1478686804043,"1024462211626":1509788624988,"1024462211630":1509788624988,"1024462211618":1509788624988,"1023987951330":1509788624214,"1024462211622":1509788624988,"1001461016529":1478686417022,"2026779724":1491634246513,"1022023088445":1509788624463,"1021727649746":1478686417051,"1024499958929":1509788624289,"1018513352774":1509788624603,"1021144632469":1478686417037,"4997145923":1509788667396,"1018309663624":1478686804065,"1022758382933":1509788625057,"1025018489772":1509788624601,"1021890437400":1478686417138,"1025219428249":1509788625128,"1025219428250":1509788625128,"1025219428251":1509788625128,"1025219428252":1509788625128,"1022049827489":1478686417172,"1024735238834":1509788667506,"1020847514378":1478686416999,"1025219428245":1509788625128,"1024735238842":1509788667507,"1025219428237":1509788625128,"1025219428238":1509788625104,"1025219428239":1509788625129,"1021729091485":1478686417051,"1025219428230":1509788625245,"1025219428231":1509788625245,"1024735238827":1509788667506,"911899291":1478686417024,"1021700517428":1478686804046,"5001733863":1509788667395,"1022307879534":1478686416981,"1021329965117":1465470268219,"1024735238855":1509788667507,"1025219428320":1509788625136,"1024735238860":1509788667506,"1024202521358":1509788625034,"1024735238859":1509788667506,"1025219428313":1509788625128,"1025219428314":1509788625128,"1016670648901":1478686804018,"1020272099581":1465470268247,"1025219428318":1509788625135,"1025219428319":1509788625136,"1025219428304":1509788625129,"1025219428306":1509788625113,"1025219428307":1509788625128,"1025797560910":1509788624197,"1025219428308":1509788625128,"1025219428309":1509788625128,"1025797560908":1509788624200,"1025219428310":1509788625128,"1025797560909":1509788624203,"1025219428311":1509788625128,"1025797560915":1509788624185,"1022399891412":1478686417207,"1025219428299":1509788625128,"364403021":1478686804029,"1025219428302":1509788625128,"1025219428303":1509788625104,"1022399891422":1478686417207,"1024462211744":1509788624200,"1025219428290":1509788625245,"1025219428293":1509788625245,"1023946402330":1491634246529,"1021141224747":1478686417037,"1023946402332":1491634246529,"1021396288030":1478686417043,"1020902834020":1478686417227,"1024055714707":1509788624328,"1004329147211":1444487341715,"1024956754383":1509788624352,"1020049764936":1465470268308,"1018513484254":1509788625229,"1024055714695":1509788624327,"1024055714688":1509788624327,"1018513484250":1509788625229,"1024055714691":1509788624327,"1021950737655":1478686417261,"1020102889256":1509788624369,"1024055714698":1509788624328,"1021043603256":1478686416991,"1021833947076":1478686417256,"1019384042958":1509788624933,"1018513484266":1509788625229,"1018513484258":1509788625229,"1018513484287":1509788625228,"1024462211944":1509788624188,"1024462211950":1509788624188,"1018513484282":1509788625228,"1024462211938":1509788624188,"1024462211939":1509788624188,"1019384042962":1509788624933,"1024462211936":1509788624188,"1018513484277":1509788625228,"1024462211937":1509788624188,"1024462211942":1509788624188,"1018513484272":1509788625229,"1023354997018":1509788624856,"1022090458364":1478686417180,"1020886055976":1478686416986,"1023354997010":1509788624856,"1019600841044":1509788624971,"1023354997012":1509788624856,"1023354997013":1509788624856,"1021881655623":1509788624423,"1020886055985":1478686416986,"1023354997007":1509788624856,"1025593477013":1509788624915,"4961233619":1509788624160,"1021225240664":1509788624170,"1021978787637":1478686417151,"1025282603522":1509788624423,"1011947458897":1478686804030,"1021978787644":1478686417151,"1021435223845":1478686417106,"1020295562046":1509788625076,"1025675788910":1509788624381,"1025675788911":1509788624381,"253641362":1478950494908,"1023830142058":1509788624393,"1019944645648":1465470268276,"1025675788912":1509788624381,"1024837996628":1509788624948,"1022458610181":1478686417072,"1020314305086":1478686804031,"1023435080766":1509788625082,"1020314305083":1478686804031,"1021954145388":1478686416986,"1023958066673":1509788667535,"1000527804747":1444487341715,"1017800078539":1478686804016,"1021975641939":1478686417263,"1023354997148":1509788624445,"1023354997149":1509788624445,"1024163985861":1509788667462,"1023354997150":1509788624445,"1003645624529":1478950494936,"1024462211986":1509788624188,"1017276700494":1509788624369,"1025372254677":1509788624305,"1024462211985":1509788624188,"1022483127709":1478943089488,"1024462211988":1509788624188,"1023354997143":1509788624445,"1024462211982":1509788624188,"1024462211983":1509788624188,"1018513352977":1509788624603,"1021893189776":1509788625104,"1020995499282":1478686417034,"1025797561170":1509788624431,"1021593556644":1478686417048,"1025797561171":1509788624425,"1021978394551":1478686417010,"1025797561169":1509788624428,"1022385866730":1478686417205,"1025797561172":1509788624406,"1020995499270":1478686417034,"324951717":1491634246534,"1023354997156":1509788624445,"1025524009744":1509788624916,"1025524009745":1509788624916,"4994787253":1509788667395,"1001461015888":1478686417022,"1025524009747":1509788624835,"1025524009748":1509788624835,"1025524009749":1509788624826,"1025524009753":1509788624848,"1024955968220":1509788624920,"1012155606997":1478686416987,"1024955968222":1509788624272,"1024955968223":1509788624616,"1020358876377":1465470268324,"1025675788784":1509788624381,"1020358876376":1465470268324,"1025675788785":1509788624381,"1024136199614":1509788625085,"1020358876378":1465470268324,"1025148772697":1509788667843,"1021138996823":1478686416988,"1024136199605":1509788625086,"1025524009777":1509788624835,"1001461015920":1478686417022,"1020212201388":1478686804053,"1025524009781":1509788624843,"1025524009782":1509788624867,"1020102888475":1509788624369,"1021048714746":1478686417093,"1024955968224":1509788625248,"1020212201407":1478686804053,"1020212201405":1478686804053,"1020212201403":1478686804053,"1020212201402":1478686804053,"1020212201401":1478686804053,"1025524009766":1509788624835,"1020212201400":1478686804053,"1020212201399":1478686804053,"1020212201398":1478686804053,"1011618465786":1478686804061,"1020212201397":1478686804053,"1020212201396":1478686804053,"1020212201395":1478686804053,"1011618465791":1478686804061,"1020212201394":1478686804053,"1011618465790":1478686804061,"1020212201393":1478686804053,"1011618465789":1478686804061,"1020212201392":1478686804053,"1011618465788":1478686804061,"1002640260265":1478686804051,"1025530431690":1509788624800,"1025524009813":1509788624510,"1002640260267":1478686804051,"1025530431688":1509788624833,"1025530431689":1509788624823,"1002640260261":1478686804051,"1007840455002":1509788624390,"1025524009816":1509788624510,"1000151225096":1509788625082,"1022204857999":1480585069085,"1025530431687":1509788624829,"1002640260263":1478686804051,"1002640260262":1478686804051,"1025524009819":1509788624433,"1025524009820":1509788624433,"1002640260259":1478686804051,"1025524009822":1509788624427,"1002640260258":1478686804051,"1001461015816":1478686417022,"1024136199625":1509788625085,"4985874253":1509788624159,"1021733415558":1509788624395,"1025524009847":1509788624433,"1021437713643":1478686417044,"1011825433597":1509788624377,"1024136199617":1509788625085,"1021248440736":1478686417004,"1024136199623":1509788625085,"1025675788701":1509788624381,"1025675788702":1509788624381,"1025675788703":1509788624381,"1025524009835":1509788624433,"1025524009839":1509788624433,"1022051531113":1478686417172,"1019956966465":1509788625079,"1019956966466":1509788624366,"1019838872902":1478686804046,"1021987175753":1478686417154,"1023867497760":1509788624355,"1025524009856":1509788624436,"1025524009860":1509788624454,"1023730914660":1509788624960,"1021225634738":1478686417039,"1025524009861":1509788624437,"1025524009862":1509788624455,"1024663542989":1509788625026,"1024462211322":1509788624413,"1023867497741":1509788624356,"1024462211323":1509788624413,"1025524009905":1509788624543,"1021776537839":1478686417254,"1023867497742":1509788624356,"1024462211320":1509788624413,"1021776537838":1478686417254,"1023867497743":1509788624356,"1024462211326":1509788624413,"1001461016054":1478686417022,"1024462211327":1509788624413,"1025524009909":1509788624543,"1024462211325":1509788624413,"1025524009911":1509788624543,"1024462211314":1509788624413,"1012155606894":1478686416987,"1024462211315":1509788624413,"1024462211312":1509788624413,"1023867497756":1509788624356,"1023867497757":1509788624356,"1023867497758":1509788624355,"1023867497759":1509788624355,"1023867497752":1509788624355,"1023867497753":1509788624355,"1023867497754":1509788624355,"1023867497755":1509788624356,"1023867497748":1509788624356,"1006681992383":1478686804032,"1023867497749":1509788624356,"1025524009897":1509788624552,"1025530431543":1509788625088,"1023867497750":1509788624356,"1025530431540":1509788625125,"1023867497751":1509788624356,"1025530431541":1509788625108,"1023867497744":1509788624356,"1012129655286":1478686417025,"1023867497745":1509788624356,"1025530431539":1509788625116,"1023867497746":1509788624356,"1023867497747":1509788624356,"1018513484303":1509788625228,"1021774571694":1509788625010,"1024501925694":1509788625029,"1013122772221":1478686804051,"1013122772220":1478686804051,"1018513484298":1509788625228,"1018513484297":1509788625228,"1023129713007":1509788624939,"1025385886694":1509788624506,"1018513484293":1509788625228,"5001733357":1509788667396,"5001733356":1509788667396,"1021906296959":1509788624466,"1022153110320":1478686416973,"1021323806105":1465470268211,"1018513484317":1509788625228,"1022953677552":1509788624291,"1021323806108":1465470268211,"1010093809782":1491634246528,"1021323806111":1465470268211,"1018513484311":1509788625228,"1024206321987":1509788625034,"1018513484310":1509788625228,"1018513484328":1509788625228,"1021323806113":1465470268211,"1021323806114":1465470268211,"1001461015997":1478686417022,"1021264823842":1478686417004,"1022253878549":1478686417284,"1022456643901":1478686417072,"1020634131808":1478686804066,"1024136199329":1509788625086,"1024136199333":1509788625086,"1025675788528":1509788624381,"1025675788529":1509788624381,"1025675788530":1509788624381,"1021888078525":1509788624465,"1021941825419":1509788624464,"1021700517332":1478686804046,"1020634131805":1478686804066,"1020634131807":1478686804066,"1020634131806":1478686804066,"1025331492182":1509788625098,"1023867497708":1509788624356,"1023867497709":1509788624356,"1025331492139":1509788625098,"1023867497710":1509788624356,"1023867497704":1509788624356,"1023867497705":1509788624356,"1023867497706":1509788624356,"1023867497707":1509788624356,"1023867497700":1509788624356,"1023867497701":1509788624356,"1023867497702":1509788624356,"1023867497703":1509788624356,"1023867497696":1509788624357,"1023867497697":1509788624357,"1023867497698":1509788624356,"649488889":1491634246511,"1023867497699":1509788624356,"1024607961306":1509788667589,"4994787042":1509788667394,"1024462211330":1509788624413,"1024462211331":1509788624413,"1024462211329":1509788624413,"1011593693223":1478686417220,"1012155606692":1478686416987,"1021896991303":1478686417258,"1025331492110":1509788625098,"1020765070814":1478686417028,"1020493223336":1509788625078,"1020966402516":1478686417001,"1025537640784":1509788624306,"1023867497692":1509788624356,"1023867497693":1509788624356,"1023867497694":1509788624356,"1023867497695":1509788624357,"1025797560791":1509788624540,"1023867497691":1509788624357,"1018559752560":1478686804015,"1025797560795":1509788624523,"1025797560792":1509788624542,"1025797560793":1509788624536,"1025007610019":1509788624977,"1022080759727":1478686417178,"1021585036378":1478686417114,"1019838872651":1478686804046,"1025524009624":1509788625128,"1025524009626":1509788625128,"1025524009627":1509788625128,"1004360210414":1478686804039,"1025524009631":1509788625167,"1019244970179":1509788624316,"1022309320985":1478686417199,"1025772002237":1509788624866,"1025524009605":1509788625245,"1025524009606":1509788625244,"1025524009607":1509788625128,"1007198850761":1478686804032,"1025524009609":1509788625112,"1021774572018":1509788625010,"1025590724263":1509788624342,"1025524009634":1509788625135,"1025524009637":1509788625169,"1021246212191":1478686417039,"1016979294182":1478686804015,"1021915996579":1478686417141,"1025524009682":1509788624214,"1022213508997":1478686417281,"1021489224358":1478686417243,"1022138954523":1478686417277,"1025524009693":1509788624205,"1025524009669":1509788624270,"1025524009673":1509788624270,"1022075123546":1478686804039,"1025331492273":1509788625098,"1021988879429":1478686417264,"1025412886608":1509788624537,"1022249684445":1478686417196,"1025412886616":1509788624524,"1025524009724":1509788625005,"1024462211498":1509788624988,"1024462211499":1509788624988,"1025524009698":1509788624205,"1025524009703":1509788624205,"1024462211501":1509788624988,"1024462211494":1509788624988,"1024574669435":1509788624925,"1025412886606":1509788624541,"1025412886607":1509788624543,"1024462211493":1509788624988,"1021485942176":1509788624398,"1004571637197":1478950494938,"1015594231491":1478686804065,"1021700518637":1478686804047,"1025523750158":1509788625171,"1022447476331":1478686804050,"4952323854":1509788624162,"1021655289765":1478686417008,"4994791815":1509788667396,"1021935788239":1509788625165,"1019608315334":1509788625077,"1012733352743":1478686804030,"1021612166248":1478686417247,"1023730912161":1509788624960,"1024343027489":1509788625031,"1021606268108":1478686417116,"1021612166246":1478686417247,"1021994115865":1478686417011,"1022488494480":1478943089254,"1020612899293":1478686417027,"1024115876490":1509788667888,"1021989790668":1478686417155,"1013517560522":1444487341759,"1021900143976":1478686417139,"1025505137813":1509788624340,"1025505137814":1509788624338,"1025505137815":1509788624341,"1025505137816":1509788624342,"1018513355877":1509788625227,"1020444460910":1478686804033,"1017435173872":1478686804032,"1021894114703":1509788624466,"1010013600175":1491634246526,"1010013600174":1491634246526,"1010013600173":1491634246521,"1022492164449":1478943089490,"1024771017016":1509788667537,"1019900864234":1509788624959,"1024154543203":1509788667409,"1010013600178":1491634246526,"1019066455319":1509788625019,"1019066455324":1509788624282,"1024374657404":1509788625086,"1024374657405":1509788625086,"1021948633338":1509788624389,"1021737612707":1478686417124,"1013517560754":1444487341759,"1011900925977":1478686804024,"1025609734904":1509788625138,"1024120464311":1509788667495,"1024774031540":1509788624420,"1021018171536":1478686417090,"1022236316658":1478686417014,"1024120464301":1509788667495,"1016444156208":1478686804016,"1327111680":1444487341747,"1021983367939":1478686416992,"1025609734888":1509788625138,"1020314312372":1478686804027,"1024120464281":1509788667495,"1025609734871":1509788625138,"1024120464284":1509788667495,"4976834956":1509788624161,"1024120464275":1509788667459,"1021663022621":1509788624324,"1023148845486":1509788625078,"243818428":1444487341725,"1019847385725":1509788625080,"1021375586156":1478686417105,"1021375586153":1478686417105,"1024771016884":1509788667537,"1022471324067":1478686417219,"1019599402358":1480585069068,"1016400115585":1480585069069,"1024952431178":1509788624193,"1025100414234":1509788624273,"1021492495379":1478686417243,"1022518641534":1509788624855,"1021782832800":1509788624395,"1022518641535":1509788624855,"1021492495371":1478686417243,"1024331231056":1509788624419,"1025585747999":1509788624351,"1016936437678":1478686804059,"1016936437679":1478686804059,"1016936437677":1478686804059,"1010025397180":1491634246527,"1020802694419":1478686417077,"1010025397173":1491634246527,"1010025397169":1491634246522,"1010025397166":1491634246527,"1016936437684":1478686804059,"1016936437685":1478686804059,"1016936437682":1478686804059,"1016936437683":1478686804059,"1021001787872":1478686417089,"1016936437681":1478686804059,"1024120464327":1509788667495,"4976834849":1509788624160,"1016620442155":1478686804049,"1025713668145":1509788624305,"1014359031285":1465470268240,"1008046630152":1478686804030,"1025373301839":1509788624383,"1024952431268":1509788624419,"1025100414459":1509788624181,"1022518641536":1509788624855,"1022518641537":1509788624855,"1025373301848":1509788624383,"4994791427":1509788667396,"1021909974988":1478686417140,"1025373301849":1509788624383,"1019599402375":1480585069061,"1024273033784":1509788624353,"1025373301847":1509788624383,"1025373301840":1509788624383,"1019599402382":1480585069065,"1025100414354":1509788624173,"1018513356040":1509788625228,"1021618457619":1509788624397,"1022269347133":1478686417197,"1025373301816":1509788624383,"1021841292100":1478686417135,"1025373301817":1509788624383,"1021326039793":1478686417238,"1025373301814":1509788624383,"1025373301815":1509788624383,"1024774031438":1509788624818,"1021288028291":1465470268201,"1026507690431":1515854751198,"1021375586213":1478686417105,"1026507690429":1515854751199,"1021547678181":1478686417113,"1014359031191":1465470268240,"1021375586221":1478686417105,"1021928193349":1478686417144,"1021928193348":1478686417144,"1019759574144":1509788624281,"1024773639085":1509788625021,"1020915802546":1478686417032,"1020612899762":1478686417027,"1022533714231":1480585069076,"1024779799405":1509788624434,"1019872552945":1478686804032,"1020932974327":1478686417083,"1013013057252":1444487341758,"1023472179462":1509788624195,"1013013057219":1444487341758,"1020606083667":1478686417018,"1024017448635":1509788624268,"1024687392423":1509788624999,"1021549906819":1478686417047,"1021596698996":1509788624405,"1024055983329":1509788624928,"1021646507134":1478686417049,"4976835281":1509788624161,"1022079576615":1478686417272,"1025888913709":1509788667405,"1022208528911":1478686804039,"1016937616478":1478686804019,"1025907920519":1509788667460,"4997151568":1509788667396,"1013013057071":1444487341758,"1001093613489":1478686417022,"1019724578353":1509788625079,"1024526178555":1509788625028,"1025531089948":1509788624335,"1024055983113":1509788624928,"1020917768455":1478686417081,"1024952431010":1509788625100,"1020612899598":1478686417027,"1019088081983":1509788624313,"1021406642890":1509788624829,"1021406642893":1509788624616,"1021694620655":1478686417121,"4976835097":1509788624161,"1023268253094":1509788624839,"1021832510428":1478686417256,"1021971308569":1478686417149,"1024952431051":1509788624533,"1008738537382":1444487341761,"1022447475874":1478686804050,"1013013057136":1444487341758,"1014527321269":1465470268319,"4976835184":1509788624161,"1021475325596":1478686417109,"1019872552726":1478686804032,"1021608758957":1478686417049,"1021475325602":1478686417109,"1025114701714":1509788667497,"1024055983207":1509788624928,"1024952431099":1509788624815,"1025310649175":1509788624298,"1022464646209":1509788624318,"1023086978909":1509788624987,"1023457499433":1509788624311,"1024154544044":1509788667410,"1024017448956":1509788624912,"1456735730":1444487341753,"1020635967840":1478686417027,"1010013600321":1491634246526,"1010013600320":1491634246521,"1456735736":1444487341754,"1013013057421":1444487341758,"1022904531459":1509788624250,"1023472179306":1509788625102,"1022501470722":1509788624538,"1012252867886":1478686417223,"1021414638300":1478686417106,"1020616438485":1478686417075,"1013517560306":1444487341759,"1022131873888":1478686417184,"1022501470843":1509788624538,"1161827847":1509788624366,"1013013057526":1444487341758,"1021906042338":1478686417139,"1023472179205":1509788624534,"1022245490983":1478686417284,"1022204859302":1480585069085,"1016937616826":1478686804034,"1022245490973":1478686417284,"1021254603777":1478686416987,"1022168051315":1478686417186,"1012400972878":1478686416994,"1012812776410":1478686804049,"1013013057481":1444487341758,"4994792152":1509788667397,"1980638590":1478950494928,"297812661":1444487341743,"1980638587":1478950494928,"1021591848975":1478686417048,"1980638606":1478950494928,"1024886230164":1509788624880,"1980638602":1478950494928,"1024886230160":1509788624880,"1024886230162":1509788624880,"1024385536330":1509788625097,"1024886230172":1509788624880,"1980638594":1478950494928,"1024886230168":1509788624880,"1023472179410":1509788624818,"1024886230170":1509788624880,"1025453757108":1509788624302,"1980638616":1478950494929,"1023242562939":1509788624462,"1980638614":1478950494929,"1024886230157":1509788624880,"1980638612":1478950494929,"1024886230158":1509788624880,"1980638613":1478950494929,"1980638610":1478950494928,"1980638611":1478950494929,"1010402464737":1478686804064,"1022004995956":1478686417158,"1022190201868":1478686417188,"662991925":1491634246507,"1017318117309":1465470268237,"1010387414164":1509788624277,"1021798167743":1509788624507,"1020015292146":1478686804040,"1013013057310":1444487341758,"1016075829639":1509788624944,"1025637916646":1509788624359,"1016396314335":1478686804017,"1020773595638":1509788624934,"1026232328987":1514456869770,"1021798167747":1509788624507,"1021798167746":1509788624507,"1026232328989":1514456869769,"1021798167745":1509788624507,"1026232328990":1514456869769,"1021798167744":1509788624507,"1026232328991":1514456869768,"1025637916648":1509788624359,"1021901585705":1509788624981,"1021901585704":1509788624981,"1013013057397":1444487341758,"1024212346088":1509788624238,"1024385536283":1509788625097,"1021901585697":1509788624981,"1021901585696":1509788624981,"1024212346084":1509788624238,"1021901585699":1509788624981,"1024212346085":1509788624238,"1021901585698":1509788624982,"1024212346082":1509788624238,"1021901585701":1509788624981,"1024212346083":1509788624238,"1024212346081":1509788624238,"1019815535283":1509788624354,"1019815535282":1509788624354,"1024385536301":1509788625097,"1024212346076":1509788624238,"1019815535281":1509788624354,"1021901585691":1509788624981,"1021901585690":1509788624981,"1021901585693":1509788624979,"1024385536296":1509788625096,"1021901585692":1509788624982,"1024385536293":1509788625096,"1024385536294":1509788625096,"662991989":1491634246507,"1024385536318":1509788625096,"1022034748689":1478686417058,"1024385536309":1509788625097,"1020940445660":1478686417084,"1019815535279":1509788624353,"1021941556378":1509788624609,"1002035747090":1478686417024,"1020612900270":1478686417075,"1022485349385":1478943089489,"1024501931509":1509788624507,"4994792893":1509788667393,"1024477025143":1509788625021,"1019166072823":1478686804020,"1021704844961":1478686417122,"1409548307":1509788625020,"1010011635094":1491634246525,"1021767496412":1509788624194,"1022005518464":1478686417057,"1022675142886":1480585069063,"1022204859646":1480585069085,"1021025250574":1478686417091,"281691275":1444487341736,"1021486727670":1478686417046,"1291065522":1478686417024,"1022241298173":1478686417014,"1025620746110":1509788624970,"1024781372673":1509788624472,"1021197848721":1509788624170,"1025412885440":1509788625118,"1025412885441":1509788625126,"1013517561539":1444487341759,"1025412885442":1509788625109,"1025412885444":1509788624829,"1025609736065":1509788624550,"1025412885445":1509788624834,"1025412885446":1509788624824,"1025608032153":1509788624523,"1025608032148":1509788624537,"1025608032146":1509788624542,"1025609736073":1509788624550,"1022451931762":1478686417296,"1025412885454":1509788625089,"1025608032145":1509788624540,"1025412885455":1509788624800,"1001380934303":1478686804059,"1001380934297":1478686804059,"1010025397849":1491634246527,"1018513354827":1509788625204,"1022976621132":1509788625073,"1025609736063":1509788624550,"1025609736056":1509788624550,"1025609736059":1509788624550,"1007592459593":1478686804023,"1022518642343":1509788624446,"1018805510641":1509788624929,"1022518642341":1509788624446,"1022518642344":1509788624446,"1022518642345":1509788624446,"1022451014294":1478686417215,"1022425717009":1478686417016,"1020133691636":1509788625081,"1020744629597":1509788624321,"1010025397862":1491634246527,"1010025397860":1491634246522,"1010025397858":1491634246522,"1022208660531":1480585069087,"1019258471587":1478686804018,"4563813587":1465469681387,"4961235816":1509788624160,"4997152051":1509788667397,"1013517561413":1444487341759,"1024214574058":1509788625071,"1024411489856":1509788624859,"1024411489857":1509788624859,"1022008009091":1478686417158,"1024411489858":1509788624859,"1024211296810":1509788624490,"1022631234677":1509788624441,"764704901":1478686417018,"1021486465189":1478686417243,"1020926682676":1478686417082,"1021700650966":1478686804046,"1016937616382":1478686804031,"1016620443271":1478686804049,"1025593614306":1509788625022,"1021349894382":1478686417104,"1025412885124":1509788624201,"1025412885125":1509788624198,"1025412885126":1509788624205,"1021767496653":1509788624817,"1025412885128":1509788624186,"1016277551885":1509788624367,"1016277551886":1509788624367,"1016277551887":1509788624367,"1009965232959":1491634246523,"5001740139":1509788667393,"1021543222558":1478686417113,"1022451669883":1478686417215,"1018229442196":1480585069071,"1024154542564":1509788667659,"1021385939682":1478686417105,"1024154542568":1509788667658,"1021385939695":1478686417105,"1021385939689":1478686417105,"1024154542572":1509788667659,"1024411489823":1509788624222,"1024411489825":1509788624222,"1024411489826":1509788624223,"1024411489827":1509788624222,"1024411489828":1509788624222,"1024154542548":1509788667659,"1024886229618":1509788624240,"1024886229626":1509788624240,"1020994183778":1478686417034,"1024886229605":1509788624240,"1024886229615":1509788624240,"1018513355190":1509788625226,"1024886229608":1509788624240,"1023786355710":1509788624300,"764180720":1509788625016,"1024411489853":1509788624859,"1024886229610":1509788624240,"1024411489854":1509788624859,"1024886229611":1509788624240,"1010093816611":1491634246528,"1024167780422":1509788624449,"1024781372628":1509788624473,"1024888075640":1509788625023,"1010093816610":1491634246522,"1024167780423":1509788624449,"1024167780420":1509788624448,"1024781372630":1509788624473,"1024167780421":1509788624449,"1024781372626":1509788624472,"1023038743732":1509788667833,"1024781372627":1509788624473,"1024781372637":1509788624472,"1024781372638":1509788624472,"1022143015193":1478686417277,"1024167780426":1509788624448,"1024781372632":1509788624473,"1024781372633":1509788624473,"4994792505":1509788667397,"1024781372635":1509788624473,"1016396443790":1478686804018,"1024886229632":1509788624240,"1021333772617":1478686417103,"1021962134727":1478686417148,"1022442756901":1478686417071,"1024781372661":1509788624473,"1024781372662":1509788624473,"1024781372663":1509788624473,"1024781372657":1509788624472,"1024781372659":1509788624472,"1024781372670":1509788624472,"1024781372671":1509788624472,"1024195175304":1509788625071,"1024781372640":1509788624472,"1022208660793":1480585069087,"1024781372642":1509788624472,"1020945293377":1478686417229,"1024781372652":1509788624472,"1022081543577":1478686417061,"1024781372654":1509788624472,"1024055982890":1509788624928,"1023836828735":1509788624970,"1021394328309":1478686417105,"1022405662982":1478686417207,"1024411489931":1509788624449,"1022356511760":1478686417069,"1024411489932":1509788624449,"1024411489933":1509788624449,"1024411489934":1509788624449,"1023123809230":1509788667538,"948464967":1444487341736,"1024411489936":1509788624449,"1023085011366":1509788624435,"1023927792620":1509788667538,"1020850141791":1478686417226,"1022048904170":1478686417301,"1020850141787":1478686417226,"1017800076462":1478686804016,"1021121325728":1478686417095,"1021945095585":1478686417144,"1025412885072":1509788624426,"1025412885077":1509788624407,"1021719787061":1478686417251,"1023123809256":1509788667538,"1022356511798":1478686417069,"1023123809269":1509788667538,"1023123809270":1509788667538,"1021719787051":1478686417251,"1011274359219":1478686804034,"1025412885070":1509788624429,"1025412885071":1509788624431,"1021245558802":1478686417236,"1022092291993":1509788625020,"1021473882748":1478686417109,"1019833361451":1478686804069,"1019833361450":1478686804069,"1016075830321":1509788624944,"1025289285346":1509788625019,"1024987165469":1509788667581,"1025289285344":1509788625019,"1022518641696":1509788624558,"1025416816998":1509788624933,"1016075830304":1509788624944,"1022208661143":1480585069087,"1024803786213":1509788624548,"1022050344963":1478686417172,"1021788860844":1478686804039,"1004101738455":1478686804029,"1025513395088":1509788624344,"1020102890517":1509788624369,"1021954140156":1478686417146,"1019073532750":1509788624324,"1025416816989":1509788624933,"1022246540384":1478686417195,"1022518641694":1509788624558,"1022518641695":1509788624558,"1022518641693":1509788624558,"1022233564937":1478686417193,"1021465232066":1478686417300,"1007394151305":1478686804015,"1024781373204":1509788624576,"1025712490388":1509788625008,"1024781373206":1509788624576,"1024781373200":1509788624575,"1022688512599":1509788624394,"1024781373202":1509788624576,"1024781373212":1509788624575,"1024781373213":1509788624576,"1021789385152":1509788624993,"1024781373215":1509788624575,"1020983566845":1478686417230,"1022455470522":1478686417297,"1024781373208":1509788624576,"1024781373209":1509788624576,"1024781373210":1509788624576,"1077941775":1491634246513,"1024781373189":1509788624576,"1021767364779":1478686417052,"1021767364780":1478686417052,"4961235439":1509788624161,"1022096092955":1478686417012,"1024781373198":1509788624575,"1024781373199":1509788624575,"1020294256887":1465470268299,"1024781373192":1509788624576,"1016620443133":1478686804049,"1013517561042":1444487341759,"1021870389938":1478686417136,"1016075830354":1509788624944,"1021955450828":1509788624256,"1024781373217":1509788624575,"1021908531218":1509788624452,"662991104":1444487341721,"1018513355332":1509788625226,"1022244574436":1478686417283,"1008739322858":1478686804030,"1021101533190":1478686417232,"1024133703005":1509788624416,"1024133703002":1509788624416,"1024133703003":1509788624416,"1024212345256":1509788625185,"1024133702998":1509788624416,"1020796664392":1478686417225,"1024133702995":1509788624416,"1024133702993":1509788624416,"1021981271193":1478686417151,"1024411489760":1509788624562,"1024411489762":1509788624562,"1024411489763":1509788624562,"1024411489764":1509788624562,"1024411489765":1509788624562,"1016075830429":1509788624944,"1021793841645":1509788624403,"1016075830417":1509788624944,"1021028265029":1478686417091,"178150447":1444487341738,"1024412538342":1509788625136,"1016075830413":1509788624944,"1016075830400":1509788624944,"1022074859067":1509788624416,"1024870107435":1509788624342,"1018626735308":1478686804016,"1023268252065":1509788624865,"1011339636392":1478686804054,"1018362481947":1509788625076,"1022204859923":1480585069085,"1021407954590":1478686416988,"1021929634294":1478686417144,"1024411489706":1509788625159,"1024411489707":1509788625159,"1024411489708":1509788625160,"1024411489709":1509788625159,"1024411489711":1509788625159,"1016837084715":1478686804019,"1013517560901":1444487341759,"1209933546":1444487341755,"1018725164760":1509788624373,"1024154542667":1509788667409,"1025007612122":1509788624977,"1024154543034":1509788667409,"1021139392326":1478686417096,"1022132530232":1478686417276,"1618884462":1444487341718,"1021980222777":1478686417263,"1022436465163":1478686417295,"1020946866902":1478686417085,"1021767496172":1509788624533,"1022436465159":1478686417295,"1022082068253":1478686417062,"1013517561238":1444487341759,"4973166405":1509788624158,"1022630317658":1509788625061,"1021801709556":1478686804065,"1010093816295":1491634246522,"1021995557892":1509788624466,"1020744629946":1509788624321,"1024132523178":1509788624325,"1019865867011":1509788624959,"1023962136408":1509788625005,"1023962136409":1509788625005,"1023962136412":1509788625005,"1017229901849":1509788624941,"1020735061817":1509788624959,"1021789384913":1509788624993,"1023962136405":1509788625005,"1022317187414":1478686417200,"1006994334213":1509788624374,"1021508223268":1478686417047,"1023821494022":1491634246536,"1022317187417":1478686417200,"1025608424601":1509788624845,"1025608424604":1509788624845,"1020016863780":1509788624389,"1025608424607":1509788624845,"1024005258478":1491634246533,"1015520699986":1478686804031,"1025608424599":1509788624846,"1024781373138":1509788625090,"1022518642082":1509788624219,"1022518642083":1509788625154,"1022836765358":1509788625018,"1021489742582":1478686417046,"1022518642081":1509788624219,"1022518642087":1509788624219,"1022518642084":1509788625154,"1022518642085":1509788625154,"1021897259685":1478686416973,"1022518642088":1509788625154,"1022465038553":1478686416989,"1022455076961":1478686417297,"1024781373172":1509788624576,"1024781373175":1509788624576,"1024781373169":1509788624576,"1024781373171":1509788624576,"1025018491034":1509788624904,"1021027479230":1478686417091,"1024781373182":1509788624576,"1024781373183":1509788624576,"1022518642079":1509788624219,"1024781373178":1509788624576,"1021149746714":1478686417234,"1012992347219":1478686804015,"1018513486710":1509788624825,"1404175368":1478686804051,"1024781373166":1509788624575,"1017354160223":1478686804049,"1025712883216":1509788624307,"1024017447779":1509788625237,"4994793079":1509788667393,"1022198851812":1478686417280,"4563814337":1465469681389,"178150741":1444487341737,"1009744367188":1491634246512,"1022251521490":1478686417066,"1021802233636":1478686417052,"1022112607655":1509788624949,"1010025397543":1491634246527,"1010025397539":1491634246522,"1022511303302":1480585069128,"1022511303303":1480585069128,"1022511303301":1480585069128,"1485176974":1491634246533,"1022456649678":1478686417298,"1022511303305":1480585069128,"1022511303311":1480585069128,"1022456649684":1478686417298,"1022511303315":1480585069128,"1022511303319":1480585069128,"1021937494211":1478686417143,"1022511303317":1480585069128,"1022021512655":1478686417162,"1022511303322":1480585069128,"1020462678180":1465470268259,"1022511303326":1480585069128,"1022511303324":1480585069128,"1022511303330":1480585069128,"1022511303328":1480585069128,"1022511303334":1480585069128,"1024244588919":1509788624948,"1022511303332":1480585069128,"1022511303338":1480585069129,"1022405661927":1478686417207,"1021937756413":1478686417010,"1021715987397":1509788624194,"4972900423":1509788624161,"1022511303341":1480585069129,"1022511303346":1480585069129,"1024952433458":1509788624443,"1022511303347":1480585069129,"1024952433459":1509788624443,"1022511303344":1480585069129,"1022511303350":1480585069129,"1024952433463":1509788624443,"1024952433460":1509788624443,"1022511303349":1480585069129,"1024952433461":1509788624443,"1020444463086":1478686804033,"734426108":1444487341744,"1022628610489":1509788624205,"1022628610490":1509788624201,"1022628610491":1509788624197,"1022201079617":1478686417064,"1022628610496":1509788624186,"1021715987373":1509788624533,"1023937101774":1509788667538,"1019596520471":1509788624946,"1022511303374":1480585069129,"1022511303375":1480585069129,"1019852237644":1478686804021,"1009173311440":1509788624389,"1022511303376":1480585069129,"1023937101781":1509788667539,"1022567140731":1509788624849,"1022511303380":1480585069129,"1022511303386":1480585069129,"1023937101790":1509788667539,"1022511303387":1480585069129,"1023937101791":1509788667539,"1022511303384":1480585069129,"1022511303385":1480585069129,"1023937101789":1509788667538,"1023937101786":1509788667538,"1023937101784":1509788667538,"1022511303389":1480585069129,"1016863693120":1478686804031,"1022511303394":1480585069129,"4976832709":1509788624161,"1022511303392":1480585069129,"1022511303393":1480585069129,"1022511303398":1480585069129,"1020766515943":1478686417225,"1022511303396":1480585069129,"1021248446380":1478686417100,"1022511303397":1480585069129,"1021782441584":1509788624395,"1023937101793":1509788667538,"1022511303402":1480585069129,"1022511303403":1480585069129,"1021261815669":1478686804066,"1022238808746":1509788624947,"1022511303401":1480585069129,"1022238808747":1509788624930,"1022511303406":1480585069129,"1022511303407":1480585069129,"1023937101803":1509788667538,"1022511303404":1480585069129,"1022511303405":1480585069129,"1019596520494":1509788624946,"1022734911322":1509788624461,"1023937101808":1509788667538,"1022511303422":1480585069129,"1022511303421":1480585069129,"1022511303171":1480585069128,"1831613869":1491634246515,"1022511303169":1480585069128,"1022511303175":1480585069128,"1022511303173":1480585069128,"1022646698521":1480585069078,"1022511303179":1480585069128,"1007053840759":1478686804015,"1022511303182":1480585069128,"1022511303180":1480585069128,"1022511303186":1480585069128,"1022511303190":1480585069128,"1022511303191":1480585069128,"1022511303188":1480585069128,"4997149005":1509788667397,"1022511303189":1480585069128,"1022511303194":1480585069128,"1022511303195":1480585069128,"1021790437120":1509788624561,"1022511303192":1480585069128,"1022511303193":1480585069128,"1022584835772":1480585069132,"1022511303199":1480585069128,"1022511303196":1480585069128,"1021319877413":1478686416982,"1022646698545":1480585069145,"1022646698547":1480585069078,"1019448525719":1478686804021,"1022646698550":1480585069078,"1023596432220":1509788624519,"1022646698555":1480585069078,"1022646698557":1480585069078,"1025732020775":1509788624294,"1021482405197":1478686417110,"1022646698538":1480585069078,"1022646698540":1480585069078,"1022511303228":1480585069128,"1022646698543":1480585069078,"1022511303229":1480585069128,"1021413853520":1509788624816,"1022511303232":1480585069128,"1022511303238":1480585069128,"1021327872967":1465470268218,"1021327872965":1465470268218,"1022511303247":1480585069128,"1025103557838":1509788625022,"1024154545278":1509788667409,"1022511303245":1480585069128,"1022646698560":1480585069078,"1021021184422":1478686417090,"1021301920360":1478686417238,"1022511303249":1480585069128,"1022511303254":1480585069128,"1022511303255":1480585069128,"1022511303253":1480585069128,"1022511303256":1480585069128,"1022511303263":1480585069128,"1022511303261":1480585069128,"1022511303266":1480585069128,"1012365061537":1478686417026,"1022511303264":1480585069128,"1022511303265":1480585069128,"1022511303270":1480585069128,"1020826809870":1478686417031,"1022511303274":1480585069128,"1022511303275":1480585069128,"1016230495240":1478686804040,"1021067322460":1478686417093,"1022511303273":1480585069128,"1022511303276":1480585069128,"1022264630183":1478686417285,"1022511303283":1480585069128,"1025014824889":1509788625006,"1022264630189":1478686417285,"4961238856":1509788624157,"1504968880":1444487341743,"1618884974":1444487341741,"1022511303579":1480585069130,"1022511303576":1480585069130,"1022511303577":1480585069130,"1021623829616":1509788624942,"1022511303583":1480585069130,"1022511303580":1480585069130,"1022511303581":1480585069130,"1021927929451":1478686417259,"1022511303587":1480585069130,"1025906476293":1509788667458,"1022511303584":1480585069130,"1025906476288":1509788667461,"1022511303591":1480585069130,"1022511303589":1480585069130,"1022511303595":1480585069130,"1000104952612":1478686804029,"1022511303592":1480585069130,"1022511303593":1480585069130,"1022511303598":1480585069130,"1024952433198":1509788624217,"1022057557667":1478686417173,"1022511303596":1480585069130,"1024952433196":1509788624217,"1022511303597":1480585069130,"1024952433197":1509788624217,"1022511303602":1480585069130,"1022511303603":1480585069130,"1024952433203":1509788624217,"1023987954607":1509788624228,"1024952433200":1509788624217,"1022073545099":1509788624928,"1000112030345":1478686417017,"1021261815339":1478686804065,"1022511303604":1480585069130,"1022511303610":1480585069131,"1022511303609":1480585069131,"1002453614390":1491634246519,"1025153365555":1509788625005,"1018513489292":1509788624893,"1018513489287":1509788624893,"1022501472371":1509788624538,"1018513489283":1509788624893,"1018513489280":1509788624893,"1018513489310":1509788624893,"1020907547501":1478686417080,"1018513489307":1509788624893,"1021583065772":1509788624397,"1018513489302":1509788624893,"1022226225371":1478686416985,"1023721734951":1509788625038,"1018513489299":1509788624893,"1021101533161":1478686417232,"1018513489325":1509788624893,"1021790437117":1509788624561,"4950621808":1509788624157,"1021790437119":1509788624561,"1021790437118":1509788624561,"1018513489320":1509788624893,"1022511303658":1480585069131,"1022511303659":1480585069131,"1022511303656":1480585069131,"1018513489317":1509788624893,"1022511303657":1480585069131,"1021101533157":1478686417232,"1022511303662":1480585069131,"1022511303663":1480585069131,"1022511303660":1480585069131,"1022511303661":1480585069131,"1025593480099":1509788624867,"1023606393395":1509788625142,"1022511303666":1480585069131,"1022511303664":1480585069131,"1023821363487":1491634246535,"1022511303671":1480585069131,"1025892450927":1509788667443,"1022511303669":1480585069131,"1022511303674":1480585069131,"1022511303675":1480585069131,"1022511303672":1480585069131,"1022511303673":1480585069131,"1022511303678":1480585069131,"1022511303679":1480585069131,"1022511303676":1480585069131,"1022511303677":1480585069131,"1024886228628":1509788624571,"1022511303424":1480585069129,"1022511303430":1480585069129,"1024886228624":1509788624571,"1024886228625":1509788624571,"1022511303428":1480585069129,"134893964":1491634246513,"1024886228626":1509788624571,"1022511303429":1480585069129,"1024886228627":1509788624571,"1022511303434":1480585069129,"1022511303438":1480585069129,"1022511303439":1480585069129,"1022511303437":1480585069129,"1022511303443":1480585069129,"1022511303440":1480585069129,"1024886228614":1509788624571,"1022511303441":1480585069129,"1022511303447":1480585069129,"1022511303450":1480585069129,"1022511303451":1480585069129,"1022511303448":1480585069129,"1022511303449":1480585069129,"1024886228616":1509788624571,"1022511303455":1480585069129,"1024886228618":1509788624571,"1022511303458":1480585069129,"1022511303459":1480585069129,"1010001146251":1491634246516,"1328158344":1491634246517,"1022511303457":1480585069129,"1010001146253":1491634246516,"1010001146255":1491634246516,"1023076363588":1509788624218,"1018513489279":1509788624893,"1018513489277":1509788624893,"1018513489276":1509788624893,"1020102892427":1509788624369,"1018513489271":1509788624893,"1022511303483":1480585069129,"1022511303480":1480585069129,"1022511303486":1480585069129,"1022511303487":1480585069130,"1022511303484":1480585069129,"1018513489265":1509788624893,"1022511303485":1480585069129,"4994789495":1509788667397,"1022511303491":1480585069130,"1022511303489":1480585069130,"1022511303494":1480585069130,"1022511303495":1480585069130,"1022511303492":1480585069130,"1022511303498":1480585069130,"1023076363580":1509788624218,"1022511303499":1480585069130,"1022110507951":1478686417182,"1022511303496":1480585069130,"1023076363582":1509788624218,"1022511303497":1480585069130,"1024552785215":1509788624185,"1023076363583":1509788624218,"1024156380511":1509788667496,"1022511303502":1480585069130,"1020830742368":1478686417078,"1022511303503":1480585069130,"1022511303500":1480585069130,"1021379123154":1478686804033,"1022511303501":1480585069130,"1023076363579":1509788624218,"1022511303506":1480585069130,"1021937756416":1478686417010,"1022511303504":1480585069130,"1022075904326":1478686417177,"1022511303505":1480585069130,"1021833687856":1509788625069,"1024952433370":1509788624829,"1024952433374":1509788624800,"1077942686":1491634246512,"1021596566251":1478686417115,"1022511303522":1480585069130,"1022628610148":1509788624827,"1022511303523":1480585069130,"1024615306971":1509788667890,"1022628610150":1509788624834,"1022628610151":1509788624824,"1022511303526":1480585069130,"1022511303527":1480585069130,"1022511303530":1480585069130,"1022511303531":1480585069130,"1022511303528":1480585069130,"1022511303529":1480585069130,"1022511303534":1480585069130,"1022511303535":1480585069130,"1022628610153":1509788624801,"1022511303533":1480585069130,"1022609080641":1509788625074,"1022511303538":1480585069130,"1022511303539":1480585069130,"1022511303536":1480585069130,"1022511303543":1480585069130,"1022511303540":1480585069130,"1010149648512":1478686804064,"1022511303541":1480585069130,"1019748431019":1509788624315,"1022511303547":1480585069130,"1022511303550":1480585069130,"1022511303551":1480585069130,"1022511303548":1480585069130,"1022323482154":1509788624290,"1022465561940":1478686417299,"1525809400":1444487341756,"1025032516176":1509788624276,"1025051652905":1509788625069,"1005997678815":1478686804054,"1024952432926":1509788625147,"1024952432927":1509788625148,"1023072299308":1509788625072,"1024952432924":1509788625147,"1024952432925":1509788625148,"1024952432928":1509788625147,"1020737286758":1478686417224,"1024552785618":1509788624185,"4972900942":1509788624161,"1525809370":1444487341708,"4976833165":1509788624161,"1023834733453":1491634246536,"1023834733454":1491634246536,"4994790279":1509788667397,"1023834733457":1491634246536,"1023834733461":1491634246536,"1016749547562":1465470268314,"1023834733467":1491634246536,"1023834733470":1491634246536,"1021871044332":1509788624394,"1618885176":1444487341720,"1004329143307":1444487341712,"1020102891646":1509788624369,"1024912063290":1509788624926,"1025771998843":1509788624438,"1026226566482":1514456869769,"1024735235191":1509788667506,"1024735235184":1509788667506,"408961541":1491634246510,"1024735235196":1509788667506,"1020772937802":1478686417225,"1024735235197":1509788667506,"1024735235195":1509788667505,"1024735235172":1509788667505,"1024735235174":1509788667507,"1024735235175":1509788667505,"1006011441254":1478686804040,"1020622601037":1509788624354,"1024735235182":1509788667506,"1021344650868":1478686417041,"1022031474498":1509788625110,"1020015290315":1478686804064,"1024735235220":1509788667506,"1023569169174":1509788624516,"1020015290319":1478686804064,"1020015290318":1478686804064,"1020015290317":1478686804064,"1024735235218":1509788667506,"1020015290316":1478686804064,"4872370412":1509788624161,"1024735235228":1509788667506,"1024735235229":1509788667506,"1020789846455":1478686417076,"1025513791238":1509788625131,"1024154545722":1509788667410,"1020789846454":1478686417076,"1025513791232":1509788625131,"1025513791235":1509788625131,"1021972359216":1478686417150,"1023569169157":1509788624516,"1024735235205":1509788667507,"1024735235200":1509788667506,"1023569169155":1509788624516,"1007980440098":1478686804015,"1021972359224":1478686417150,"1025513791253":1509788625169,"1023569169166":1509788624519,"1025513791248":1509788625131,"1024735235209":1509788667506,"1024735235211":1509788667506,"1025771998859":1509788624438,"1025771998850":1509788624438,"1022240643100":1478686417194,"1020293993583":1465470268279,"1025513791308":1509788624916,"1024952433094":1509788624554,"1024952433095":1509788624554,"1019732047599":1509788624315,"1024952433099":1509788624554,"1025513791301":1509788624917,"1024952433096":1509788624554,"1024952433097":1509788624554,"1022282063586":1478686417198,"1022282063587":1478686417198,"1021036126275":1478686417092,"1025513791324":1509788624838,"1021237304386":1478686416976,"1024341058886":1509788624423,"1021489483697":1478686417243,"1025513791317":1509788624826,"1025513791319":1509788624849,"1025513791312":1509788624864,"1025513791315":1509788624864,"1025513791342":1509788624838,"1025513791336":1509788624838,"1025513791332":1509788624838,"1021340718754":1465470268224,"1022080099004":1478686417178,"1025513791328":1509788624838,"1025513791329":1509788624838,"1618885265":1444487341729,"1024552785414":1509788624185,"1020775559407":1478686417029,"1021743251134":1478686417125,"1025513791348":1509788624838,"4997149475":1509788667397,"1025513791349":1509788624868,"1022248376532":1478686417196,"1019204998988":1478686804019,"1025627035186":1509788625022,"1025796378066":1509788624274,"1025471191359":1509788624307,"1008809589340":1509788625018,"1008809589338":1509788625018,"1008809589339":1509788625018,"1023889653614":1491634246528,"1023889653612":1491634246528,"1023889653613":1491634246528,"1021585817738":1478686417008,"1291065281":1478686417024,"1023072299019":1509788625072,"1021770251756":1478686417009,"1023569169109":1509788624516,"1021770251751":1478686417009,"1021770251750":1478686417009,"1023569169119":1509788624516,"1023569169112":1509788624516,"1022251391309":1478686417014,"1022646698462":1480585069078,"1022628610772":1509788625105,"1022251391313":1478686417014,"1022628610775":1509788625113,"1016620443893":1478686804049,"1014872936605":1509788624543,"1022628610771":1509788625122,"1022628610781":1509788625089,"1022112604443":1509788624944,"1008809589302":1509788625018,"1023569169136":1509788624516,"1014872936620":1509788624543,"1021240057125":1478686417039,"1008809589304":1509788625018,"1022511303155":1480585069128,"1014872936633":1509788624610,"1025513791229":1509788625131,"1618885389":1444487341732,"1014872936635":1509788624569,"1025513791231":1509788625131,"1022511303158":1480585069128,"1023076364160":1509788624557,"1022646698470":1480585069078,"1023569169122":1509788624516,"1025513791226":1509788625112,"1014872936628":1509788624543,"1023076364168":1509788624557,"1022511303167":1480585069128,"1022511303164":1480585069128,"1025513791218":1509788625246,"1022646698479":1480585069078,"1025513791219":1509788625244,"4972901354":1509788624162,"1002085682074":1478686804029,"1801859296":1444487341738,"1021799349398":1478686417052,"1021645587894":1478686417049,"1023076364157":1509788624557,"1023076364159":1509788624557,"1023076364152":1509788624557,"1020998771492":1465470268304,"1021655811091":1509788624523,"1021164558682":1478686417097,"1021364049270":1478686417104,"1021655811095":1509788624524,"1021655811094":1509788624524,"1022484695982":1478943089532,"1021655811093":1509788624524,"1021927404772":1478686417259,"1021655811092":1509788624524,"1012277897989":1478686804062,"1023970783773":1509788624982,"1021655811097":1509788624524,"1021655811096":1509788624524,"1009118261079":1478686804023,"1020295959826":1509788624321,"1023228274280":1509788624958,"1022468314269":1478686417299,"1024489476874":1509788624836,"1801859284":1444487341740,"1024771015232":1509788667537,"1020998771482":1465470268304,"1024771015238":1509788667537,"1024771015239":1509788667537,"1020998771487":1465470268304,"1020438171022":1478686804031,"1020438171021":1478686804031,"1024771015216":1509788667537,"1024771015217":1509788667537,"1024771015220":1509788667537,"1024771015227":1509788667537,"1013138897143":1478686804015,"1022769527531":1509788625056,"1024771015210":1509788667537,"1024771015211":1509788667537,"1024771015214":1509788667537,"1024771015215":1509788667537,"4976833351":1509788624162,"1014872936480":1509788624612,"1014872936484":1509788624612,"1014872936486":1509788624544,"499271217":1509788624369,"1014872936508":1509788624538,"1014872936496":1509788624544,"1021349762596":1478686417104,"1021476900821":1478686417045,"1014872936501":1509788624536,"1022162936129":1478686417186,"1023476635420":1509788625082,"1025531484823":1509788624335,"1022078133372":1478686417177,"4972901497":1509788624162,"1022058736526":1475218613699,"1021605347477":1509788625082,"1021095764729":1478686417094,"1024161753145":1509788667562,"1022977667832":1509788625050,"1021583984612":1478686417114,"1303384448":1444487341752,"1021088948603":1478686417036,"1303384452":1444487341734,"1021587785657":1478686417246,"1000216247638":1444487341749,"1025796377314":1509788624274,"1019759571635":1509788624281,"1021773920943":1478686417128,"1025902149722":1509788667459,"1021995167608":1509788624463,"1025902149720":1509788667461,"1009715006239":1491634246511,"1022184170048":1478686417187,"1012157183467":1478686417223,"1023085406222":1509788625047,"1020516157222":1465470268303,"1022189937637":1478686417188,"1012895615469":1478686804028,"1022189937638":1478686417188,"1021693836556":1509788624396,"1016473908776":1478686804069,"1009715006219":1491634246511,"1018451492040":1509788624427,"1022199505760":1478686417064,"1009715006211":1491634246511,"1020294124276":1465470268291,"1024156379381":1509788667463,"1009715006254":1491634246511,"1022064110426":1478686417270,"1009715006247":1491634246511,"1017354159007":1478686804049,"1021955976509":1509788624466,"1024154544180":1509788667658,"126245643":1444487341716,"1024161753267":1509788667562,"4997150024":1509788667397,"1024420796490":1509788624860,"1021354086662":1465470268228,"1024420796491":1509788624860,"1021354086661":1465470268228,"1021354086660":1465470268228,"1024420796489":1509788624860,"1021354086659":1465470268228,"1024420796494":1509788624860,"1025098707157":1509788624298,"1024420796493":1509788624860,"1325929387":1491634246519,"1021890834731":1478686417054,"1025118368252":1509788625022,"1024837992752":1509788624948,"1016954002183":1478686804069,"1022112605836":1509788624944,"1024781895156":1509788625021,"1023502717366":1509788624943,"1022023084382":1509788624463,"1003491883213":1478686417220,"1009710812022":1480585069062,"4994790750":1509788667397,"1024195046093":1509788624507,"1024195046088":1509788624507,"1307054360":1444487341721,"1011278555385":1480585069074,"1021156957609":1478686804031,"178149263":1444487341738,"1021789387409":1509788624993,"297815257":1444487341745,"1022701224054":1509788624525,"1022701224055":1509788624525,"1022701224056":1509788624525,"1022701224058":1509788624525,"1022701224059":1509788624525,"1022701224061":1509788624525,"1022701224062":1509788624525,"1021629595659":1478686417119,"1021789387469":1509788624993,"4994790641":1509788667398,"1016936831881":1478686804019,"662993609":1491634246507,"1025274866330":1509788624233,"1025274866331":1509788624234,"1025274866333":1509788624234,"1025274866326":1509788624234,"4997543100":1509788667397,"1025274866325":1509788624234,"1077943584":1491634246513,"1025274866346":1509788624233,"1025274866347":1509788624233,"1025274866344":1509788624233,"1019525086694":1509788625078,"1020462679515":1465470268259,"1025274866349":1509788624234,"1021269939695":1478686804038,"1025274866342":1509788624233,"1021269939694":1478686804038,"1021269939693":1478686804038,"1021269939692":1478686804038,"1021865145975":1509788624394,"1021269939696":1478686804038,"1021900927901":1480585069077,"1022089143340":1509788624439,"1018513357130":1509788624892,"1016396314775":1478686804017,"1020447083036":1478686804033,"1025732939527":1509788624957,"1022043532233":1478686417171,"1016954002033":1478686804069,"1023784125201":1491634246536,"1020553511137":1478686417074,"1018517027075":1478686804065,"1024597611422":1509788624939,"1021491054796":1478686416974,"1021789387319":1509788624993,"1019204997237":1478686804020,"1022540531976":1509788625064,"1022701224064":1509788624525,"1002419010024":1480585069061,"1007198854323":1478686804032,"1017354158592":1478686804049,"1022484565471":1478943089488,"1022484565469":1478943089488,"456935125":1444487341723,"1021700521756":1478686804046,"1025061222249":1509788624932,"1022238678829":1509788624947,"1025712884829":1509788624305,"1022631233402":1509788624434,"1024774031266":1509788624534,"1017388646387":1478686804034,"1025607504924":1509788624431,"1022346679929":1478686417289,"1025607504925":1509788624425,"1025607504923":1509788624428,"1004329142345":1444487341711,"1021640867944":1509788624404,"1021738924700":1478686417252,"1020323483389":1478686804023,"1009965234272":1491634246523,"1018513357528":1509788624906,"1021891359629":1478686417138,"1016230494970":1478686804031,"1017354158591":1478686804049,"1024774031295":1509788624195,"854224074":1491634246515,"4997150715":1509788667396,"1021738924718":1478686417252,"1021897782037":1478686417054,"1016230494921":1478686804017,"1016396315447":1478686804017,"1016728184703":1478686804056,"1022357035003":1509788624937,"1000280079242":1478686804027,"1025607504928":1509788624407,"1007322716111":1478686804022,"1026232332002":1514456869770,"1021738924723":1478686417252,"1026232332004":1514456869769,"1026232332006":1514456869770,"1021738924720":1478686417252,"1026232332007":1514456869768,"1016728184604":1478686804063,"1024117189786":1509788624525,"1024117189787":1509788624525,"1021018433481":1478686417090,"1021928845581":1478686804049,"1016299060893":1480585069065,"1024774031357":1509788625102,"1023927138388":1491634246530,"1023754633738":1509788625081,"1023680579230":1509788667538,"1004731019322":1478686804052,"1022310111474":1478686416982,"4976834257":1509788624160,"1022449963090":1478686417072,"1004588284087":1444487341763,"1004731019467":1478686804041,"1004731019466":1478686804041,"1018513488461":1509788624892,"1004731019471":1478686804041,"1018513488459":1509788624892,"1004731019469":1478686804041,"1018513488456":1509788624892,"1018513488454":1509788624892,"1018513488449":1509788624892,"1004731019483":1478686804041,"1022511303698":1480585069126,"1004731019482":1478686804041,"1022511303699":1480585069126,"1022112605396":1509788624944,"1004731019481":1478686804041,"1022511303697":1480585069126,"1018513488476":1509788624892,"1022511303702":1480585069126,"1004731019486":1478686804041,"1022511303703":1480585069126,"1018513488474":1509788624892,"1022232518582":1478686417193,"1004731019485":1478686804041,"1022511303700":1480585069126,"883059253":1491634246515,"1018513488472":1509788624892,"1004731019473":1478686804041,"1022511303705":1480585069126,"1018513488468":1509788624892,"1022511303710":1480585069126,"1022511303711":1480585069126,"1018513488464":1509788624892,"1013028520828":1478686416995,"1022511303713":1480585069126,"1004731019490":1478686804041,"1021790697787":1478686417052,"1021977996512":1478686417010,"1025607505061":1509788624799,"1025607505058":1509788624823,"1004731019518":1478686804041,"1025607505056":1509788624829,"1004731019516":1478686804041,"1025607505057":1509788624833,"1021472311854":1478686417045,"4976834150":1509788624160,"1019166070056":1478686804020,"1018513357314":1509788624892,"1022307096698":1478686417068,"1022196490651":1478686417189,"1018513488430":1509788624892,"1021472705166":1478686417109,"1018513488423":1509788624892,"1022922093807":1509788624932,"1021789387110":1509788624993,"1022458483032":1478686417298,"1018513488445":1509788624892,"1021806818935":1478686417255,"1018513488441":1509788624892,"1018513488437":1509788624892,"1022631233408":1509788624451,"1018513488433":1509788624892,"1004731019592":1478686804041,"1024187050403":1509788625034,"1024576508526":1509788667501,"1004731019598":1478686804041,"1004731019596":1478686804041,"1024576508514":1509788667500,"1004731019586":1478686804041,"4976834476":1509788624160,"1004731019591":1478686804041,"1022859442380":1509788625018,"1004731019609":1478686804041,"1024576508536":1509788667501,"1023076363232":1509788624854,"1022356772557":1478686417203,"1023820971909":1491634246535,"1024576508528":1509788667501,"1023820971913":1491634246535,"1004731019606":1478686804041,"1025401344":1478686417020,"1004731019605":1478686804041,"1024576508533":1509788667500,"1022236974556":1478686417065,"1024154545045":1509788667409,"1023076363228":1509788624854,"1023076363229":1509788624854,"1020278919835":1480585069076,"1023076363230":1509788624854,"1023076363231":1509788624854,"1021976948051":1478686417301,"1016230495182":1478686804031,"1020136577825":1480585069063,"1022246542718":1478686417195,"1024576508511":1509788667500,"1025007614177":1509788624977,"1024576508499":1509788667500,"1024058732922":1509788625016,"1024576508502":1509788667501,"1016230495197":1478686804017,"1004731019531":1478686804041,"1004731019530":1478686804041,"1004731019528":1478686804041,"1025628083103":1509788624828,"1004731019535":1478686804041,"1004731019534":1478686804041,"1004731019533":1478686804041,"1004731019532":1478686804041,"1004731019523":1478686804041,"1004731019521":1478686804041,"1004731019520":1478686804041,"1004731019527":1478686804041,"1004731019525":1478686804041,"804155553":1444487341726,"1020923014268":1478686417032,"1016230495155":1478686804016,"1025607505223":1509788624201,"1004731019539":1478686804041,"1022026885691":1478686417058,"1004731019537":1478686804041,"1004731019536":1478686804041,"1021155647023":1509788625020,"1025607505227":1509788624186,"1025607505224":1509788624204,"1004731019540":1478686804041,"1025607505225":1509788624198,"4994791121":1509788667396,"1021715987585":1509788624419,"1925197227":1444487341708,"1077944108":1491634246517,"1004731019577":1478686804041,"1004731019576":1478686804041,"1004731019583":1478686804041,"1004731019582":1478686804041,"1016728184364":1478686804051,"1004731019570":1478686804041,"1016230495128":1478686804018,"1004731019568":1478686804041,"1025628083104":1509788624833,"1004731019574":1478686804041,"1025628083105":1509788624823,"1022621664912":1509788625074,"1004731019572":1478686804041,"1025628083107":1509788624746,"1024212347071":1509788624238,"1021655810048":1509788624801,"1024492230420":1509788667888,"1021223934682":1478686417099,"1016768815951":1478686804049,"1018725691308":1509788624972,"1018725691311":1509788624972,"1018725691310":1509788624972,"1021715987559":1509788624816,"1014163996545":1465470268240,"1020779885658":1478686416982,"1021231536472":1478686417039,"1021314896997":1465470268208,"1021314896996":1465470268207,"1018725691315":1509788624972,"1021314896998":1465470268208,"1021155647214":1509788625021,"1016728184566":1478686804063,"1020810293833":1478686416998,"1020923014273":1478686417033,"4994790938":1509788667396,"1020810293835":1478686416998,"1019596520429":1509788624946,"1019596520431":1509788624946,"1024453171575":1509788625030,"1021680598963":1478686804028,"1021928714469":1478686417142,"1019596520423":1509788624942,"1019596520417":1509788624959,"1019596520418":1509788624959,"1023821496225":1491634246536,"1013148466019":1478686804062,"1013148466021":1478686804062,"1013148466020":1478686804062,"1013148466023":1478686804062,"1013148466022":1478686804062,"1013148466025":1478686804062,"1021517924352":1478686416977,"1013148466026":1478686804062,"1013148466028":1478686804062,"1024576508555":1509788667501,"1024576508552":1509788667500,"1024576508553":1509788667501,"1024576508558":1509788667500,"1023134951571":1509788624205,"1024576508556":1509788667501,"1024576508557":1509788667501,"1024576508547":1509788667501,"1021680074726":1478686804032,"1023820971902":1491634246535,"1020006507067":1509788625076,"158357129":1444487341704,"1021341635492":1509788624180,"1014933499436":1478686804018,"1018513474767":1509788624604,"1022447873609":1480585069106,"1018513474764":1509788624604,"1023945737988":1491634246517,"1022447873613":1480585069106,"1018513474760":1509788624604,"1022447873601":1480585069106,"1018513474755":1509788624604,"1673135028":1478686804054,"1022447873604":1480585069106,"1014933499427":1478686804031,"1018513474782":1509788624604,"1018513474781":1509788624603,"1022447873630":1480585069106,"1018513474777":1509788624603,"1022447873629":1480585069106,"1022447873616":1480585069106,"1018513474770":1509788624604,"1018513474797":1509788624603,"1022447873646":1480585069106,"1022447873647":1480585069106,"1018513474794":1509788624603,"1022447873644":1480585069106,"1012418140190":1478686417074,"1018513474790":1509788624603,"1022447873632":1480585069106,"1022447873639":1480585069106,"1018513474786":1509788624603,"1020497164957":1478686804033,"1022447873637":1480585069106,"1024325459535":1495284743424,"1021112672215":1478686417095,"126248894":1444487341736,"1022447873651":1480585069106,"1022447873648":1480585069106,"1022447873649":1480585069106,"1018513474804":1509788624604,"1018513474802":1509788624603,"1016399709943":1480585069069,"1018513474800":1509788624603,"1022447873546":1480585069105,"1022447873544":1480585069105,"1001557479894":1478686417023,"1022447873551":1480585069105,"1022293075401":1478686417198,"1022447873543":1480585069105,"1022447873540":1480585069105,"1022447873562":1480585069105,"1022517998189":1509788625075,"1022086388135":1478686417062,"1022447873567":1480585069105,"1000531072254":1478686804051,"1025332402722":1509788625019,"1022447873557":1480585069105,"1025771090998":1509788624523,"1022427950585":1478686417294,"1025771090997":1509788624537,"1021969076882":1478686417149,"1022447873570":1480585069105,"1022447873568":1480585069105,"1022447873569":1480585069105,"1023821217794":1509788624970,"1004329154088":1444487341740,"1022447873595":1480585069105,"1000531072214":1478686804051,"1016301797584":1480585069066,"1022447873592":1480585069105,"1022447873598":1480585069106,"1022454296478":1478686417216,"1022447873590":1480585069105,"1022630721816":1509788625074,"1022447873588":1480585069105,"1018513474736":1509788624604,"1022447873739":1480585069106,"1022447873737":1480585069106,"1021272566008":1509788624433,"1022447873742":1480585069106,"1022447873741":1480585069106,"1022092548371":1478686417061,"1021272566003":1509788624434,"1022447873731":1480585069106,"1021272566002":1509788624441,"1022447873728":1480585069106,"1021272566007":1509788624433,"1023207824274":1509788625043,"1022447873735":1480585069106,"1021903146575":1478686417139,"1018364721976":1509788624172,"1022447873746":1480585069106,"1022447873748":1480585069106,"1021387124504":1478686804027,"1022447873749":1480585069106,"1022447873770":1480585069106,"1022447873771":1480585069106,"1022953409673":1509788625073,"1020819328476":1509788624311,"1021985461085":1478686416975,"1023066657740":1509788625073,"1025593748079":1509788624844,"1023947049031":1491634246531,"1023947049029":1491634246531,"1022233567645":1478686417193,"1022447873786":1480585069106,"1025772008600":1509788625137,"1022447873787":1480585069106,"1012749085909":1478686416995,"1022447873784":1480585069106,"1022447873785":1480585069106,"1022447873790":1480585069106,"1025772008604":1509788625136,"1025772008605":1509788625136,"1022447873789":1480585069106,"1025772008607":1509788625136,"4954802157":1509788624164,"1025593748080":1509788624844,"1022447873779":1480585069106,"1025593748082":1509788624844,"1004709252357":1509788624972,"1022447873777":1480585069106,"1025593748083":1509788624844,"1022447873782":1480585069106,"1025593748085":1509788624844,"1025593748086":1509788624844,"1022447873679":1480585069106,"1022447873690":1480585069106,"1022447873691":1480585069106,"1022447873689":1480585069106,"1001557479749":1478686417023,"1022451412706":1478686417296,"1022447873692":1480585069106,"1022447873682":1480585069106,"1022447873680":1480585069106,"1022447873681":1480585069106,"1022447873686":1480585069106,"1022447873687":1480585069106,"1022447873684":1480585069106,"1010091970086":1491634246528,"1020804910269":1478686417077,"1010091970092":1491634246528,"1022447873726":1480585069106,"1010091970096":1491634246522,"1019355870798":1509788624316,"1021089996199":1478686417036,"1022447873866":1480585069106,"1025671606052":1509788624921,"1022447873867":1480585069106,"1022447873864":1480585069106,"1024360898886":1509788625016,"1022447873865":1480585069106,"1022447873871":1480585069106,"1025671606061":1509788624921,"1025671606059":1509788624921,"1022447873881":1480585069107,"1022447873887":1480585069107,"1022447873885":1480585069107,"1020883292310":1478686417227,"1004847404128":1478686804032,"1020883292307":1478686417227,"1022447873877":1480585069107,"1020883292335":1478686417227,"1021965406254":1478686417148,"4954801783":1509788624164,"1012125189777":1478686417025,"1025671606018":1509788624921,"1022447873890":1480585069107,"1024460646234":1509788624989,"1024460646233":1509788624988,"1025671606024":1509788624921,"1001557479614":1478686417023,"1018644548145":1478686804022,"1024460646236":1509788624987,"1022447873893":1480585069107,"1024460646237":1509788624987,"1025671606036":1509788624921,"1021019871320":1509788624971,"1025671606045":1509788624921,"1021965406261":1478686417148,"1025671606043":1509788624921,"1022431357959":1478686417212,"1023431289069":1509788625016,"335705412":1444487341743,"1024899727713":1509788624334,"757091446":1444487341728,"1023431289072":1509788625016,"1024161748350":1509788667562,"1022447873834":1480585069106,"1022447873835":1480585069106,"1022447873833":1480585069106,"1022447873838":1480585069106,"1022447873839":1480585069106,"1022447873836":1480585069106,"1022447873837":1480585069106,"1022447873827":1480585069106,"1022447873824":1480585069106,"1022447873830":1480585069106,"1562262640":1444487341719,"1022447873828":1480585069106,"1021272566017":1509788624433,"1020605022554":1478686417224,"1000531072289":1478686804051,"1016719530064":1478686804070,"1016719530065":1478686804070,"1019697171415":1509788624391,"1008740777178":1478686804030,"1021558438105":1478686417113,"1016719530062":1478686804070,"1016719530063":1478686804070,"335705499":1444487341743,"1025880144463":1509788667402,"1022259520032":1478686417196,"1024840498187":1509788624961,"1025666756548":1509788624393,"1022346029527":1478686804065,"1025666756549":1509788624393,"1025666756546":1509788624393,"1025666756547":1509788624393,"1025666756544":1509788624393,"662980139":1444487341733,"1001557479484":1478686417023,"1025666756545":1509788624393,"1019865339368":1509788625079,"1022754963875":1509788624182,"1025666756542":1509788624393,"1025666756543":1509788624393,"1025666756540":1509788624393,"1025666756541":1509788624393,"1025548396107":1509788625020,"1016397350710":1465470268265,"1022184562627":1478686417187,"1000175484432":1478950494932,"1021387124334":1478686804065,"1025801631633":1509788624945,"1016284642899":1480585069064,"1023945737976":1491634246517,"1022108670844":1478686417276,"1018379795768":1509788625079,"1008317277836":1478686804023,"1022434373435":1480585069078,"1022434373436":1480585069078,"1022434373437":1480585069078,"1022434373438":1480585069078,"1023309914351":1509788624233,"1021173473359":1465470268186,"1022318371853":1478686417200,"1020245764480":1509788625020,"1021173473361":1465470268186,"1009745951565":1491634246512,"1024686356178":1509788625150,"1024686356176":1509788625150,"1024686356177":1509788625150,"1025593747704":1509788625136,"1024686356174":1509788625150,"1024686356175":1509788625150,"1024607972792":1509788667589,"1020743568336":1478686417028,"1025593747699":1509788625136,"1025593747700":1509788625136,"1025593747701":1509788625136,"1025593747702":1509788625136,"1025593747703":1509788625136,"1019552071848":1480585069074,"1023096543228":1509788625046,"1022434373464":1480585069078,"1022046934066":1478686417171,"1022434373466":1480585069078,"1022434373456":1480585069078,"1022087830446":1478686417179,"1022493619165":1478943089536,"1022434373461":1480585069078,"1001557480445":1478686417023,"1022434373462":1480585069078,"1022434373448":1480585069078,"1022434373449":1480585069078,"1022434373450":1480585069078,"1003695428210":1478686417220,"1022282589776":1478686417286,"1022434373453":1480585069078,"1022434373454":1480585069078,"1025044696052":1509788624569,"1022434373455":1480585069078,"1022434373440":1480585069078,"1003695428216":1478686417220,"1018085664822":1478686804049,"1003635134403":1478686416993,"1022434373442":1480585069078,"1022434373445":1480585069078,"1021501945041":1478686416991,"1022434373446":1480585069078,"1022434373447":1480585069078,"1022455475575":1478686417297,"1020419569618":1478686804028,"1025902165735":1509788667450,"1024471262552":1509788624294,"1022455475580":1478686417298,"1022455475576":1478686417297,"1020773976252":1478686417029,"1003695428241":1478686417220,"1003695428242":1478686417220,"1025593747547":1509788624211,"1016399709267":1480585069069,"1021814147758":1509788624403,"1021874834993":1478686417136,"2003310029":1478950494931,"1024313270175":1509788624169,"1022023866133":1478686417163,"1020987889119":1478686417034,"1021307037944":1478686417238,"2003310032":1478950494931,"1025289016751":1509788624286,"1011906312197":1478686804064,"1021491591051":1509788624401,"1023042015266":1509788625079,"1022013642474":1478686417159,"1025628089881":1509788624428,"1025628089882":1509788624431,"1025628089883":1509788624425,"1001557480283":1478686417023,"1025469489307":1509788624973,"1021732750849":1478686417051,"2003309959":1478950494930,"1021968945157":1478686417149,"1020210506580":1509788624310,"1022459538762":1478686417217,"2003309968":1478950494930,"1025628089889":1509788624407,"1022434373176":1480585069095,"1022434373177":1480585069096,"1022434373178":1480585069096,"1025234622290":1509788624948,"1022434373179":1480585069096,"1022434373181":1480585069096,"1025541973240":1509788625082,"1022434373183":1480585069096,"1020551953990":1478686804027,"1020551953987":1478686804027,"1020551953986":1478686804027,"1020551953984":1478686804027,"1002052791526":1478950494935,"1022434373175":1480585069095,"1023064821910":1509788625048,"1022095825491":1478686417274,"1022382860605":1478686417205,"1012476731298":1444487341702,"1010091970014":1491634246522,"1020551954000":1478686804027,"1008797385416":1478686804025,"1020841872677":1478686417078,"1012158876307":1478686417025,"1008797385422":1478686804025,"1024782432771":1509788625020,"1024686356424":1509788624556,"1024686356422":1509788624556,"1024686356423":1509788624556,"1024686356420":1509788624556,"1022095825534":1478686417274,"1024686356421":1509788624556,"1008797385385":1478686804025,"1024926728651":1509788625089,"1023162866414":1509788625044,"1008797385388":1478686804025,"1018451608539":1509788624427,"1024926728654":1509788625090,"1024926728652":1509788625090,"1015506932556":1480585069068,"1008797385400":1478686804025,"1008797385406":1478686804025,"1024926728658":1509788625089,"1020294131189":1465470268292,"1020841872731":1478686417078,"1008797385396":1478686804025,"1024926728660":1509788625089,"1021625024042":1478686417117,"1024926728683":1509788625090,"1022434373211":1480585069096,"1022434373212":1480585069096,"1024789248441":1509788625090,"1021387123951":1478686804065,"1022434373200":1480585069096,"1022434373201":1480585069096,"1022434373202":1480585069096,"1024926728672":1509788625090,"1018828969329":1478686804028,"1022434373205":1480585069096,"1022434373207":1480585069096,"1021151322846":1509788624934,"1024926728677":1509788625089,"1022434373195":1480585069096,"1022434373196":1480585069096,"1022434373198":1480585069096,"1022434373184":1480585069096,"1022184168827":1478686417187,"1022434373186":1480585069096,"1024926728689":1509788625089,"1022434373188":1480585069096,"1022434373191":1480585069096,"1017038548821":1478686804042,"1022447873483":1480585069105,"1017038548822":1478686804042,"1017038548823":1478686804042,"1019125312499":1509788625080,"1015594227019":1478686804065,"1022447873487":1480585069105,"1022447873485":1480585069105,"1022447873474":1480585069105,"1010091969871":1491634246528,"1022455868537":1478686417072,"1015599731987":1478686804016,"1022447873475":1480585069105,"1022447873473":1480585069105,"1017038548824":1478686804042,"1022447873478":1480585069105,"1010091969867":1491634246528,"1017038548825":1478686804042,"1017038548826":1478686804043,"1022447873476":1480585069105,"1017038548827":1478686804043,"1022447873477":1480585069105,"1022447873502":1480585069105,"1025801631217":1509788624945,"1022447873500":1480585069105,"413563697":1478686417018,"1022092548620":1478686417061,"1365783295":1478686804024,"1022447873501":1480585069105,"1022447873490":1480585069105,"1022447873489":1480585069105,"1444951484":1444487341726,"1017038548808":1478686804042,"1020400957394":1465470268317,"1017038548809":1478686804042,"1017038548810":1478686804042,"1021309135286":1478686416988,"1017038548811":1478686804042,"126247974":1444487341742,"1001557479986":1478686417023,"1021242680706":1478686417236,"1022447873515":1480585069105,"1020194122498":1509788624354,"1022447873506":1480585069105,"1022447873507":1480585069105,"1022447873504":1480585069105,"1022447873505":1480585069105,"1020194122504":1509788625078,"1022447873510":1480585069105,"1020807663522":1478686417077,"1022447873509":1480585069105,"1025279448116":1509788624562,"1025279448117":1509788624562,"1020419569377":1478686804028,"1025279448118":1509788624562,"1025279448113":1509788624562,"1020194122517":1509788625078,"1022447873520":1480585069105,"4954801390":1509788624162,"1020194122520":1509788625078,"1025279448121":1509788624562,"136604570":1478686417017,"1021506794974":1478686417007,"247753988":1444487341749,"1022095825551":1478686417274,"4937500038":1509788624162,"1025593747738":1509788624548,"1025593747739":1509788624548,"1022095825553":1478686417274,"1025593747740":1509788624548,"1021929360519":1478686417142,"1022434373344":1480585069096,"1022434373347":1480585069096,"1022434373350":1480585069096,"1023432075840":1509788624523,"1022434373337":1480585069096,"1022434373338":1480585069096,"1022434373339":1480585069096,"1022434373340":1480585069096,"1024644543128":1509788625164,"1022434373341":1480585069096,"1024644543129":1509788625164,"1022434373342":1480585069096,"1024644543130":1509788625163,"1022466878671":1478686417072,"1024644543131":1509788625163,"1022434373328":1480585069096,"1022434373329":1480585069096,"1022434373330":1480585069096,"1024644543126":1509788625163,"1022434373331":1480585069096,"1022434373332":1480585069096,"1022434373335":1480585069096,"1022434373320":1480585069096,"1022434373322":1480585069096,"1022434373323":1480585069096,"1022434373324":1480585069096,"1022434373325":1480585069096,"247754035":1444487341743,"1022434373327":1480585069096,"1018246756134":1509788625020,"1025026476869":1509788624972,"1001557480045":1478686417023,"1018364721239":1509788624172,"1021998044986":1478686417301,"1025344593825":1509788624308,"1024157290597":1509788667856,"1017403049242":1478686804020,"1022945020077":1509788624977,"1021513740817":1509788624276,"1021998044980":1478686417301,"1021513740822":1509788624273,"1021998044983":1478686417301,"1021998044982":1478686417301,"1021513740810":1509788624273,"1021513740809":1509788624273,"1021513740808":1509788624273,"1021941027991":1509788624609,"1021513740813":1509788624273,"1021513740803":1509788624273,"1021513740802":1509788624273,"1562261764":1444487341740,"1021513740801":1509788624273,"1021513740800":1509788624273,"1025018348335":1509788625023,"1021982578203":1478686417057,"1021513740804":1509788624273,"1021513740858":1509788624811,"1021513740857":1509788624811,"1016831990567":1478686804028,"1021513740856":1509788624811,"1021513740863":1509788624811,"1021513740861":1509788624811,"1021513740860":1509788624811,"1021513740851":1509788624811,"1021513740850":1509788624811,"1024846526808":1509788624948,"1021513740855":1509788624811,"1018364723076":1509788624172,"1021513740854":1509788624811,"1021513740852":1509788624812,"1022393216956":1478686417291,"1020612887964":1478686417027,"1021901966017":1509788624394,"1020430971583":1465470268321,"1022090059259":1509788624439,"1022036972173":1509788624462,"1024899728493":1509788624334,"1022609358049":1509788625074,"1025344593904":1509788624307,"1021513740873":1509788624811,"1021513740872":1509788624811,"1014573456882":1478686804031,"1022043394621":1478686417059,"1021513740867":1509788624811,"1021513740866":1509788624811,"1021513740865":1509788624811,"1021513740864":1509788624811,"1021513740871":1509788624811,"1021513740870":1509788624811,"1021513740868":1509788624811,"1020911212417":1478686417080,"1011715992176":1478686804027,"1024926729961":1509788625090,"1024926729966":1509788625090,"1020911212422":1478686417080,"1025714992636":1509788624537,"1025714992634":1509788624540,"1025609871239":1509788624999,"1021998044993":1478686417301,"1010628176560":1478686804054,"1024926729974":1509788625089,"1014573456859":1478686804031,"1025593880135":1509788624540,"1020314315549":1478686804027,"4937499333":1509788624162,"1025593880138":1509788624524,"1025593880136":1509788624542,"1025593880137":1509788624537,"1022409599013":1478686417208,"1017124140318":1478686804024,"1010044522262":1480585069062,"757090697":1444487341728,"2033065348":1491634246510,"1024005246757":1491634246530,"1022090059013":1478686417180,"1024005246760":1491634246533,"1022365167079":1509788624957,"1022021374229":1509788624181,"1161437691":1478686804033,"1022866375609":1509788624467,"1020294261359":1465470268300,"1022132789240":1478686417276,"1022866375605":1509788624467,"1022866375606":1509788624467,"1022346030246":1478686804047,"1022233568734":1478686417193,"1009797331097":1478686804028,"1020244848457":1465470268278,"1004787242479":1480585069067,"1022240122797":1478686417014,"1022240122795":1478686417014,"1018513473988":1509788624603,"1116481410":1491634246508,"1022835703869":1509788624388,"1022835703867":1509788624388,"1021893707885":1478686417138,"1018364722825":1509788624172,"1022420347083":1478686417209,"1022828495004":1509788625074,"1022254933741":1478686416976,"1023947574728":1491634246532,"1021425267820":1478686417106,"1022104739809":1478686417275,"1025646700771":1509788624337,"1022065676918":1478686417175,"1022051652283":1478686417269,"1022051652282":1478686417269,"1024411624975":1509788624462,"1018513473949":1509788624603,"1018513473944":1509788624603,"1018513473936":1509788624603,"1018513473965":1509788624603,"1198137871":1491634246507,"1018513473955":1509788624603,"1019767819109":1509788624315,"1018513473953":1509788624603,"1022090321110":1509788624943,"1021580722031":1509788624404,"1198137875":1491634246507,"1018513473974":1509788624603,"1008829106037":1509788625081,"4848502149":1509788624163,"1019703987849":1509788624320,"1022221247564":1478686417281,"1025015857885":1509788624430,"1023432469555":1509788624516,"1021622007820":1478686417117,"1020675146139":1478686417075,"1022490211403":1478943089315,"1022130036432":1509788625082,"1022130036431":1509788625082,"1567635681":1491634246519,"1022130036430":1509788625082,"1022130036429":1509788625082,"1020047792872":1509788625077,"1022130036428":1509788625082,"1022220592226":1478686417192,"1016854127683":1478686804034,"148008260":1478686804039,"1020047792871":1509788625077,"1021953479778":1478686417146,"1018513473900":1509788624603,"1021953479781":1478686417146,"1198138063":1491634246507,"1018513473897":1509788624603,"1016862909597":1478686804016,"1018513473918":1509788624603,"1018513473917":1509788624603,"1022049686448":1509788624434,"1523728228":1478686417024,"1020675146145":1478686417075,"1022271840638":1478686417285,"1018513473912":1509788624603,"1198138067":1491634246507,"1018513473908":1509788624603,"1018513473905":1509788624603,"1008689921999":1478686804064,"1018513473904":1509788624603,"1024460645298":1509788624988,"1021934998846":1478686416982,"1024460645299":1509788624989,"1021453973065":1478686804043,"1021453973064":1478686804043,"1024460645297":1509788624987,"1021240845206":1465470268197,"4937499527":1509788624162,"1025771090332":1509788624428,"1022238680841":1478686417194,"1025771090333":1509788624431,"1021453973063":1478686804043,"1021453973062":1478686804043,"1022455474744":1478686417297,"1021453973061":1478686804043,"1022455474745":1478686417297,"1024460645281":1509788624989,"1024460645286":1509788624988,"1021644290950":1509788624404,"1024460645290":1509788624988,"1024460645295":1509788624987,"1024460645292":1509788624989,"1010323840714":1465470268245,"1016854127665":1478686804049,"1022234092792":1478686417065,"1010812468228":1509788624299,"1024460645258":1509788624988,"1024460645259":1509788624988,"1018364722602":1509788624172,"1020950401921":1478686417033,"1022198323514":1509788624928,"1024634451509":1509788667600,"1021769842930":1478686417127,"1020665709231":1478686417075,"1024634451514":1509788667594,"1025513399170":1509788624339,"1024634451492":1509788667599,"1024634451489":1509788667650,"1020294260885":1465470268300,"1016399708406":1480585069069,"1024634451497":1509788667603,"1016366023310":1465470268320,"1022731909438":1509788624379,"1012115882086":1478686417223,"4954800401":1509788624162,"1022481036856":1478943089315,"1025711847317":1509788624306,"1021501944033":1478686416991,"1023066658105":1509788625073,"1024634451525":1509788667649,"1023032448968":1509788624421,"1023032448969":1509788624421,"1020747894755":1478686417028,"1021334170319":1478686416983,"1022040903916":1478686417170,"1021487526881":1478686417110,"1024313269077":1509788624927,"1025068027068":1509788624293,"1025331485928":1509788624871,"1023538112973":1509788625004,"1025068027064":1509788624293,"1021608377087":1478686417008,"1023538112966":1509788625003,"1025331485923":1509788624871,"1025068027060":1509788624293,"1025331485920":1509788624871,"1021020266474":1478686416979,"1025331485921":1509788624871,"1023538112965":1509788625003,"1025331485926":1509788624871,"1018659490486":1478686804039,"1025331485924":1509788624871,"1021419370282":1478686804050,"1023538112991":1509788625003,"1025201591482":1509788624281,"1010013589496":1491634246521,"1023538112986":1509788625003,"1022099103649":1509788624530,"1023538112985":1509788625003,"1023538112982":1509788625003,"1023538112980":1509788625003,"1025068027043":1509788624293,"1020850522396":1478686417078,"1025331485896":1509788624871,"1025331485890":1509788624871,"1025331485891":1509788624871,"1198137799":1491634246507,"1008054620920":1478686804052,"1025331485892":1509788624872,"1025331485912":1509788624871,"1025331485913":1509788624871,"1025331485918":1509788624871,"1025331485917":1509788624871,"1025331485907":1509788624871,"1025331485904":1509788624871,"1025331485910":1509788624871,"1020824701876":1509788624934,"1025331485908":1509788624871,"1001380921565":1478686804051,"1001380921560":1478686804051,"1001380921562":1478686804051,"1001380921556":1478686804051,"1024648738807":1509788624515,"1021513740500":1509788624276,"1025331485883":1509788624872,"1001380921550":1478686804051,"1025331485886":1509788624871,"1001380921544":1478686804051,"1025331485884":1509788624871,"1025331485872":1509788624872,"1025331485878":1509788624872,"1198137783":1491634246507,"1021782687948":1509788624399,"1023538112942":1509788625003,"1023538112940":1509788625003,"1023538112941":1509788625003,"1025772008130":1509788624565,"1012967849873":1478686804034,"1026832365049":1523788103996,"1022208665212":1480585069087,"1531592120":1478686804054,"1023538112953":1509788625004,"1001380921573":1478686804051,"1001380921572":1478686804051,"1017612634214":1478686804066,"1001380921569":1478686804051,"1023538112947":1509788625003,"1021261815822":1478686804066,"1021711385920":1478686417250,"1021250019524":1478686804046,"1022081670951":1478686417178,"1022346030939":1478686804050,"1021632100804":1509788624352,"1023637205588":1509788624279,"1598961789":1444487341741,"1022451804467":1478686417215,"1012259801270":1478686417025,"1325803590":1444487341749,"1020294130159":1465470268292,"1018364722401":1509788624172,"1025884208338":1509788667465,"1025884208339":1509788667461,"1022065676385":1478686417175,"1025270010212":1509788624423,"1292905030":1478950494921,"1025067634042":1509788624292,"1012967849500":1478686804032,"1021178455419":1478686417234,"1021562109506":1509788624401,"1021874834193":1478686417136,"1024869595541":1509788624942,"1020500966911":1465470268303,"1022138686288":1478686417013,"1021250019421":1478686804046,"1022921428385":1509788624937,"1025608035453":1509788625107,"1021940373265":1478686417260,"1021894494940":1509788624465,"1025910684231":1509788667457,"1024785055407":1509788624197,"1024899729301":1509788624335,"1021619255833":1478686416981,"1021619255835":1478686416981,"1025714861581":1509788624420,"1025902164955":1509788667460,"1025044696649":1509788624870,"1019865600924":1509788625077,"1020532554564":1509788624324,"1021020659362":1478686417035,"1021769842953":1478686417127,"1021513740795":1509788624276,"1021513740794":1509788624273,"1020824701672":1509788624934,"1021513740793":1509788624273,"1021513740796":1509788624273,"1021513740791":1509788624273,"1021513740789":1509788624273,"1021513740788":1509788624273,"1021124729050":1478686416974,"1023845074682":1491634246537,"1025331483242":1509788624467,"1025331483243":1509788624467,"1025331483247":1509788624467,"4937502283":1509788624165,"1025331483245":1509788624467,"1023491056692":1509788624932,"1025331483232":1509788624467,"1025331483258":1509788624467,"1024212344620":1509788625184,"1024212344619":1509788625184,"1025331483260":1509788624467,"1024212344616":1509788625184,"1022062927687":1478686417174,"1021139134551":1478686417234,"1024212344614":1509788625184,"1024212344612":1509788625184,"1025331483249":1509788624467,"1022133965592":1509788625079,"1024212344610":1509788625184,"1025331483253":1509788624467,"1021132712076":1478686417037,"1000307199549":1478686804029,"1024212344607":1509788625184,"1025331483215":1509788624467,"1025331483231":1509788624467,"1025331483218":1509788625171,"1021774564950":1509788624193,"1025331483216":1509788624467,"1013321074188":1509788625020,"1010091968129":1491634246528,"1023032449499":1509788624820,"1016092490611":1509788624941,"4938550799":1509788624165,"1023032449487":1509788624820,"1013321074192":1509788625020,"1022645662438":1480585069137,"1022645662439":1480585069137,"1022645662440":1480585069137,"1022645662441":1480585069137,"1022645662442":1480585069137,"1013321074210":1509788625020,"1022645662446":1480585069137,"1022645662448":1480585069137,"1024886241120":1509788624880,"1022645662453":1480585069137,"1022645662456":1480585069137,"1020891158861":1478686416999,"1022645662458":1480585069137,"4990058773":1509788624163,"1021286719992":1478686417040,"1022645662460":1480585069137,"1022447478286":1478686804065,"1022645662462":1480585069137,"4563957897":1465469681386,"1023829870954":1509788667494,"1023829870952":1509788667494,"1023829870958":1509788667494,"1023829870957":1509788667494,"1023829870945":1509788667494,"1024520675922":1509788624444,"1024520675923":1509788624444,"1024634452120":1509788667599,"1024520675921":1509788624444,"1023617023029":1509788624969,"1023829870949":1509788667494,"1024520675918":1509788624444,"1023330888504":1509788625072,"1024634452102":1509788667649,"1024520675919":1509788624444,"1021027209609":1478686417035,"1024634452104":1509788667600,"1015170348178":1478686804053,"1015170348179":1478686804053,"1010092492414":1491634246517,"1023829870923":1509788667494,"1023829870920":1509788667494,"1020797830148":1478686417077,"1022047329935":1478686417171,"1010092492409":1491634246516,"1010092492402":1491634246516,"1023829870917":1509788667494,"1022292946228":1478686417286,"1010092492396":1491634246516,"1010091968116":1491634246522,"1023829870943":1509788667494,"1024634452128":1509788667600,"1023829870930":1509788667494,"1010092492390":1491634246516,"1022292946237":1478686417286,"1010092492387":1491634246516,"1023829870935":1509788667494,"1022292946232":1478686417286,"1010755059101":1444487341761,"1008664490297":1478686804030,"1018771823522":1509788624372,"1022402388939":1478686417292,"1022136063022":1478686417184,"1020294260345":1465470268300,"1011515976498":1480585069074,"1025331483274":1509788624467,"1025331483272":1509788624467,"1025331483273":1509788624467,"1015536818877":1478686804033,"1025331483270":1509788624467,"1017431624612":1509788624284,"1021742582919":1478686804039,"1021742582926":1478686804039,"1021742582925":1478686804039,"1021742582924":1478686804039,"1022468581362":1478686417299,"1021742582923":1478686804039,"1021742582922":1478686804039,"1021742582921":1478686804039,"1021742582920":1478686804039,"4990058604":1509788624163,"1021526064731":1478686417113,"1022438434812":1478686417213,"1022413661562":1478686417302,"1022645662611":1480585069138,"1020437528360":1478686804031,"1021453974160":1478686804065,"1022645662620":1480585069138,"1022645662624":1480585069138,"1022242876323":1478686417066,"1023204676111":1509788625043,"1022645662626":1480585069138,"1022645662627":1480585069138,"1022645662631":1480585069138,"1021531435458":1509788624461,"1022645662636":1480585069138,"1022645662638":1480585069138,"1022645662643":1480585069138,"1022645662649":1480585069138,"1025299894645":1509788624294,"1020980551417":1478686417087,"1022645662654":1480585069138,"1022645662655":1480585069138,"1022645662658":1480585069138,"1021566825359":1509788624397,"1022645662660":1480585069138,"1022645662662":1480585069138,"1022645662663":1480585069138,"1022645662664":1480585069138,"1022645662667":1480585069138,"4938551059":1509788624165,"1024886884798":1509788624460,"4967121227":1509788624163,"1021733801382":1478686417051,"1022645662689":1480585069138,"1021453974249":1478686804029,"1022645662691":1480585069138,"1022645662692":1480585069138,"1022645662693":1480585069138,"1009845434100":1509788625017,"1022645662694":1480585069138,"1022193735419":1478686417280,"1022645662696":1480585069138,"1022645662699":1480585069138,"1022645662701":1480585069138,"1022645662702":1480585069138,"1025270013764":1509788624197,"1022645662706":1480585069138,"1020725871001":1509788624393,"1022645662710":1480585069138,"1022645662711":1480585069138,"1022645662716":1480585069138,"1023032449263":1509788624196,"1023032449260":1509788624196,"1022645662719":1480585069138,"1022645662470":1480585069137,"1022645662473":1480585069137,"1022645662476":1480585069137,"757089455":1444487341716,"1022645662479":1480585069137,"1022645662480":1480585069137,"1022645662481":1480585069137,"1022014037425":1478686417160,"1025907275170":1509788667456,"1021231804263":1478686417003,"1022468187792":1478686417218,"1023032449078":1509788625103,"1022645662505":1480585069137,"1022645662506":1480585069137,"1025373819990":1509788624306,"1022645662518":1480585069137,"1022014037407":1478686417160,"1025296748838":1509788624871,"1021781118902":1478686804065,"1022645662525":1480585069137,"1023032449071":1509788625103,"1022241303418":1478686417014,"1021453974091":1478686804065,"1022645662528":1480585069137,"1022645662529":1480585069137,"1022645662530":1480585069138,"1025703459229":1509788624308,"1022645662532":1480585069138,"1022645662533":1480585069138,"1022645662535":1480585069138,"1022645662536":1480585069138,"1024886884642":1509788624460,"1001380925396":1478686804051,"1022645662537":1480585069138,"1022645662538":1480585069138,"1001380925395":1478686804051,"1022645662542":1480585069138,"4960177769":1509788624165,"1001380925389":1478686804051,"1022645662545":1480585069138,"1001380925391":1478686804051,"1001380925385":1478686804051,"1022645662548":1480585069138,"1022478022985":1478943089487,"1022645662551":1480585069138,"1022645662554":1480585069138,"1019286928139":1509788625077,"1021418322036":1509788624399,"1021946534351":1478686417144,"1021946534350":1478686417144,"1021874832758":1478686417136,"1025533718423":1509788624348,"1025533718416":1509788624348,"1015536819127":1478686804033,"1020591535847":1478686417027,"1022270663949":1509788624938,"1022339473724":1478686417202,"1024641399693":1509788624520,"1021834461434":1478686416973,"1022645661827":1480585069136,"1022645661828":1480585069136,"1022093988711":1478686417274,"1022645661832":1480585069136,"1022645661835":1480585069136,"1021834461417":1478686416973,"1021251071411":1478686417100,"1022645661840":1480585069136,"1021933820671":1478686804065,"1022645661843":1480585069136,"1022645661845":1480585069136,"1024953995004":1509788624254,"1022245496930":1478686417195,"1022645661848":1480585069136,"1022645661851":1480585069136,"1022645661855":1480585069136,"1022645661856":1480585069136,"1022645661857":1480585069136,"1022645661858":1480585069136,"1022645661859":1480585069136,"1021763161874":1509788624395,"1024154541700":1509788667658,"1022245759040":1478686417195,"757090074":1444487341731,"1022645661882":1480585069136,"1022645661883":1480585069136,"1022645661887":1480585069136,"1022645661888":1480585069137,"1023829871531":1509788667494,"1023829871529":1509788667494,"1022645661892":1480585069137,"1022645661895":1480585069137,"1025561895657":1509788624344,"1020898367725":1478686417032,"1022645661898":1480585069137,"1021953219470":1478686417146,"1022645661899":1480585069137,"1022645661901":1480585069137,"1023829871527":1509788667494,"1022645661902":1480585069137,"1021915202631":1509788624997,"1022645661904":1480585069137,"1022645661907":1480585069137,"1022645661909":1480585069137,"1022645661910":1480585069137,"1022645661912":1480585069137,"1021334169334":1478686416983,"1022645661913":1480585069137,"1021334169333":1478686416983,"1023829871536":1509788667494,"1022645661915":1480585069137,"1020293997811":1465470268279,"1021334169331":1478686416983,"1022645661917":1480585069137,"1022645661919":1480585069137,"1023924636711":1509788624961,"1021453580773":1478686417107,"1021453580768":1478686417107,"1022465172783":1478686417303,"1007023955401":1478686804033,"1023044245680":1509788625047,"1020294259908":1465470268300,"1022457046440":1478686417298,"1019233314203":1509788625077,"1022645661950":1480585069137,"1022645661951":1480585069137,"1021062207074":1478686417232,"1022645661701":1480585069136,"1024743767316":1509788624958,"1024002752827":1491634246532,"1024002752823":1491634246530,"1022645661708":1480585069136,"1022238812237":1509788624947,"1019672920925":1478686804051,"1022238812238":1509788624933,"1022645661711":1480585069136,"1024002752819":1491634246532,"1022645661715":1480585069136,"1022645661717":1480585069136,"1022700713933":1509788624973,"1022645661719":1480585069136,"1004353008234":1444487341756,"1022645661721":1480585069136,"1018573245950":1480585069072,"1022645661750":1480585069136,"1022645661752":1480585069136,"1022645661753":1480585069136,"1022645661756":1480585069136,"1022645661759":1480585069136,"1022645661762":1480585069136,"1022645661765":1480585069136,"1022645661768":1480585069136,"1021208342244":1478686804027,"1022645661771":1480585069136,"228222795":1444487341728,"1022645661778":1480585069136,"1022645661782":1480585069136,"1022645661785":1480585069136,"4967121608":1509788624164,"1022645661786":1480585069136,"1022645661791":1480585069136,"4990059407":1509788624164,"1022645661793":1480585069136,"1022645661794":1480585069136,"1022645661795":1480585069136,"1022241302622":1478686417014,"1022645661797":1480585069136,"1023926865095":1491634246528,"1022645661799":1480585069136,"1021234424916":1478686417039,"1024782562253":1509788625021,"1016399318018":1480585069070,"1024370207526":1509788624926,"1022645661814":1480585069136,"1022645661815":1480585069136,"1022645661817":1480585069136,"1022645661818":1480585069136,"1019449324029":1509788624286,"1021219221374":1465470268196,"1022645661823":1480585069136,"1021626857048":1478686417247,"1024615441468":1509788624810,"1024154542004":1509788667659,"1021626857044":1478686417247,"1022303825390":1478686417199,"1021626857046":1478686417247,"1014730860880":1465470268256,"1021355533941":1478686417006,"1018513477599":1509788624262,"1021660542026":1478686417050,"1018513477596":1509788624263,"1018513477594":1509788624263,"1018513477592":1509788624263,"1018513477591":1509788624263,"1018513477589":1509788624263,"1021462231058":1509788624405,"1018513477587":1509788624263,"1016092489754":1509788624941,"1018513477612":1509788624262,"1022317718825":1509788624938,"1018513477609":1509788624262,"1018513477607":1509788624262,"1018513477606":1509788624262,"1018513477603":1509788624262,"1025192417784":1509788667497,"1019409609292":1509788624312,"1022317718819":1509788625019,"1018513477629":1509788624263,"1018513477627":1509788624263,"1022005125015":1478686417266,"1018513477621":1509788624262,"795755566":1491634246535,"1023821482792":1491634246536,"1023821482785":1491634246536,"4937501981":1509788624163,"1022217579344":1478686417192,"795755570":1491634246508,"1021619648204":1478686417117,"4990059014":1509788624164,"1025881452744":1509788667467,"1016937360818":1478686804022,"1022000535672":1478686416972,"795755545":1491634246508,"1016870381988":1478686804025,"1022645661952":1480585069137,"1013113456940":1465470268252,"1022645661956":1480585069137,"1021286720005":1478686417040,"1022645661962":1480585069137,"1022645661964":1480585069137,"1022645661965":1480585069137,"1023995937161":1509788667538,"1022645661966":1480585069137,"1021918479476":1478686417141,"1022645661969":1480585069137,"1022645661970":1480585069137,"1020814214714":1478686417225,"1022645661971":1480585069137,"1022645661972":1480585069137,"1022645661973":1480585069137,"1022645661974":1480585069137,"1022645661976":1480585069137,"1018334966281":1478686804022,"1022645661978":1480585069137,"1022645661980":1480585069137,"1022645661982":1480585069137,"1022645661983":1480585069137,"1022011547629":1478686417057,"4894771303":1509788624163,"4990059202":1509788624163,"1022233832098":1478686417065,"1020957875853":1478686417000,"1020957875854":1478686417000,"1023032449579":1509788624535,"1023032449576":1509788624535,"757090016":1444487341715,"1001797080299":1478686804054,"1020786294966":1478686416997,"4960177251":1509788624163,"1022645662021":1480585069131,"1022645662022":1480585069131,"1022645662024":1480585069131,"1022645662025":1480585069131,"1022645662026":1480585069131,"1022645662027":1480585069131,"1022645662029":1480585069131,"1022645662030":1480585069131,"1022645662031":1480585069131,"1022645662032":1480585069131,"1022645662033":1480585069131,"1022645662034":1480585069131,"1022645662038":1480585069131,"1022645662040":1480585069131,"1021946534900":1478686417144,"1022645662043":1480585069131,"1022645662046":1480585069131,"1020744614444":1509788624321,"1022645662050":1480585069131,"1022645662052":1480585069131,"1020814214720":1478686417226,"1020814214722":1478686417226,"1021789375608":1509788624993,"1024154541893":1509788667659,"1021737865027":1478686417251,"1024663288227":1509788625069,"1016966065397":1478686804049,"1021877452875":1478686417053,"1021877452877":1478686417053,"1021335740604":1478686417103,"1021594220323":1509788625079,"1023617022127":1509788624969,"1018364721079":1509788624172,"1019595589743":1509788624317,"1025637916678":1509788624359,"1019595589742":1509788624313,"1025637916679":1509788624359,"1025406849997":1509788624441,"1025637916676":1509788624359,"1025637916677":1509788624359,"1025406849999":1509788624507,"1025637916675":1509788624359,"1025406849995":1509788624466,"1025406849985":1509788624512,"1020962986751":1478686417033,"1021983497768":1509788624463,"1024595780220":1509788624934,"1024595780221":1509788624934,"1024595780222":1509788624934,"1024595780223":1509788624934,"1022018361819":1478686417161,"1022051785689":1509788625066,"1016719529369":1478686804069,"1016719529371":1478686804069,"1016719529372":1478686804069,"1016719529373":1478686804069,"1016719529374":1478686804069,"1024686356664":1509788624219,"1016719529375":1478686804069,"1024686356662":1509788624219,"1024686356663":1509788624219,"1024686356661":1509788624219,"1024686356659":1509788624219,"1025637916790":1509788624359,"1025757331289":1509788624970,"1025406849983":1509788624511,"1025757331293":1509788624969,"1013075446914":1478686804066,"1573269932":1478686417024,"1021335740611":1478686417103,"1021691464980":1478686417050,"1666191144":1478686417024,"1016719529376":1478686804069,"1016719529377":1478686804069,"1021334692061":1478686417103,"1016719529378":1478686804069,"1016719529379":1478686804069,"1018546113145":1478686804017,"1017402527113":1478686804035,"1022234488214":1478686417282,"1021277283479":1478686417101,"1020293997064":1465470268279,"1018364720897":1509788624172,"1025637916812":1509788624359,"1025637916813":1509788624359,"1025637916811":1509788624359,"1020419570173":1478686804028,"1023756480760":1509788624945,"1021763291528":1478686417127,"795755481":1491634246508,"1025628610668":1509788624186,"1021763291527":1478686417127,"1025628610665":1509788624200,"1025628610666":1509788624203,"1025628610667":1509788624197,"1022940954662":1509788625052,"1024727775906":1509788624170,"1024595780224":1509788624934,"1022485363915":1478943089536,"1022447477436":1478686804071,"1022447477437":1478686804071,"1017402527190":1478686804035,"1018517801049":1480585069070,"1017402527188":1478686804035,"1022050343628":1478686417172,"1017402527189":1478686804035,"1017402527186":1478686804035,"1017402527187":1478686804035,"1022050343625":1478686417172,"1017402527184":1478686804035,"1017402527185":1478686804035,"1022050343622":1478686417172,"1020744615187":1509788624321,"1022104213027":1478686417182,"1021528554463":1509788624397,"1021151325512":1509788624960,"1020741731554":1478686417075,"1022026356847":1478686417011,"1022339474887":1478686417202,"1012226375809":1478686416994,"1021740878204":1478686417125,"1025007995589":1509788625007,"1019309473376":1509788624315,"1022026356851":1478686417011,"1022026356853":1478686417011,"1018054075659":1491634246514,"1025908191520":1509788667452,"1025593747448":1509788624437,"1024686356942":1509788624442,"1025593747449":1509788624437,"1024686356943":1509788624442,"1024045350912":1509788624378,"1024686356940":1509788624442,"1024045350913":1509788624378,"1024686356941":1509788624442,"1024045350918":1509788624377,"1024045350919":1509788624377,"1024045350916":1509788624378,"1024686356936":1509788624442,"1024045350917":1509788624377,"1024045350922":1509788624377,"757088281":1444487341730,"1024045350923":1509788624377,"1024045350920":1509788624377,"1024045350921":1509788624377,"1023556074849":1509788624382,"1024045350924":1509788624377,"1023556074850":1509788624382,"1024045350925":1509788624377,"1025593747447":1509788624437,"1024086121957":1509788624518,"1025524411304":1509788624418,"1019771486902":1509788624315,"1019771486901":1509788624317,"1025524411303":1509788624418,"1025524411301":1509788624418,"424178712":1444487341732,"1363688476":1491634246520,"1023431812336":1509788624521,"1025606199122":1509788624364,"1021242157937":1478686417100,"1019825233892":1509788624302,"1025606199121":1509788624363,"1010755057671":1444487341761,"1022701236274":1509788624525,"1025879488163":1509788667912,"1025879488164":1509788667917,"616581541":1478950494912,"1025879488166":1509788667892,"1021832627325":1478686417256,"1025524411264":1509788624418,"1023556074800":1509788624382,"1025056753572":1509788625007,"1025637917014":1509788624359,"1023556074796":1509788624382,"1023556074797":1509788624382,"1025637917012":1509788624359,"1023556074798":1509788624382,"1025637917013":1509788624359,"1023556074799":1509788624382,"1025637917010":1509788624359,"1023556074792":1509788624382,"1025637917011":1509788624359,"1023556074793":1509788624382,"1025524411295":1509788624418,"1023556074794":1509788624382,"1025524411292":1509788624418,"1023121709910":1509788625046,"1025637917009":1509788624359,"1023556074795":1509788624382,"1022479858970":1478943089488,"1022701236264":1509788624525,"1017402526844":1478686804056,"1022701236266":1509788624525,"1017402526845":1478686804056,"1022701236267":1509788624525,"1022701236268":1509788624525,"1022701236269":1509788624525,"1020858253943":1478686416983,"1022701236270":1509788624525,"1022701236271":1509788624525,"1021976027114":1478686417150,"5001725858":1509788667398,"1022216531388":1478686416973,"1021948632449":1509788624389,"1025524411259":1509788624418,"1021738387747":1478686417252,"1025524411250":1509788624418,"1025524411252":1509788624418,"1022412874239":1478686417070,"1209673145":1444487341707,"1020709489229":1509788624934,"1023460255679":1509788624311,"1022092547114":1478686417061,"1020264636885":1509788624960,"1020419569896":1478686804028,"1024567206308":1509788667496,"1021453975092":1478686804050,"1025593747210":1509788625022,"1024686356794":1509788624853,"1020962986761":1478686417034,"1024686356792":1509788624853,"1023617022332":1509788624969,"1020962986760":1478686417034,"1020962986759":1478686417033,"1024686356790":1509788624853,"1024686356791":1509788624853,"1024686356787":1509788624853,"1022466089625":1509788625079,"4937501597":1509788624163,"1021933821195":1478686804047,"1017402526958":1478686804056,"1017402526959":1478686804056,"1024552788249":1509788624185,"1018364720730":1509788624172,"1021770107691":1478686417009,"1020854846117":1478686417078,"1022438302466":1478686417071,"1022079571549":1478686417178,"1000531073700":1478686804054,"1016719529944":1478686804069,"1016719529945":1478686804070,"1022645662849":1480585069139,"1022645662852":1480585069139,"1022645662853":1480585069139,"1022645662854":1480585069139,"1022645662855":1480585069139,"1022645662858":1480585069139,"1016719529941":1478686804069,"1021984284130":1509788624463,"1016719529942":1478686804069,"1016719529943":1478686804069,"1019220074632":1509788624314,"1023204676873":1509788625043,"1000531073677":1478686804054,"1000531073678":1478686804054,"1021358154614":1478686417104,"1000531073679":1478686804054,"1022645662892":1480585069139,"1000531073673":1478686804054,"1025551018329":1509788624343,"1012209336998":1509788625017,"1022645662894":1480585069139,"1000531073675":1478686804054,"1025551018331":1509788624335,"1000531073684":1478686804054,"1000531073680":1478686804054,"1022645662900":1480585069139,"1025608426973":1509788624438,"1025608426974":1509788624438,"1021998046467":1478686417301,"1025608426962":1509788624438,"1021998046466":1478686417301,"1000531073695":1478686804054,"1022645662908":1480585069139,"1000531073690":1478686804054,"1016625683760":1478686804058,"1022645662912":1480585069139,"1016625683761":1478686804058,"1016625683762":1478686804058,"1022645662922":1480585069139,"1022645662928":1480585069139,"1008251088586":1478686804023,"1010000741893":1491634246516,"1022645662931":1480585069139,"1022645662932":1480585069139,"1022645662933":1480585069139,"1022645662936":1480585069139,"1023132981708":1509788625144,"1022645662939":1480585069139,"1022645662941":1480585069139,"1009850806650":1491634246514,"1022346028579":1478686804047,"1016625683759":1478686804058,"1015506935389":1480585069068,"1022645662943":1480585069139,"1022645662945":1480585069139,"1019958662344":1478686804021,"1022645662948":1480585069139,"1022645662950":1480585069139,"1021715057789":1509788624395,"1022398194985":1478686417292,"1001644775469":1444487341702,"1022645662954":1480585069139,"1018517801698":1480585069070,"1023132981754":1509788625168,"1024055967969":1509788624928,"1021665513116":1478686417120,"1020790228300":1478686417077,"1004353009292":1444487341756,"1022645662724":1480585069138,"1022645662725":1480585069138,"1024244586458":1509788624948,"1022645662730":1480585069138,"1022645662731":1480585069138,"1023391312001":1509788624385,"1022365034453":1509788624948,"1025485745609":1509788625136,"1022645662747":1480585069138,"1242571916":1478686804029,"1022645662749":1480585069138,"1022675284547":1480585069070,"1022645662757":1480585069138,"1008956507199":1465470268262,"1022645662763":1480585069138,"1025322440633":1509788624305,"1022645662766":1480585069138,"1022645662774":1480585069138,"1022645662775":1480585069138,"1024205134139":1509788625034,"1022645662778":1480585069138,"1022645662779":1480585069138,"1022645662780":1480585069138,"1022645662781":1480585069138,"1025429253750":1509788624407,"1022254935307":1478686416976,"1022645662785":1480585069138,"1021453974857":1478686804050,"1022645662786":1480585069138,"1021453974856":1478686804050,"1022645662787":1480585069138,"1022011546251":1478686417057,"1022746447450":1509788625017,"1021358154648":1478686417104,"1022645662789":1480585069138,"1022645662790":1480585069138,"1022746447449":1509788625017,"1021358154645":1478686417104,"1022645662792":1480585069138,"1022645662793":1480585069138,"1021655691592":1509788624813,"1021358154647":1478686417104,"1022413660862":1478686417302,"1021453974855":1478686804050,"1018364720510":1509788624172,"1025429253742":1509788624432,"1025429253743":1509788624426,"1022443151465":1478686417295,"1025429253741":1509788624429,"1012562440038":1478686417074,"1022157558621":1478686417278,"1826750980":1478686804029,"1022645662826":1480585069139,"1022645662827":1480585069139,"1022645662828":1480585069139,"1021655298406":1509788624610,"1022645662830":1480585069139,"1022645662833":1480585069139,"1444952274":1444487341733,"1022645662835":1480585069139,"1025523887078":1509788625003,"1021721349452":1478686804047,"1022645662839":1480585069139,"1022645662841":1480585069139,"1021673115234":1509788624544,"1022645662843":1480585069139,"1022645662844":1480585069139,"1022645662845":1480585069139,"1022645662846":1480585069139,"1024752547820":1509788667502,"1022090581684":1478686417062,"1021832496666":1478686417256,"1022645663105":1480585069139,"1024752547821":1509788667502,"1022645663107":1480585069139,"1022645663109":1480585069139,"1022645663110":1480585069139,"1022645663115":1480585069140,"1022645663116":1480585069140,"1022645663117":1480585069140,"1022290717351":1478686417068,"1021334168511":1478686416983,"1018364720313":1509788624172,"1021455023240":1509788624398,"1021832496655":1478686417256,"1024752547828":1509788667502,"1024752547824":1509788667502,"1024287970209":1509788625246,"1001675315019":1478686804029,"1024287970202":1509788624271,"1024287970203":1509788624614,"1022645663148":1480585069131,"1020987889758":1478686417034,"1022645663149":1480585069131,"1022645663150":1480585069131,"1022645663152":1480585069131,"1022645663154":1480585069131,"1022645663158":1480585069131,"4959258798":1509788624163,"1022645663160":1480585069131,"1022645663161":1480585069131,"1022645663162":1480585069132,"1022645663165":1480585069132,"1022645663166":1480585069132,"1022645663169":1480585069132,"1022103688590":1509788624190,"1444952420":1444487341748,"1021993196588":1509788624926,"1021242681719":1478686417236,"1021242681722":1478686417236,"1012189021340":1478686416994,"1025548396739":1509788625020,"1021334168526":1478686416983,"1019915540538":1478686804021,"1021430906245":1478686417106,"1021334168512":1478686416983,"1021430906244":1478686417106,"1024576512538":1509788667501,"1021443620180":1478686417107,"1021452664013":1478686417107,"1024576512536":1509788667501,"1021626331841":1509788624404,"1020972030406":1478686417034,"1021742582767":1478686804039,"1021742582766":1478686804039,"1021742582765":1478686804039,"1022645663002":1480585069139,"1021742582764":1478686804039,"1021742582763":1478686804039,"1021742582762":1478686804039,"1020919995617":1478686417032,"1021742582761":1478686804039,"1022645663006":1480585069139,"1022645663009":1480585069139,"1019294662142":1509788624323,"1022645663010":1480585069139,"1022645663011":1480585069139,"1022645663012":1480585069139,"1022645663014":1480585069139,"1022645663015":1480585069139,"1022460583968":1480585069075,"1022645663017":1480585069139,"1022645663019":1480585069139,"1022645663020":1480585069139,"1022645663021":1480585069139,"1022645663023":1480585069139,"1024710474463":1509788624997,"1022645663029":1480585069139,"1022073542415":1509788624280,"1022324926471":1478686417288,"1022645663033":1480585069139,"1022645663035":1480585069139,"1021554505270":1509788624405,"1022645663043":1480585069139,"1022645663044":1480585069139,"1021757000286":1478686417126,"4954802320":1509788624163,"1022464647303":1509788624318,"1021408493448":1478686417006,"1021363396923":1509788624394,"1021945094051":1478686417055,"1022645663076":1480585069139,"1021125382360":1478686417002,"1022645663077":1480585069139,"1022645663078":1480585069139,"1022645663080":1480585069139,"1022645663081":1480585069139,"1022645663084":1480585069139,"1022645663087":1480585069139,"1022238158138":1478686417065,"1022645663089":1480585069139,"1022645663090":1480585069139,"519991563":1478686417019,"1022645663094":1480585069139,"1021396820201":1478686804040,"1022645663100":1480585069139,"1025902160998":1509788667462,"1024643621226":1509788667496,"1025902160999":1509788667463,"1025902160997":1509788667461,"1022098966835":1509788624530,"1021865663252":1509788624402,"1025902161004":1509788667463,"1025902161003":1509788667457,"1015535895114":1478686804063,"1025902161000":1509788667462,"1025902161001":1509788667456,"1022305007316":1478686417015,"1024661971566":1509788625025,"1025911467492":1509788667450,"134641689":1444487341730,"1025605155336":1509788625126,"1021781775965":1478686417255,"1018283189958":1465470268271,"1025547089911":1509788625018,"1025619049230":1509788625124,"1022058334152":1478686417173,"1023994108521":1491634246518,"1025619049231":1509788625107,"1025619049229":1509788625116,"1002728458239":1478686804059,"1002728458236":1478686804059,"1025619049237":1509788625087,"1002728458233":1478686804059,"1019527041079":1509788624376,"1002728458231":1478686804059,"1022101195086":1478686417012,"1019527041082":1509788624316,"1021352525270":1478686417041,"1021776664107":1478686417128,"1022025434623":1478686417267,"1021208343627":1478686804027,"1021693694261":1478686804054,"1021980869197":1478686417056,"1021693694259":1478686804054,"1020766378741":1478686417028,"1021760673073":1478686417254,"1000359107223":1465470268262,"1011737616602":1478686804024,"1020068294740":1509788625081,"1021206246454":1478686417038,"1021967893148":1478686417149,"1021345053817":1478686804023,"1021789378549":1509788624993,"1021776664113":1478686417128,"1021874838767":1478686417136,"1020622590283":1509788625080,"1021048048478":1478686417093,"1024576781793":1509788624462,"1018451611670":1509788624427,"1022013244639":1478686417266,"1025011668747":1509788624462,"1022444862989":1478686417214,"1017031474105":1478686804019,"1008054486257":1478686804025,"1000931228772":1478686417021,"1021614927038":1478686417116,"1021901839924":1509788624399,"1025513665865":1509788624337,"1024002890607":1491634246532,"1026507567271":1515854751200,"1021876411549":1478686417136,"1021876411550":1478686417136,"1021760279980":1478686417127,"1933050834":1444487341750,"1025528477269":1509788624339,"1022065673777":1478686417012,"1025619049029":1509788624186,"1025619049026":1509788624197,"1025619049024":1509788624200,"1025619049025":1509788624204,"1021517145802":1509788624373,"1021668659663":1509788624396,"922895888":1491634246514,"922895895":1491634246514,"1021985325798":1478686417057,"922895896":1491634246514,"922895901":1491634246514,"1013265242779":1509788624353,"1021817559260":1478686416984,"1025192412146":1509788667497,"1021810612588":1478686417256,"1022449712901":1478686417295,"1022087170277":1478686417273,"1021138481496":1478686417002,"922895916":1491634246514,"1019244985955":1509788624316,"1021817559243":1478686416984,"1022346426690":1478686804071,"1021566692294":1509788624405,"1025619049086":1509788624540,"1025619049087":1509788624542,"1021655297712":1478686417008,"1022098049049":1478686417275,"1025007474405":1509788624978,"1022383782772":1478686417290,"922895947":1491634246514,"1021925039837":1478686417054,"1022198320739":1509788624959,"1022198320741":1509788624926,"1021925039833":1478686417054,"1025911467190":1509788667450,"1018513479071":1509788624263,"1000850749152":1478686417024,"1018513479068":1509788624263,"1012108285927":1478686417223,"1018513479063":1509788624263,"1412310385":1478686804029,"1020893249653":1478686417227,"1022431099945":1480585069095,"1023994370904":1491634246518,"1021475726642":1478686417109,"1006883577711":1478686804028,"1018513478990":1509788624263,"1018513478987":1509788624263,"1021750449274":1509788624395,"1018513478981":1509788624263,"1023152114170":1509788667538,"1018513478977":1509788624263,"1024161744306":1509788667562,"1021980869559":1478686417010,"1022293603337":1478686417198,"1018513479001":1509788624263,"1018513478998":1509788624263,"1022293603334":1478686417198,"1018513478997":1509788624263,"1025513796631":1509788624435,"1022293603328":1478686417198,"1018513478994":1509788624263,"1018513479021":1509788624263,"1025629142280":1509788624844,"1018513479016":1509788624263,"1018513479012":1509788624263,"1022182723468":1478686417187,"1021789378101":1509788624993,"1018513479025":1509788624263,"1018513479024":1509788624263,"1022002496821":1478686804049,"1022002496820":1478686804049,"1022002496822":1478686804049,"1018702618182":1509788624427,"1025619049093":1509788624523,"1022002496817":1478686804048,"1022002496816":1478686804048,"1022002496819":1478686804048,"1025619049088":1509788624537,"1022038542106":1478686417011,"1025900326222":1509788667462,"4966603207":1509788624164,"1024612957840":1509788624389,"1025900326226":1509788667463,"1025900326225":1509788667465,"1022238814999":1509788624947,"1022002496815":1478686804048,"1019137767534":1509788625016,"4997142587":1509788667398,"166492175":1444487341729,"5001731012":1509788667398,"1022437785357":1478686417071,"1022437785358":1478686417071,"1021059844841":1478686804043,"1023924639657":1509788624961,"1022437785364":1478686417071,"1025772004830":1509788624228,"1022437785363":1478686417071,"1021904854867":1478686417259,"1021904854864":1478686417259,"1022988016693":1509788624533,"1008744574764":1478686804030,"1021297604836":1478686417102,"1021473498708":1509788624816,"1022988016662":1509788624816,"1022988016655":1509788624194,"570708027":1478686804051,"1020743048106":1478686416996,"1022368447299":1478686417069,"1025589820225":1509788624352,"1024383185752":1509788624281,"1020506728530":1478686804039,"1006884625855":1478686804046,"1024863038511":1509788624342,"4966603349":1509788624164,"1024383185743":1509788624169,"1016937362620":1478686804022,"1021463535990":1478686417108,"1022346033688":1478686804066,"1022346033689":1478686804066,"1022346033690":1478686804067,"1022346033691":1478686804067,"1010025388126":1491634246527,"1021976412390":1509788625197,"1021976412387":1509788625197,"1022392432944":1478686417070,"1021976412399":1509788625197,"1021976412395":1509788625197,"4997143382":1509788667398,"1021976412406":1509788625197,"1021976412404":1509788625197,"1021976412403":1509788625197,"1021976412402":1509788625197,"4894773591":1509788624164,"1022087301969":1478686417062,"1021976412413":1509788625198,"1021976412410":1509788625198,"1021976412408":1509788625198,"1021504955453":1478686804035,"1021504955452":1478686804035,"1021504955455":1478686804035,"1021504955454":1478686804035,"1021504955449":1478686804035,"1021504955451":1478686804035,"1021504955450":1478686804035,"1022988016784":1509788624419,"1021976412366":1509788625198,"1022227149624":1478686417192,"1021976412365":1509788625198,"1022227149625":1478686417192,"1021976412364":1509788625198,"1021976412361":1509788625197,"1024462877951":1509788624990,"1021976412375":1509788625197,"1021940761141":1478686417143,"1021976412373":1509788625197,"1021976412372":1509788625197,"1021976412368":1509788625197,"1021976412382":1509788625197,"1021976412379":1509788625197,"1021477168869":1478686417045,"1019449321922":1509788624353,"1229470595":1444487341716,"1021477168872":1478686417045,"1004334392519":1444487341756,"1021504955465":1478686804035,"1021504955464":1478686804035,"1021504955466":1478686804035,"1021504955463":1478686804035,"1023419890337":1509788625084,"1020878308121":1509788624933,"1020878308115":1509788624933,"1022293079917":1478686417198,"1022335546870":1478686417201,"1022087301926":1478686417062,"1020878308117":1509788624934,"1021634194470":1478686417008,"1020878308116":1509788624933,"1019186527838":1509788624314,"1022433853397":1478686417294,"1014152188469":1465470268319,"5001730271":1509788667398,"1021953344198":1509788624607,"1024294391643":1509788625032,"1021953344197":1509788624607,"1021953344195":1509788624607,"1021953344194":1509788624607,"1021953344193":1509788624607,"1021953344192":1509788624607,"1021953344207":1509788624608,"1021953344206":1509788624608,"1021037169001":1478686417092,"1016396437013":1478686804017,"1021953344201":1509788624607,"1021953344200":1509788624607,"1025585756757":1509788624351,"1021953344208":1509788624607,"1023431817916":1509788624521,"1021353967293":1465469681398,"1022478017465":1478943089487,"1024115999191":1509788667890,"1021432472001":1478686804064,"1021432472000":1478686804064,"4960179348":1509788624164,"1521232281":1478686804033,"4966603582":1509788624165,"1020257697741":1465470268311,"1021432471999":1478686804064,"1021976412457":1509788625144,"1000458722372":1491634246511,"1025721541241":1509788624186,"5001730425":1509788667398,"1025721541238":1509788624203,"1025721541239":1509788624197,"1023152114477":1509788667538,"1025721541237":1509788624200,"1002728457422":1478686804059,"1002728457421":1478686804059,"1025385614898":1509788624408,"1002728457420":1478686804059,"1025385614899":1509788624408,"1002728457419":1478686804059,"1025385614901":1509788624408,"1002728457417":1478686804059,"1025385614902":1509788624408,"1002728457415":1478686804059,"1002728457413":1478686804059,"1002728457411":1478686804059,"1002728457410":1478686804059,"1021953344181":1509788624607,"1023820567532":1491634246535,"1021953344191":1509788624607,"1021953344190":1509788624607,"1021953344189":1509788624607,"1021953344188":1509788624608,"1025385614892":1509788624409,"1021953344187":1509788624608,"1021897121344":1478686417258,"1025385614893":1509788624409,"1021953344186":1509788624608,"1021897121347":1478686417259,"1021953344184":1509788624608,"1021655297035":1478686417008,"1019974649939":1509788624311,"549344049":1478686417019,"1007430073575":1478686804025,"1025806476712":1509788667447,"5001730492":1509788667398,"1014765205451":1478686804024,"1023924639204":1509788624961,"1025033034742":1509788624612,"1021226038931":1478686417099,"1025033034746":1509788624612,"1018923470797":1509788624301,"1020560600436":1478686417026,"1023931978827":1491634246530,"1021332602631":1478686417103,"1021200086888":1465470268193,"1025784456879":1509788624349,"1020462689122":1465470268260,"1025148771503":1509788667843,"1025251395250":1509788625007,"1291075359":1478686417024,"1022016784365":1509788625067,"560616083":1491634246514,"1022121642021":1478686417183,"1025373817316":1509788624305,"1025796383445":1509788624275,"1025033034839":1509788624916,"1012117197325":1478686417025,"1025796383441":1509788624275,"1025796383454":1509788624275,"1021057748777":1478686417093,"1025033034840":1509788624916,"1025796383449":1509788624274,"1021790557076":1509788624403,"1025033034843":1509788624835,"1025796383428":1509788624274,"1025796383429":1509788624275,"1022930739093":1509788625052,"1021905771168":1478686417259,"1021905771172":1478686417259,"1025796383435":1509788624275,"1025796383479":1509788624274,"1025796383472":1509788624274,"1025796383484":1509788624275,"1025796383485":1509788624275,"1025796383480":1509788624275,"1025796383481":1509788624274,"1025796383482":1509788624275,"1025033034875":1509788624868,"1025796383462":1509788624274,"1025033034848":1509788624825,"1025796383458":1509788624274,"1025796383459":1509788624274,"1025796383469":1509788624274,"4997144032":1509788667395,"1025033034857":1509788624835,"1022389813246":1478686417290,"1025796383466":1509788624274,"1025796383383":1509788624274,"1025796383376":1509788624274,"1025331482158":1509788624871,"1021032058600":1478686417035,"1025796383377":1509788624274,"1025796383389":1509788624274,"1025796383391":1509788624274,"1024573503987":1509788667472,"1025033034777":1509788624543,"1025796383387":1509788624274,"1025033034779":1509788624543,"1025796383364":1509788624274,"1023251335734":1509788625083,"1025033034757":1509788624552,"1023251335735":1509788625083,"1025796383361":1509788624274,"1025033034753":1509788624552,"1025033034764":1509788624543,"1025796383373":1509788624274,"1021848886852":1509788624993,"1025796383374":1509788624274,"1022436604237":1478686417213,"1025796383368":1509788624274,"1023251335738":1509788625083,"1187656340":1491634246519,"1023251335736":1509788625083,"1025033034763":1509788624538,"1023251335737":1509788625083,"1025033034801":1509788624536,"1025033034802":1509788624538,"1021842202112":1478686417053,"1013122766416":1478686804066,"1024782429517":1509788625019,"1024771026331":1509788667537,"1022850257445":1509788625074,"1025796383397":1509788624274,"1025796383398":1509788624274,"1025033034790":1509788624566,"1022346034184":1478686804067,"1025368180782":1509788624917,"1025796383393":1509788624274,"1022346034181":1478686804067,"1025033034797":1509788624548,"1025033034798":1509788624544,"1021746253892":1478686417126,"1022346034183":1478686804067,"1025796383400":1509788624274,"1025033034792":1509788624548,"1025796383401":1509788624274,"1025368180775":1509788624513,"1025796383402":1509788624274,"1025368180773":1509788624178,"1025033034795":1509788624566,"1025033034962":1509788624198,"1008993212623":1478686804030,"4966603906":1509788624165,"1025721410976":1509788624406,"1025033034970":1509788624205,"1323842168":1478950494922,"1025033034948":1509788624270,"1025033034951":1509788624205,"1025033034947":1509788624270,"1025373817203":1509788624307,"1025528869438":1509788624338,"1025033034957":1509788624215,"1025528869436":1509788624335,"1025528869437":1509788624339,"1025026481187":1509788624959,"1025796383349":1509788624274,"1023734722327":1509788624969,"1025910810951":1509788667579,"1025033034995":1509788624210,"1024117048939":1509788624325,"1025033035005":1509788624210,"1025796383358":1509788624274,"1021088549341":1478686416988,"1025796383354":1509788624274,"1025721410972":1509788624431,"1020509220682":1465470268322,"1019449323446":1509788624353,"1022282592401":1478686417286,"1025721410970":1509788624428,"1025721410971":1509788624425,"1021721351943":1478686804027,"1025033034986":1509788624205,"1022005117038":1478686417266,"1018513477635":1509788624263,"1024381875656":1509788624301,"1025033034886":1509788624822,"5001731833":1509788667396,"1021754118526":1478686417126,"4985871862":1509788624160,"1022431099280":1480585069095,"1025619050396":1509788624425,"1025619050397":1509788624406,"1025619050394":1509788624428,"1025619050395":1509788624431,"1021261427679":1478686416985,"1025406847757":1509788624466,"1025902422150":1509788667459,"1025406847753":1509788624512,"1025406847755":1509788624466,"1025406847751":1509788624511,"1020856818636":1478686416999,"1023391314685":1509788624368,"1024489356367":1509788624440,"1025406847768":1509788624441,"1022238684727":1509788624947,"1021935649798":1509788624465,"1012968893879":1478686804018,"1022238684729":1509788624931,"1021025373642":1478686417091,"1021256709047":1478686417100,"1025406847762":1509788624466,"1020800063872":1509788624945,"1024087295414":1509788667550,"1022645661574":1480585069135,"1025796383709":1509788624276,"1024087295419":1509788667551,"1022645661578":1480585069135,"1025796383710":1509788624276,"1025796383711":1509788624275,"1025796383704":1509788624275,"1025796383705":1509788624276,"1022645661582":1480585069135,"1025796383707":1509788624276,"1253719976":1444487341708,"1022645661586":1480585069135,"1025033035072":1509788624889,"1021357242458":1478686416989,"1022645661589":1480585069135,"1022645661591":1480585069135,"1009211968586":1478686804058,"1021357242454":1478686416989,"1022645661594":1480585069135,"1022645661597":1480585069135,"1009211968626":1478686804058,"1025796383732":1509788624276,"1009211968627":1478686804058,"1022645661601":1480585069135,"1025033035125":1509788624916,"1009211968625":1478686804058,"1025796383735":1509788624276,"1022645661605":1480585069135,"1025796383729":1509788624276,"1025033035121":1509788624916,"1009211968628":1478686804058,"1025796383730":1509788624275,"1008317280681":1478686804023,"1025796383741":1509788624275,"1025033035133":1509788624835,"1022645661612":1480585069135,"1025796383737":1509788624276,"1025796383716":1509788624275,"1022645661617":1480585069135,"1025796383717":1509788624275,"1022645661618":1480585069135,"1022645661619":1480585069135,"1022645661621":1480585069135,"1025796383713":1509788624276,"1022645661623":1480585069136,"1025796383715":1509788624275,"1018245833204":1509788625079,"1022645661624":1480585069136,"1022645661625":1480585069136,"1025796383725":1509788624275,"1025796383726":1509788624275,"1025796383727":1509788624275,"1009211968623":1478686804058,"1025796383721":1509788624275,"1021789115059":1509788624435,"1022645661631":1480585069136,"1022402395712":1478686417292,"1024087295474":1509788667550,"1025796383638":1509788624275,"1024087295472":1509788667551,"1025796383639":1509788624275,"1022306972566":1509788624923,"1024087295477":1509788667550,"1024087295482":1509788667551,"1025796383645":1509788624275,"1024087295480":1509788667550,"1024087295486":1509788667550,"1024087295484":1509788667550,"4959261398":1509788624164,"1024087295463":1509788667551,"1024087295461":1509788667551,"1025032510726":1509788624276,"1024087295464":1509788667550,"1024087295465":1509788667551,"1024087295469":1509788667550,"1025796383670":1509788624275,"1025796383671":1509788624275,"1024087295446":1509788667550,"1022645661670":1480585069136,"1025796383666":1509788624275,"1022645661671":1480585069136,"1022373953466":1478686417204,"1022645661672":1480585069136,"1025796383676":1509788624275,"1025796383677":1509788624275,"1024087295451":1509788667550,"1022645661675":1480585069136,"1025796383672":1509788624275,"1022645661677":1480585069136,"1025796383673":1509788624275,"1025796383674":1509788624275,"1022645661679":1480585069136,"1024087295453":1509788667551,"1025796383652":1509788624275,"1024087295426":1509788667551,"1022645661682":1480585069136,"1025796383654":1509788624275,"4966604154":1509788624165,"1025796383655":1509788624275,"1025796383648":1509788624275,"1022645661686":1480585069136,"1022645661688":1480585069136,"1025796383661":1509788624275,"1024087295435":1509788667551,"1022645661690":1480585069136,"1025796383662":1509788624275,"1022645661691":1480585069136,"1025796383663":1509788624275,"1024087295438":1509788667551,"1025796383657":1509788624275,"1022645661694":1480585069136,"1025796383658":1509788624275,"1025796383574":1509788624275,"1021519635001":1478686417007,"1019795211745":1509788624391,"1025796383569":1509788624275,"1019795211744":1509788624391,"1025796383570":1509788624275,"1019795211746":1509788624391,"1025796383581":1509788624275,"1023924638671":1509788624961,"1022645661452":1480585069135,"1025796383578":1509788624275,"1022645661455":1480585069135,"1022645661456":1480585069135,"1022645661459":1480585069135,"1025715119129":1509788624341,"1025796383554":1509788624275,"1020649199124":1478686417075,"1022457444943":1480585069111,"1025796383555":1509788624275,"1025796383564":1509788624275,"1025796383560":1509788624275,"1022645661470":1480585069135,"1025796383604":1509788624275,"1025796383606":1509788624275,"1025796383601":1509788624275,"1022645661479":1480585069135,"1025033035251":1509788624835,"1022002495833":1478686804065,"1022645661485":1480585069135,"1024710467779":1509788624997,"1025033035238":1509788624916,"1022645661492":1480585069135,"1021755691066":1478686417051,"1022645661493":1480585069135,"1022645661494":1480585069135,"1025715119162":1509788624439,"1022645661495":1480585069135,"1025796383587":1509788624275,"1025033035245":1509788624916,"1022645661498":1480585069135,"1022645661500":1480585069135,"1025796383593":1509788624275,"1025796383595":1509788624275,"1022645661505":1480585069135,"1022988016635":1509788625101,"1025715119176":1509788624345,"1021848231884":1509788624815,"1022645661513":1480585069135,"1025796383519":1509788624275,"1025715119175":1509788624335,"1025033035167":1509788624842,"1022645661516":1480585069135,"1025033035160":1509788624835,"1025715119170":1509788624346,"1025033035162":1509788624835,"1022645661520":1480585069135,"1025033035140":1509788624824,"1021740618049":1509788624932,"1025033035141":1509788624835,"1022645661522":1480585069135,"1025796383488":1509788624274,"1022457444877":1480585069111,"1022645661526":1480585069135,"1022733740695":1509788624540,"1020438176749":1478686804031,"1022700710020":1509788624973,"1021098117891":1509788624932,"1025098308015":1509788624293,"1021279124983":1509788624941,"5001732034":1509788667395,"1025796383549":1509788624275,"1025796383550":1509788624275,"1021279124988":1509788624941,"1025531491184":1509788624341,"1013122766796":1478686804066,"1025033035180":1509788624584,"1025033035181":1509788624825,"1025796383535":1509788624275,"1025796383530":1509788624275,"1025033035179":1509788624836,"1021279125011":1509788624941,"243824783":1444487341722,"1025628748507":1509788624846,"1021826867009":1478686417133,"1021279125017":1509788624940,"1021199037142":1478686417098,"1021013184473":1478686417231,"1021279125001":1509788624940,"1867651442":1444487341750,"1025513796524":1509788624511,"1021279125044":1509788624940,"1025003016250":1509788625006,"1025003016251":1509788625006,"1023170727793":1509788625072,"1025003016248":1509788625006,"1022318768180":1509788624931,"1025003016246":1509788625006,"1022318768181":1509788624931,"1022432410492":1478686417016,"1021208343044":1478686804027,"142769836":1444487341710,"1022318768178":1509788625016,"1022318768179":1509788624933,"1022318768174":1509788624942,"1021953476596":1478686417146,"1000931228409":1478686417021,"1021279125024":1509788624940,"1022400298267":1478686417292,"1025513796528":1509788624510,"1025628748527":1509788624846,"1024207094063":1509788625033,"1021279125077":1509788624940,"1024519240886":1509788667903,"1025033035280":1509788624835,"1021279125074":1509788624940,"1025628748442":1509788624846,"1025033035295":1509788624835,"1021279125082":1509788624940,"1025513796572":1509788624441,"1021279125063":1509788624940,"1018513478302":1509788624263,"1025711581075":1509788624345,"1025033035269":1509788624849,"1025033035271":1509788624849,"1024453570698":1509788625030,"4937502744":1509788624164,"1025033035277":1509788624835,"1021279125070":1509788624940,"1453859059":1478950494923,"1025711581086":1509788624345,"1025033035273":1509788624824,"1025513796562":1509788624451,"1025881320954":1509788667458,"1002728456654":1478686804059,"1002728456652":1478686804059,"1024204079583":1509788667509,"1002728456651":1478686804059,"1002728456650":1478686804059,"1002728456649":1478686804059,"1018513478313":1509788624263,"1025513796587":1509788624435,"1019483007848":1478686804047,"1002728456646":1478686804059,"1018513478307":1509788624263,"1025033035320":1509788624825,"1002728456642":1478686804059,"1018513478306":1509788624263,"1019634258034":1509788624933,"1025710925756":1509788624308,"1025033035303":1509788624835,"1021279125088":1509788624940,"1025033035309":1509788624843,"1020709491089":1509788624934,"1018513478324":1509788624263,"1025033035305":1509788624843,"1021279125098":1509788624941,"1025033035307":1509788624867,"1018513478222":1509788624263,"1025033035477":1509788625239,"1025721411502":1509788624211,"1018513478221":1509788624263,"1020294264872":1465470268300,"1025721411503":1509788624211,"1025033035472":1509788625239,"1018513478216":1509788624263,"1025033035475":1509788625240,"1018513478213":1509788624263,"1025033035486":1509788625239,"1018513478212":1509788624263,"1025033035487":1509788625239,"1025033035480":1509788625239,"1025607646361":1509788624455,"1018513478209":1509788624263,"1025033035483":1509788625239,"1025033035462":1509788625239,"1018513478236":1509788624263,"1018513478235":1509788624263,"1025033035456":1509788625239,"1022282724023":1478686417067,"1018513478233":1509788624263,"1025721411508":1509788624211,"1025033035468":1509788625240,"1025721411509":1509788624211,"1018513478229":1509788624263,"1025033035470":1509788625239,"1025721411504":1509788624211,"1025721411505":1509788624211,"1018513478226":1509788624263,"1025721411506":1509788624211,"1025033035467":1509788625239,"1017770574230":1478686804021,"1023152770798":1509788624227,"1023152770796":1509788624269,"1023152770797":1509788624270,"1024087295491":1509788667550,"1023152770804":1509788624227,"1024087295493":1509788667551,"1024087295498":1509788667551,"1023152770815":1509788624215,"1024087295499":1509788667551,"1024087295497":1509788667551,"1024087295502":1509788667551,"1024087295503":1509788667551,"1024087295501":1509788667551,"1025033035413":1509788625239,"1023329580313":1509788625040,"1025033035410":1509788625239,"4959261015":1509788624164,"1025033035419":1509788625239,"1021774565567":1509788624419,"1025772004089":1509788624211,"1025772004091":1509788624211,"1020469243532":1509788625077,"1025033035395":1509788625239,"1025033035407":1509788625240,"1024204079463":1509788667509,"1025033035401":1509788625240,"1025772004087":1509788624211,"1025033035445":1509788625239,"1021387127138":1478686804067,"1025033035442":1509788625239,"1025902553738":1509788667461,"1025902553739":1509788667459,"1025902553741":1509788667464,"1025033035451":1509788625239,"1025902553743":1509788667459,"1025033035428":1509788625240,"1008351621227":1478686804023,"1831082961":1478686804024,"1025033035437":1509788625239,"1025033035432":1509788625239,"1022065672652":1478686417175,"1018309533719":1478686804056,"396648612":1491634246533,"1018309533718":1478686804056,"1018309533717":1478686804056,"1025629535141":1509788624858,"1021537333173":1509788624397,"1025629535150":1509788624858,"945573719":1444487341747,"1025629535146":1509788624858,"1018309533721":1478686804056,"1025629535144":1509788624858,"1018309533720":1478686804056,"1022780659099":1509788624856,"1025629535145":1509788624858,"1022241174956":1509788624939,"1019355341231":1465470268236,"1024087295904":1509788667550,"1025033035585":1509788624210,"1025033035586":1509788624206,"1025033035587":1509788624197,"245266822":1478950494907,"5001731385":1509788667398,"1015931796914":1478686804025,"1024087295891":1509788667550,"1017970717696":1509788624372,"1024087295895":1509788667550,"1024087295893":1509788667550,"1023939973203":1509788667538,"1024087295899":1509788667550,"1024087295896":1509788667550,"1022780659108":1509788624856,"1021181736176":1465470268188,"1024087295872":1509788667550,"1024087295873":1509788667550,"1022780659106":1509788624856,"1022780659107":1509788624856,"1024087295882":1509788667550,"1021958194852":1478686417056,"1024087295887":1509788667550,"1022780659115":1509788624856,"1025033035542":1509788624215,"1025033035537":1509788624205,"1025033035539":1509788624205,"1021774565672":1509788624814,"1025033035546":1509788624215,"1018105724023":1509788625020,"1022252840123":1478686417196,"1023152770837":1509788624206,"1018923600684":1509788624282,"225737250":1478686804032,"1025033035533":1509788624270,"1025033035534":1509788624270,"1023152770845":1509788624206,"1023152770842":1509788624206,"1023152770854":1509788624424,"1023152770852":1509788625168,"1025033035575":1509788624205,"1024689103799":1509788624451,"1022377098727":1478686417204,"1025067638093":1509788624293,"1025033035582":1509788624229,"1025033035578":1509788624230,"1025033035579":1509788624210,"1023152770857":1509788624230,"1018468521697":1478686804031,"1025033035565":1509788624205,"1012911874518":1478686804062,"1025033035732":1509788624426,"1021848886669":1509788624993,"1025429255974":1509788625126,"1025033035717":1509788624437,"1025429255975":1509788625109,"1025033035719":1509788624454,"1025628748609":1509788624846,"1025429255973":1509788625117,"1025033035712":1509788624456,"1025033035724":1509788624437,"1025033035727":1509788624434,"1018546114919":1478686804017,"5001731519":1509788667395,"1025911466599":1509788667450,"1021089073899":1478686417002,"1021089073898":1478686417002,"1022119414876":1478686417183,"1025607646647":1509788624438,"1025619049698":1509788624823,"1022462162998":1478686417217,"1025619049696":1509788624828,"1025619049697":1509788624833,"1022073671443":1478686417012,"1025607646652":1509788624438,"1025619049711":1509788624746,"1025607646654":1509788624438,"1025607646650":1509788624438,"1022418123679":1478686417302,"1025607646651":1509788624438,"1018805502679":1509788624928,"1000931228531":1478686417021,"1022015734704":1509788625067,"1025033035670":1509788624440,"1024087295856":1509788667549,"1025628748561":1509788624846,"1025033035666":1509788624433,"1026507569079":1515854751199,"1024087295861":1509788667550,"1023946395856":1491634246531,"1024087295866":1509788667549,"1024087295867":1509788667549,"1024087295865":1509788667549,"1024087295869":1509788667550,"1022245893540":1478686417195,"1024087295842":1509788667550,"1024087295843":1509788667550,"1021467206415":1478686417045,"1022245893542":1478686417195,"1023946395853":1491634246529,"1024087295847":1509788667550,"1023946395854":1491634246531,"1023946395855":1491634246531,"1020940960743":1478686417033,"1025033035660":1509788624510,"1024087295850":1509788667550,"1025033035663":1509788624433,"1024087295849":1509788667550,"1024087295852":1509788667549,"1025033035659":1509788624511,"1024087295853":1509788667550,"1018309533943":1478686804056,"1018309533942":1478686804056,"1025033035701":1509788624432,"1018309533941":1478686804056,"1019287184719":1509788625079,"1018309533940":1478686804056,"1025373817344":1509788624306,"1023337444514":1509788625072,"1298807437":1478686804054,"1020437520854":1478686804031,"1025033035711":1509788624432,"1024087295838":1509788667550,"1024087295839":1509788667550,"1024087295836":1509788667550,"1018309533944":1478686804056,"1024087295837":1509788667550,"1025033035685":1509788624432,"1020437520843":1478686804031,"1025628748581":1509788624846,"4985872086":1509788624160,"1022108929378":1478686417276,"1025234619472":1509788624948,"1025234619473":1509788624948,"1025234619474":1509788624948,"1025234619475":1509788624948,"1021789380490":1509788624993,"1025234619476":1509788624948,"1025234619477":1509788624959,"1020350622025":1480585069074,"1025234619479":1509788624948,"1024686353655":1509788624533,"1025234619458":1509788624947,"1025234619459":1509788624948,"1025234619461":1509788624948,"1025234619462":1509788624948,"1025234619463":1509788624930,"1025359791296":1509788624319,"1025234619466":1509788624947,"1025234619467":1509788624947,"1025234619468":1509788624948,"1025234619469":1509788624948,"1024232915449":1509788625017,"1021048701901":1478686417093,"1025234619470":1509788624948,"1000309825515":1478686417018,"1025234619471":1509788624948,"1019759564449":1509788624311,"1019721028821":1509788624959,"1021789380538":1509788624993,"1010091972337":1491634246522,"1020996534517":1478686417230,"1025617474372":1509788624367,"1021167975052":1478686417038,"1020654050154":1478686804047,"1022047456879":1478686417171,"1020462686456":1465470268260,"1021911537163":1478686417140,"1021226040688":1478686417235,"1022790359983":1509788624565,"1025771088898":1509788624822,"1025771088897":1509788624832,"1008480204457":1478686804016,"1520313029":1478686804015,"1022064234358":1478686417174,"1018658444405":1509788624389,"1025359791295":1509788624280,"1023074782342":1509788625047,"1021789380601":1509788624993,"1021673117929":1509788624396,"1021173479995":1465470268186,"1020994830491":1480585069070,"1020800455709":1478686417077,"1022457444177":1480585069111,"1022457444179":1480585069111,"1013362755909":1478686804030,"1021028778609":1478686417091,"1022457444170":1480585069111,"1022457444174":1480585069111,"1022457444175":1480585069111,"1022457444162":1480585069111,"1712725645":1444487341733,"1019795212538":1509788624391,"1022047456907":1478686417171,"1022047456906":1478686417171,"1016396438975":1478686804017,"1022047456911":1478686417171,"1025771089150":1509788624203,"1025771089149":1509788624200,"1022047456902":1478686417171,"1025169737911":1509788624393,"1011209078930":1478686804022,"1017650907371":1478686804020,"1020994830426":1480585069070,"1021789380425":1509788624993,"1021668005895":1509788624435,"1025532673704":1509788624340,"1021668005891":1509788625020,"1020786037683":1509788624276,"1024167775502":1509788624420,"1021695531496":1509788624400,"1025026478195":1509788624959,"1001733374925":1478686417023,"1008129196317":1478686804034,"1022457444154":1480585069110,"1022457444156":1480585069110,"1024686353434":1509788624815,"1022457444157":1480585069110,"1022457444158":1480585069111,"1014706354492":1509788624944,"1022457444159":1480585069111,"1020784595865":1478686804046,"886590498":1478686417020,"1020294133673":1465470268292,"1025208928985":1509788624922,"1025208928983":1509788624922,"1025910678763":1509788667459,"1021931197985":1478686417055,"1003954420135":1480585069061,"1291073001":1478686417024,"1020917369511":1478686416976,"1021931197972":1478686417055,"1112161134":1478950494920,"1021733936606":1478686417124,"1016301672844":1480585069066,"1021874836897":1478686417136,"1024686353856":1509788625101,"1022239996902":1478686417194,"1014249708632":1478686804031,"1021903411085":1478686417139,"1021692254247":1509788625084,"1025771089154":1509788624186,"1021113321129":1478686416972,"1025721411658":1509788624228,"1021963307075":1478686417056,"1018468522222":1478686804034,"1024244711464":1509788624948,"1022239996880":1478686417194,"1022239996881":1478686417194,"1020551816397":1478686804047,"1001877159397":1478686804029,"1001877159396":1478686804029,"1023927132086":1491634246530,"1023927132084":1491634246528,"1022213388746":1478686417281,"1001877159406":1478686804029,"1010011492377":1491634246525,"1001877159410":1478686804033,"1010011492380":1491634246525,"1010011492371":1491634246525,"1024263848852":1509788667831,"1010011492375":1491634246525,"225735914":1478686804024,"1021354619956":1465470268233,"1022369099967":1478686417204,"1022153360464":1478686417063,"1022153360458":1478686417063,"1022153360461":1478686417063,"1001877159383":1478686804015,"1022153360460":1478686417063,"1025017568919":1509788625006,"1023152112077":1509788667538,"1021700512587":1478686804046,"1023846914855":1509788625079,"1020790887107":1478686417077,"1023108206388":1509788625046,"1022103683862":1509788625080,"1016952176163":1444487341761,"1019125313961":1509788625079,"1024489484639":1509788624843,"1024453312292":1509788624992,"1024686353686":1509788624194,"1012701114528":1478686804066,"1023205327137":1509788624569,"1007592465372":1478686804023,"993280307":1491634246508,"1018700125604":1465470268241,"1019287185571":1509788625079,"1009456280236":1480585069064,"1025671607339":1509788624921,"1020878310388":1509788624934,"1021574946912":1509788624397,"1020878310376":1509788624934,"1022754970121":1509788624393,"1025671607345":1509788624921,"1025671607356":1509788624921,"1016819664345":1478686804025,"1021941549697":1478686417260,"1025671607358":1509788624921,"1025671607359":1509788624921,"1020878310375":1509788624934,"1020878310374":1509788624934,"662986151":1444487341725,"1022232001291":1478686417193,"1025385613174":1509788624409,"1021953477609":1478686417010,"1025385613177":1509788624408,"1024954392267":1509788625021,"1025385613153":1509788624408,"1018513350396":1509788624499,"1025385613156":1509788624408,"1025385613161":1509788624408,"1021323686157":1465470268211,"1023480444568":1509788625081,"1021340726787":1465470268224,"1022273683172":1480585069094,"1004329151505":1444487341736,"1021789380048":1509788624993,"784487582":1509788625019,"1021767621803":1509788624400,"1021323555116":1478686417005,"1020790231386":1478686417077,"1025910941569":1509788667579,"1025910941570":1509788667579,"1025671607367":1509788624921,"1025671607361":1509788624921,"1025910941573":1509788667579,"1025910941574":1509788667578,"1024653715607":1509788667888,"1021059842413":1478686804045,"1025910941576":1509788667578,"1021059842412":1478686804045,"1025910941577":1509788667578,"1021059842415":1478686804045,"1025910941578":1509788667578,"1021059842414":1478686804045,"1025910941579":1509788667578,"1006876365828":1478686804028,"1021059842409":1478686804045,"1025671607369":1509788624921,"1021059842411":1478686804045,"1021059842410":1478686804045,"1023336790329":1509788625040,"1025435810350":1509788624915,"1022193861904":1478686417280,"1021428017994":1478686804026,"1021840494819":1478686417053,"1020305273987":1478686804026,"1025713416996":1509788624345,"1020762181710":1478686417028,"1022058728722":1475218613699,"1021744946909":1478686417126,"1021098116175":1509788624942,"1021098116174":1509788624940,"1021098116169":1509788624932,"1025771089600":1509788625106,"1019482744722":1509788624312,"1021098116165":1509788624932,"1022079173339":1478686417061,"1021098116160":1509788624930,"1021985458522":1478686417153,"1021985458525":1478686417153,"1012651179246":1478686417074,"1025609740609":1509788624866,"1002277578293":1478686804016,"1021562495881":1509788624865,"1327248807":1480585069060,"1712725201":1444487341729,"1022075765331":1509788624416,"1022346031798":1478686804050,"1021464849966":1478686417045,"1021387126099":1478686804065,"1022252185795":1478686417284,"1025772007152":1509788625166,"1025385613195":1509788624408,"1025385613197":1509788624408,"1022024126288":1478686417163,"1025344586049":1509788624308,"1021098116153":1509788624971,"1021098116152":1509788624971,"1025771089598":1509788625114,"1025771089599":1509788625123,"1021098116151":1509788624970,"1016819664071":1478686804025,"1024107743857":1509788624440,"1023835118254":1491634246536,"1024107743853":1509788624440,"1020744618731":1509788624321,"1025779871473":1509788624305,"1025278921892":1509788624516,"1022736622621":1509788624301,"1021158144539":1478686417097,"1021812183839":1478686417256,"1022654308702":1509788624462,"1021874837468":1478686417257,"1025609740452":1509788624438,"1025609740453":1509788624845,"1025609740454":1509788624438,"1025609740455":1509788624845,"1024195038578":1509788624507,"1025609740450":1509788624438,"1025609740451":1509788624845,"1025609740456":1509788624438,"1021264442282":1478686417237,"1015145570537":1478686804053,"1015145570539":1478686804053,"1022525860033":1509788667503,"1020747895508":1478686417028,"1021013836456":1478686417001,"1021354620647":1465470268233,"1020320740422":1509788625078,"1021385028821":1478686417239,"1021639304677":1478686417049,"1022470288494":1478686417073,"1024313263684":1509788624169,"1021354620648":1465470268233,"1020278142525":1480585069076,"1008824523211":1478686804052,"1022041558275":1478686417058,"1021090907818":1478686417002,"1022041558276":1478686417058,"1008824523215":1478686804052,"1008824523212":1478686804052,"1024741534780":1509788624342,"1008824523201":1478686804052,"1008824523206":1478686804052,"1008824523204":1478686804052,"154694313":1444487341723,"1017113783289":1478686804018,"1019030157734":1509788624935,"1019945288255":1509788624323,"1019945288254":1509788624323,"1021151328792":1509788624934,"1019945288253":1509788624323,"1019945288252":1509788624323,"1021404031788":1478686417240,"1020932050697":1478686417228,"598235161":1478686417019,"1008317284149":1478686804023,"1024185863535":1509788625071,"341733344":1517734758204,"1021821489762":1478686417053,"1022445909419":1478686417016,"1025608429615":1509788624212,"1021821489771":1478686417053,"1022184687059":1480585069083,"4977873785":1509788624165,"1021821489774":1478686417053,"1025608429624":1509788624212,"1023354486675":1509788625071,"1019945288259":1509788624323,"1019945288258":1509788624323,"1025083756792":1509788624178,"1019945288257":1509788624323,"1019945288256":1509788624323,"1000531070844":1478686804059,"1025608429616":1509788624212,"1025608429617":1509788624212,"1025608429618":1509788624212,"1025608429622":1509788624212,"1025323090187":1509788624304,"1021164566824":1478686417234,"1021325914318":1478686417005,"1021164566817":1478686417234,"1021164566822":1478686417234,"1008824523195":1478686804052,"1022271979314":1478686417197,"1008824523198":1478686804052,"1008824523199":1478686804052,"1016689380465":1509788624975,"1025513406027":1509788624344,"1024107743873":1509788624430,"1020278142528":1480585069076,"1024107743879":1509788624430,"1024107743876":1509788624430,"1021369168571":1478686417239,"192313209":1478950494906,"1016172438620":1509788624284,"1021640352326":1509788624200,"1020294263455":1465470268300,"1022046669411":1478686417171,"1022457443300":1480585069110,"1016396437852":1478686804017,"1020891811137":1509788624933,"1019745145133":1509788624316,"1018513479810":1509788624263,"1019745145135":1509788624317,"1018513479808":1509788624263,"1023233114572":1509788624958,"1013075451016":1478686804066,"1022072620252":1478686417060,"1021369168578":1478686417239,"1019291774492":1509788624282,"1018513479759":1509788624263,"1025384169923":1509788624835,"1018513479752":1509788624263,"1021354619167":1465470268233,"1021354619164":1465470268233,"1018513479744":1509788624263,"1444948663":1444487341716,"1025772005567":1509788624549,"1018513479765":1509788624263,"1016819663708":1478686804025,"1001733375935":1478686417023,"1021455806409":1509788624977,"1021048702843":1478686417093,"1018513479806":1509788624263,"1018513479805":1509788624263,"1018513479804":1509788624263,"1021354619169":1465470268233,"1021680590002":1478686804028,"1021789379376":1509788624993,"1021594347412":1509788624817,"1016845876368":1509788624366,"1021428018683":1478686804026,"1844449569":1478950494927,"1018513479708":1509788624263,"1018513479698":1509788624263,"1018513479726":1509788624263,"1021867102217":1509788624394,"1025772005578":1509788624549,"1025772005580":1509788624549,"1025772005581":1509788624549,"1025772005568":1509788624549,"1018513479717":1509788624263,"1025772005570":1509788624549,"1018513479714":1509788624263,"1018513479712":1509788624263,"1018513479740":1509788624263,"1025056757296":1509788624999,"376466059":1491634246507,"1022208671116":1480585069088,"1022238687170":1509788624947,"1022457443033":1480585069087,"1022208671117":1480585069088,"1022457443034":1480585069087,"1022426902665":1478686417211,"1022208671119":1480585069088,"1022208671112":1480585069088,"1022457443038":1480585069087,"1022457443039":1480585069087,"1022208671115":1480585069088,"1022208671108":1480585069088,"1022208671109":1480585069088,"1022208671110":1480585069088,"1022208671111":1480585069088,"1022208671104":1480585069088,"1022208671105":1480585069088,"1022208671106":1480585069088,"134903045":1444487341742,"1022208671107":1480585069088,"1022208671133":1480585069088,"1022689829101":1509788624394,"1022208671128":1480585069088,"1022208671129":1480585069088,"1005988103276":1478686804046,"1022208671130":1480585069088,"1022484049204":1480585069126,"1016819663578":1478686804025,"1020874378539":1478686416999,"1022208671149":1480585069088,"1022208671151":1480585069088,"1022208671145":1480585069088,"1021394858534":1478686417105,"1022208671137":1480585069088,"1022346032466":1478686804050,"1022208671139":1480585069088,"1025608431303":1509788625167,"1022208671165":1480585069088,"1022208671167":1480585069088,"1022208671160":1480585069088,"1022208671162":1480585069088,"1021987163897":1478686417057,"1022208671159":1480585069088,"1022536216125":1509788624392,"1022208671152":1480585069088,"1022208671155":1480585069088,"1020433197856":1478686804028,"1019739639953":1509788624173,"1022956818768":1509788624978,"1022457442973":1480585069110,"1022457442974":1480585069110,"1022457442975":1480585069110,"1461332562":1444487341724,"1022054795915":1478686417173,"1022208671196":1480585069088,"1022208671197":1480585069088,"1022208671199":1480585069088,"1022208671192":1480585069088,"1022154932374":1478686417013,"1022054795917":1478686417173,"1022361367748":1478686417289,"1022457442944":1480585069110,"1022457442946":1480585069110,"1012388121279":1478686416994,"1022788919113":1509788624183,"1022208671212":1480585069088,"1022457443000":1480585069110,"1022208671213":1480585069089,"1022380373778":1478686417205,"1022208671209":1480585069088,"1012412761356":1478686804028,"1022208671211":1480585069088,"1022208671204":1480585069088,"1022208671206":1480585069088,"1022208671207":1480585069088,"1022457442995":1480585069110,"1022208671201":1480585069088,"1022457442998":1480585069110,"1012701115444":1478686804066,"1022457442999":1480585069110,"1022208671228":1480585069089,"1022457442984":1480585069110,"1022208671230":1480585069089,"1022208671231":1480585069089,"1022208671220":1480585069089,"1022457442976":1480585069110,"1022457442977":1480585069110,"1022457442978":1480585069110,"1022457442980":1480585069110,"1022457442981":1480585069110,"1021226039362":1478686417003,"1022457442983":1480585069110,"1020885650670":1509788624940,"1023846522748":1491634246537,"1021131013466":1478686417233,"1024256902916":1509788625032,"1021234559783":1480585069071,"1022457442880":1480585069110,"1022457442881":1480585069110,"1022457442882":1480585069110,"1022457442883":1480585069110,"1022457442884":1480585069110,"1022457442885":1480585069110,"1022457442886":1480585069110,"1022457442936":1480585069110,"1022457442937":1480585069110,"1022457442939":1480585069110,"1022457442940":1480585069110,"1022457442941":1480585069110,"1022457442943":1480585069110,"1024520943485":1509788625028,"1022457442930":1480585069110,"1021755693092":1478686417126,"1021594347161":1509788624419,"1022457442922":1480585069110,"1021440733122":1478686417241,"1024838000711":1509788624948,"1011231887169":1480585069074,"1022457442924":1480585069110,"1022457442925":1480585069110,"1023233114153":1509788624958,"1022457442926":1480585069110,"1022457442927":1480585069110,"1010025387875":1491634246522,"1008970274309":1478686804023,"1022457442840":1480585069110,"1024607973966":1509788667589,"1022457442832":1480585069110,"1022457442833":1480585069110,"1022457442834":1480585069110,"1022457442835":1480585069110,"1022457442836":1480585069110,"1022850521990":1509788625053,"1022457442837":1480585069110,"1022457442838":1480585069110,"1022457442839":1480585069110,"1022073537897":1509788624928,"1022457442826":1480585069110,"1022457442827":1480585069110,"1021718339089":1478686417009,"1022457442828":1480585069110,"1022457442829":1480585069110,"1024453966605":1509788625070,"1021718339090":1478686417009,"1022457442831":1480585069110,"1001733375685":1478686417023,"5001730042":1509788667398,"1022457442873":1480585069110,"1021379130366":1478686804033,"1022457442875":1480585069110,"1022457442877":1480585069110,"1022457442878":1480585069110,"1021874835830":1478686417009,"1022457442879":1480585069110,"1021236788081":1478686417099,"1016819663403":1478686804025,"1022457442868":1480585069110,"1001733375730":1478686417023,"1022457442870":1480585069110,"1021903409965":1478686417139,"1022208671100":1480585069088,"1022208671102":1480585069088,"1022208671098":1480585069087,"1021729087193":1509788624403,"1022208671372":1480585069090,"1022457442776":1480585069109,"1022457442777":1480585069109,"1022457442778":1480585069109,"1022208671375":1480585069090,"1022457442779":1480585069109,"1022457442780":1480585069109,"1022457442781":1480585069109,"1022208671370":1480585069090,"1022457442782":1480585069109,"1022208671371":1480585069090,"1022457442783":1480585069110,"1021432868032":1478686417007,"1022208671365":1480585069090,"1022121641429":1478686417183,"1022208671360":1480585069089,"1022457442772":1480585069109,"1022208671361":1480585069089,"1022457442773":1480585069109,"1022208671362":1480585069089,"1022457442774":1480585069109,"1022208671388":1480585069090,"1023821487736":1491634246536,"1022208671385":1480585069090,"1022208671386":1480585069090,"1022208671387":1480585069090,"1022457442752":1480585069109,"1022208671381":1480585069090,"1022457442753":1480585069109,"1010093936824":1491634246528,"1022898886513":1509788625017,"1022208671382":1480585069090,"1022457442754":1480585069109,"1024161745464":1509788667562,"1022457442755":1480585069109,"1010093936826":1491634246522,"1022457442756":1480585069109,"1006788810685":1478686804029,"1022208671377":1480585069090,"1021997124917":1478686417156,"1022208671378":1480585069090,"1022457442758":1480585069109,"1022267129104":1478686417285,"1022447874154":1480585069107,"1022447874155":1480585069107,"1022447874152":1480585069107,"1022447874153":1480585069107,"1024244582257":1509788624948,"1022447874158":1480585069107,"1022447874159":1480585069107,"1018513480425":1509788625204,"1022447874157":1480585069107,"1018513480422":1509788625204,"1024912056128":1509788624926,"1018513480419":1509788625204,"1024204081552":1509788667509,"1024492238525":1509788667889,"1022447874168":1480585069107,"1503274921":1478950494923,"1022457442784":1480585069110,"1022457442785":1480585069110,"1018513480438":1509788625204,"1022447874160":1480585069107,"1022457442786":1480585069110,"1022447874161":1480585069107,"229274519":1478950494907,"1022447874164":1480585069107,"1022457442712":1480585069109,"1022457442713":1480585069109,"1021048047003":1478686417093,"1020987885879":1478686417034,"1022457442704":1480585069109,"1022457442705":1480585069109,"1017193212886":1465470268268,"1023856221234":1491634246537,"1022457442707":1480585069109,"1022457442710":1480585069109,"1022457442711":1480585069109,"1023856221224":1491634246537,"1022457442697":1480585069109,"1022457442698":1480585069109,"1022457442699":1480585069109,"1022457442700":1480585069109,"1014688136857":1465470268263,"1022457442701":1480585069109,"1022457442702":1480585069109,"1022457442703":1480585069109,"1022457442747":1480585069109,"1022457442748":1480585069109,"1022457442749":1480585069109,"1022457442750":1480585069109,"1022457442751":1480585069109,"1024552792732":1509788624185,"1022349964875":1480585069096,"1022256119220":1478686416990,"1022457442740":1480585069109,"1008280059051":1478686804052,"1022457442741":1480585069109,"1022457442743":1480585069109,"1021597230441":1478686417115,"1022208671244":1480585069089,"1022208671245":1480585069089,"1022208671246":1480585069089,"1022208671247":1480585069089,"1021948628620":1509788624355,"1022282726054":1478686417067,"1022457442654":1480585069109,"1025608430958":1509788625139,"1025608430959":1509788625139,"1022457442632":1480585069109,"1019241443835":1509788624315,"1025902551792":1509788667457,"1022208671261":1480585069089,"1022457442633":1480585069109,"1025902551793":1509788667458,"1022457442634":1480585069109,"1022208671263":1480585069089,"1022457442635":1480585069109,"1025902551795":1509788667464,"1022208671256":1480585069089,"1022457442636":1480585069109,"1025902551796":1509788667459,"1022208671257":1480585069089,"1022208671258":1480585069089,"1022208671259":1480585069089,"1025560852041":1509788624304,"1022208671252":1480585069089,"1022208671253":1480585069089,"1025608430961":1509788625139,"1022208671254":1480585069089,"1022457442626":1480585069109,"1022457442627":1480585069109,"1025608430963":1509788625139,"1022208671248":1480585069089,"1022457442628":1480585069109,"1021225647034":1478686417039,"1022208671249":1480585069089,"1022457442629":1480585069109,"1022208671250":1480585069089,"1022457442630":1480585069109,"1022457442680":1480585069109,"1001733375422":1478686417023,"1022069605970":1509788624943,"1022457442672":1480585069109,"1022193729848":1478686417280,"1016819663212":1478686804025,"1022069605979":1509788624944,"1022457442665":1480585069109,"1022457442666":1480585069109,"1022208671295":1480585069089,"1022457442667":1480585069109,"1022457442670":1480585069109,"1022208671291":1480585069089,"1022457442671":1480585069109,"1022069605965":1509788624944,"1022457442658":1480585069109,"1022457442659":1480585069109,"1022069605966":1509788624943,"1022867429875":1509788625053,"1022457442660":1480585069109,"1022457442661":1480585069109,"1022457442662":1480585069109,"1022457442663":1480585069109,"1022208671309":1480585069089,"1022447874190":1480585069107,"1022447874191":1480585069107,"1022447874188":1480585069107,"1022447874189":1480585069107,"1022069605949":1509788624944,"1022069605950":1509788624944,"1022083761873":1478686417179,"1022083761872":1478686417179,"1022208671299":1480585069089,"1022447874202":1480585069107,"1024115870766":1509788667473,"1022208671326":1480585069089,"1022447874200":1480585069107,"1022399510015":1478686417015,"1022208671320":1480585069089,"1022447874205":1480585069107,"1022447874194":1480585069107,"1016444147452":1478686804023,"1022208671340":1480585069089,"1022457442616":1480585069109,"1022457442617":1480585069109,"1022457442619":1480585069109,"1022208671338":1480585069089,"1022208671339":1480585069089,"1022208671332":1480585069089,"1022447874210":1480585069107,"1022208671333":1480585069089,"1022208671334":1480585069089,"1022447874208":1480585069107,"1024779544475":1509788625024,"1022208671328":1480585069089,"1022208671329":1480585069089,"1022208671330":1480585069089,"1022447874212":1480585069107,"1022208671331":1480585069089,"1022457442615":1480585069109,"4977874500":1509788624164,"1020953152402":1478686417229,"1022873589273":1509788624462,"1021585040678":1478686417114,"886590427":1478686417020,"1020927331327":1478686417082,"1022365693506":1478686417069,"1022619707155":1509788625075,"1016819663072":1478686804025,"1014646325859":1478686804052,"1001733375025":1478686417023,"886590455":1478686417020,"1015658448437":1478686804016,"1023924640107":1509788624961,"192312395":1478950494906,"1020747896573":1478686417028,"938625203":1491634246515,"1022447874318":1480585069105,"1022447874319":1480585069105,"1024686353334":1509788624419,"1025608430752":1509788624550,"1025608430758":1509788624549,"1022447874330":1480585069105,"1015658448456":1478686804017,"1008317283292":1478686804023,"1022447874328":1480585069105,"1022447874329":1480585069105,"1022073538541":1509788624280,"1022447874323":1480585069105,"1022447874320":1480585069105,"1015658448449":1478686804019,"1022447874321":1480585069105,"1022447874326":1480585069105,"1022447874327":1480585069105,"1002452687199":1491634246509,"1021814937446":1509788625014,"1021059843175":1478686804065,"1025508817562":1509788624344,"1021814937444":1509788625013,"1025508817564":1509788624339,"1327116412":1444487341727,"1021814937454":1509788625013,"1022291376853":1478686417286,"1021814937452":1509788625013,"1025508817557":1509788624340,"1021814937449":1509788625014,"1017770575961":1478686804022,"1025508817559":1509788624340,"1024552792960":1509788624185,"1025608430748":1509788624550,"1025608430749":1509788624550,"1021814937458":1509788625013,"1023844949631":1491634246537,"1021814937466":1509788625013,"1021814937479":1509788625013,"1021814937478":1509788625013,"1021814937477":1509788625013,"1021814937476":1509788625013,"1021814937474":1509788625013,"1021814937473":1509788625013,"1001733375126":1478686417023,"1021264443260":1478686417237,"1021814937484":1509788625013,"1021814937481":1509788625013,"1021814937480":1509788625013,"1013075451771":1478686804066,"4977874725":1509788624164,"1022135403386":1478686417184,"1021814937490":1509788625014,"1021814937489":1509788625014,"1020294131978":1465470268292,"1003695427493":1478686417220,"1003695427492":1478686417220,"1021286725156":1478686417004,"1003695427497":1478686417220,"1003695427499":1478686417220,"1003695427498":1478686417220,"1000499744043":1478686804059,"1024926735675":1509788624415,"1022099097220":1509788624416,"1024926735678":1509788624416,"1024926735676":1509788624416,"1021015934495":1478686416988,"1020398726061":1509788624319,"1024926735690":1509788624415,"1018513480463":1509788625204,"1024926735689":1509788624415,"1022490603034":1478943089490,"1020398726059":1509788624282,"1024926735692":1509788624415,"1018513480456":1509788625204,"1024188877134":1509788624490,"1024926735681":1509788624415,"1022098966270":1509788624924,"1024926735687":1509788624415,"1025551022266":1509788624344,"1019237511286":1509788624314,"1024926735704":1509788624415,"1024926735705":1509788624415,"1021963308795":1478686417056,"1019237511283":1509788624314,"1024926735711":1509788624415,"1018513480474":1509788625204,"1021375328653":1478686417104,"1024926735709":1509788624415,"1023233114699":1509788624958,"1024926735698":1509788624415,"1018513480471":1509788625204,"1024926735699":1509788624415,"1024926735696":1509788624415,"1024926735697":1509788624416,"1010295129471":1491634246522,"1024926735702":1509788624416,"1021112008756":1478686417037,"1010295129470":1491634246522,"1024926735703":1509788624415,"1018513480466":1509788625204,"1018513480495":1509788625204,"1012129519767":1509788625082,"1022766505647":1509788624824,"1018513480487":1509788625204,"1024926735712":1509788624415,"1013952965457":1509788625069,"1018513480508":1509788625204,"1018513480505":1509788625204,"1022023862852":1478686417163,"1018513480502":1509788625204,"1020792198370":1478686417077,"1018513480500":1509788625204,"1018513480498":1509788625204,"1000526083305":1444487341712,"1025278883725":1509788624484,"1025278883727":1509788624484,"1024210958160":1509788624266,"1025278883720":1509788624484,"1025278883721":1509788624484,"1025278883722":1509788624484,"1025278883723":1509788624484,"1227016491":1444487341728,"1025278883717":1509788624484,"1025278883718":1509788624484,"1025278883719":1509788624484,"1002494683569":1491634246520,"1000526083303":1444487341715,"1025278883715":1509788624484,"1022721302033":1509788624985,"1022721302030":1509788624984,"1022721302028":1509788624984,"1025715229086":1509788625166,"1022191370145":1478686417279,"1019365348893":1509788624316,"1000526083313":1444487341712,"1019365348894":1509788624312,"1025278883728":1509788624484,"1025278883729":1509788624484,"1022721302019":1509788624985,"1025278883730":1509788624483,"1019365348891":1509788625081,"1025278883731":1509788624484,"1022429138250":1478686417294,"1024760486064":1509788625021,"1024002681751":1491634246532,"1025593854710":1509788624828,"1021874826400":1478686417136,"1025593854711":1509788624746,"1025593854708":1509788624833,"1025593854709":1509788624823,"1022084675621":1509788624289,"1022721302048":1509788624986,"1022721302108":1509788624986,"1020974085741":1478686417229,"1024156431579":1509788667500,"1024404489210":1509788624417,"1021599964320":1478686417115,"1021443986042":1478686417044,"1022957104206":1509788624816,"1022423240106":1480585069071,"1022721302134":1509788624985,"1017473558192":1465470268256,"1022721302117":1509788624985,"1000927169405":1478686417021,"1000237720248":1444487341761,"1024330366646":1509788625007,"1025278883597":1509788624482,"1025278883592":1509788624483,"1024330366643":1509788625007,"1025278883594":1509788624483,"1025278883588":1509788624483,"1024330366654":1509788625007,"1025278883589":1509788624483,"1025278883590":1509788624483,"1025278883591":1509788624483,"1024332463770":1509788624544,"1022043780846":1478686417269,"1024330366651":1509788625007,"1022423240012":1480585069071,"1025278883586":1509788624482,"1025278883612":1509788624482,"1021099523647":1478686417002,"1025278883608":1509788624482,"1025278883609":1509788624482,"1025278883610":1509788624482,"1022721302153":1509788624985,"1025278883605":1509788624482,"1025278883606":1509788624482,"1022721302149":1509788624985,"1021999215511":1478686416991,"1025278883600":1509788624482,"1016301756476":1480585069066,"1016301756477":1480585069066,"1025278883624":1509788624482,"1025278883625":1509788624482,"1025278883620":1509788624483,"1025278883621":1509788624483,"1025278883622":1509788624483,"1025278883623":1509788624482,"1025278883616":1509788624482,"1024950543248":1509788625177,"1025278883619":1509788624483,"1025278883645":1509788624483,"1021701677681":1478686804039,"1020560154228":1478686417224,"1022326507321":1478686417200,"1025278883660":1509788624483,"1025278883661":1509788624483,"1025278883662":1509788624483,"1025278883663":1509788624483,"1025278883656":1509788624483,"1023924430477":1509788624969,"1025278883658":1509788624483,"1025278883659":1509788624483,"1025278883653":1509788624483,"1018498818916":1478686804037,"1021099523687":1478686417002,"1018498818915":1478686804037,"1025278883648":1509788624483,"1018498818914":1478686804037,"1025278883649":1509788624483,"1018498818913":1478686804037,"1025278883650":1509788624483,"1025278883676":1509788624483,"1025278883677":1509788624483,"1025278883678":1509788624483,"1025278883673":1509788624483,"1022423239962":1480585069071,"1025278883668":1509788624483,"1025278883665":1509788624483,"1025278883666":1509788624483,"1024811080590":1509788624311,"1021955436867":1509788624256,"1021099523649":1478686417002,"1025278883686":1509788624483,"1025525302806":1509788625083,"1021939445840":1478686417260,"1025278883687":1509788624483,"1025278883680":1509788624483,"1025278883683":1509788624483,"1021492483503":1509788624398,"1025278883708":1509788624483,"1021787006812":1509788624399,"1002457458436":1491634246518,"1025278883711":1509788624484,"1020795169850":1478686417029,"1025278883705":1509788624484,"1025278883700":1509788624484,"1025278883701":1509788624484,"1025278883702":1509788624484,"1022490087741":1478943089490,"1025278883703":1509788624484,"1025278883697":1509788624483,"1025278883699":1509788624484,"1024287767968":1509788624522,"1016728008793":1478686804017,"1020811685110":1478686417030,"1025278883465":1509788624485,"1024287767973":1509788624522,"1021887016157":1478686804027,"1025278883466":1509788624484,"1025278883467":1509788624485,"1024287767975":1509788624522,"1022721302294":1509788624984,"1025278883462":1509788624484,"1024287767978":1509788624522,"1025278883463":1509788624485,"1024287767981":1509788624522,"1022150606094":1478686417277,"1022721302289":1509788624984,"1022721302286":1509788624984,"1022957104387":1509788624194,"1022737423899":1509788624430,"1025278883487":1509788624484,"1024287767987":1509788624522,"1024287767988":1509788624522,"1025278883481":1509788624484,"1024287767990":1509788624522,"1024287767992":1509788624522,"1024287767994":1509788624522,"1022721302274":1509788624986,"1025278883473":1509788624484,"1024287767999":1509788624522,"1025278883500":1509788624485,"1024287767936":1509788624521,"1021980734208":1478686417151,"1020505103124":1478686804032,"1025278883502":1509788624485,"1025278883503":1509788624485,"1024287767939":1509788624521,"1024330366739":1509788625007,"531275404":1491634246520,"1025278883498":1509788624484,"1012905169942":1478950494940,"1024287767943":1509788624518,"1025278883492":1509788624484,"1025798199184":1509788625113,"1025278883493":1509788624484,"1025798199185":1509788625122,"1025278883494":1509788624484,"1024287767946":1509788624521,"1025798199186":1509788625105,"1025278883495":1509788624484,"1025278883488":1509788624484,"1024287767948":1509788624521,"1025278883489":1509788624484,"1023730834143":1509788624961,"1025100361086":1509788624273,"1025278883490":1509788624484,"1024287767950":1509788624518,"1025798199190":1509788625087,"798797484":1491634246517,"1024287767953":1509788624522,"1022422322370":1478686417293,"1024287767954":1509788624522,"1024287767956":1509788624522,"1000116476488":1478686804029,"1025278883508":1509788624484,"1024287767960":1509788624522,"1022721302310":1509788624983,"1025874615090":1509788667581,"1846079281":1444487341743,"1024287767964":1509788624522,"1022721302306":1509788624983,"1024330366730":1509788625007,"1025278883505":1509788624485,"1022511322044":1480585069126,"1025278883506":1509788624484,"1025874615092":1509788667581,"1025278883507":1509788624484,"1024330366729":1509788625007,"1024490867131":1509788625028,"1025278883533":1509788624481,"1025278883534":1509788624481,"1024423495114":1509788624936,"1022721302364":1509788624986,"1022049941321":1478686417172,"1020068233577":1478686804026,"1025798199283":1509788624540,"1025798199284":1509788624537,"1023924430596":1509788624969,"1025798199285":1509788624542,"1025278883549":1509788624481,"1025278883550":1509788624481,"165447823":1478686417023,"1025278883545":1509788624481,"1025278883546":1509788624481,"1025278883547":1509788624481,"1025890867813":1509788667404,"1025278883540":1509788624481,"1024314899546":1509788625016,"1025278883541":1509788624481,"1025278883543":1509788624481,"1024314899545":1509788625019,"1025278883536":1509788624481,"1025278883538":1509788624481,"1025798592492":1509788625102,"1025278883539":1509788624481,"1025278883565":1509788624481,"1025278883566":1509788624481,"1025278883561":1509788624481,"1025890867799":1509788667404,"1025278883562":1509788624481,"1025278883563":1509788624481,"1024287768007":1509788624522,"1020235877192":1465470268180,"1025278883559":1509788624481,"1025278883552":1509788624481,"1024287768012":1509788624522,"1022721302386":1509788624984,"1025278883554":1509788624481,"1025890867805":1509788667404,"1801775636":1444487341744,"1003975622661":1478686417221,"1022721302382":1509788624984,"1003975622663":1478686417221,"1022171971500":1478686417063,"1022255727277":1478686417066,"1003975622657":1478686417221,"1022721302378":1509788624984,"1003975622656":1478686417221,"1022721302379":1509788624983,"1003975622659":1478686417221,"4947748767":1509788624154,"1022721302376":1509788624984,"1022721302374":1509788624985,"1003975622668":1478686417221,"1022721302375":1509788624984,"1025278883568":1509788624481,"1022721302370":1509788624986,"1003975622664":1478686417221,"1025278883569":1509788624481,"1025890867791":1509788667404,"1022721302368":1509788624986,"1023010058678":1509788625048,"1021706658788":1478686417122,"1003975622666":1478686417221,"1022721302369":1509788624986,"1023961131450":1509788625037,"1025100361175":1509788624173,"1025278883356":1509788624250,"1025278883357":1509788624250,"1020294205241":1465470268296,"1025278883359":1509788624250,"1011684084844":1478686804064,"1025278883344":1509788624250,"1024287767868":1509788624521,"1025171140998":1509788624999,"1016977967568":1465470268267,"1025278883374":1509788624251,"1025278883369":1509788624251,"1025278883365":1509788624251,"1025278883360":1509788624250,"1025278883362":1509788624251,"1021051025952":1478686417036,"1025278883384":1509788624250,"1025406942814":1509788624456,"1025278883380":1509788624250,"1025278883382":1509788624250,"1025278883378":1509788624251,"1021500741474":1478686804031,"1024287767906":1509788624521,"1024287767914":1509788624522,"1020526337341":1465470268322,"1008341107956":1478686804052,"1022957104576":1509788624419,"1025278883420":1509788625198,"1024287767921":1509788624522,"1023999404577":1509788625017,"4985891069":1509788624153,"1025278883422":1509788625199,"1025278883423":1509788625199,"1022041159517":1478686417170,"1024287767926":1509788624522,"1025880513030":1509788667404,"427858008":1478950494910,"1022027527328":1478686417164,"1024287767932":1509788624521,"1022192680540":1509788625083,"1024287767872":1509788624522,"1025278883437":1509788625199,"1025278883438":1509788625199,"1025278883439":1509788625199,"1024287767876":1509788624521,"1025278883432":1509788625199,"1025278883433":1509788625199,"1025278883434":1509788625199,"1022250615787":1478686417066,"1010025802550":1478686804067,"1025278883428":1509788625199,"1025278883429":1509788625198,"1025278883430":1509788625199,"1025278883431":1509788625199,"1024287767884":1509788624521,"1025278883424":1509788625199,"1025278883425":1509788625199,"1021504804717":1478686417047,"1025278883427":1509788625199,"1024287767889":1509788624521,"1025278883448":1509788625198,"1025278883449":1509788625198,"1000527787268":1444487341711,"1021890423921":1478686417138,"1024287767897":1509788624522,"1025278883445":1509788625199,"1025278883446":1509788625199,"1024287767900":1509788624522,"1023924430773":1509788624969,"1025278883441":1509788625199,"1025278883442":1509788625199,"1000927169278":1478686417021,"1020777343488":1478686804039,"1025278883443":1509788625199,"1006848372285":1478686804040,"1025278883213":1509788624890,"1025278883214":1509788624890,"1022464527695":1509788624280,"1025278883215":1509788624890,"1025278883208":1509788624889,"1025278883209":1509788624889,"1025278883210":1509788624889,"1025880512982":1509788667404,"1025278883211":1509788624890,"1022921582599":1509788624298,"1025278883205":1509788624889,"601661910":1444487341750,"1025278883206":1509788624890,"1025278883207":1509788624890,"1025278883200":1509788624889,"1025278883202":1509788624889,"1022127143289":1509788624338,"142772891":1444487341710,"1025278883216":1509788624890,"1020962813136":1478686417033,"1020799757976":1478686417077,"1025091055299":1509788624307,"1025278883217":1509788624889,"1025278883218":1509788624889,"1024687216366":1509788625083,"1022052169212":1478686417172,"1021907070106":1509788624466,"1025880513008":1509788667404,"1025278883245":1509788624249,"1025278883246":1509788624249,"1025278883240":1509788624249,"1025278883241":1509788624249,"1025278883242":1509788624249,"1025278883243":1509788624249,"1021906152606":1478686417139,"1025880513018":1509788667404,"1021762103045":1478686417127,"1025278883263":1509788624249,"1020526337732":1465470268322,"1025278883258":1509788624249,"1022021891988":1478686417162,"1025278883253":1509788624249,"4985891605":1509788624154,"1025278883249":1509788624249,"1025278883250":1509788624249,"1025278883276":1509788624249,"1025278883277":1509788624249,"1019023900705":1480585069072,"1025278883278":1509788624249,"1025278883279":1509788624249,"1025278883274":1509788624249,"1025278883275":1509788624249,"1023956150819":1509788624519,"1025278883270":1509788624249,"1025278883271":1509788624249,"1025278883267":1509788624249,"1009744387020":1491634246512,"1016301626100":1480585069066,"1022098045810":1478686417275,"1020913136031":1478686417080,"1025278883286":1509788624249,"1022073142008":1478686416990,"1025278883280":1509788624249,"1025278883282":1509788624249,"1022193728972":1478686417280,"1025278883308":1509788624250,"1025278883311":1509788624251,"1001016300478":1478686417018,"1025278883325":1509788624251,"1019833675853":1478686804065,"1000927168889":1478686417021,"1025278883317":1509788624251,"1025278883318":1509788624250,"1025278883319":1509788624250,"1025278883312":1509788624251,"1025278883313":1509788624251,"1025278883314":1509788624251,"1025278883315":1509788624251,"1004150345326":1478686804052,"1022468853129":1478686804049,"1004150345323":1478686804052,"1004150345322":1478686804052,"1004150345321":1478686804052,"1004150345320":1478686804052,"1003975623677":1478686417221,"1004150345319":1478686804052,"1003975623676":1478686417221,"1004150345318":1478686804052,"1020742216349":1478686417075,"1004150345317":1478686804052,"1004150345316":1478686804052,"1004150345313":1478686804052,"1003975623674":1478686417221,"1004150345312":1478686804052,"1025214657009":1509788624424,"1025323055225":1509788624304,"1000237719724":1444487341761,"1020776687987":1478686416984,"1021948621462":1509788624390,"1004023989813":1478686417222,"1022080482033":1509788624928,"1004023989823":1478686417222,"1004023989822":1478686417222,"1004023989821":1478686417222,"1004023989820":1478686417222,"1004023989819":1478686417222,"1004023989818":1478686417222,"1025278883132":1509788624584,"1004150345310":1478686804052,"1025278883133":1509788624585,"1004150345309":1478686804051,"1025278883134":1509788624585,"1025278883135":1509788624585,"1004150345306":1478686804051,"1004150345304":1478686804051,"1025278883148":1509788624585,"1025278883149":1509788624585,"1025278883150":1509788624585,"1025278883151":1509788624585,"1025278883144":1509788624584,"1025278883145":1509788624584,"1025278883146":1509788624584,"1025278883141":1509788624584,"1025278883142":1509788624584,"1025278883143":1509788624585,"1025278883137":1509788624585,"1025278883138":1509788624584,"1025278883139":1509788624584,"1004023989831":1478686417222,"1004023989830":1478686417222,"1004023989828":1478686417222,"1004023989826":1478686417222,"1004023989825":1478686417222,"1004023989824":1478686417222,"1004023989839":1478686417222,"1004023989838":1478686417222,"1004023989836":1478686417222,"1004023989835":1478686417222,"1025278883152":1509788624585,"1004023989834":1478686417222,"1025278883153":1509788624584,"1004023989833":1478686417222,"1004023989832":1478686417222,"1025278883155":1509788624584,"1021927517609":1478686417142,"1021980733641":1478686417151,"1021148283695":1478686417037,"1022470557183":1478686804049,"1025278883196":1509788624890,"1015657855985":1478686804017,"1025278883198":1509788624890,"1025278883199":1509788624890,"1025278883193":1509788624890,"1025278883194":1509788624890,"1018883913772":1509788624311,"1025278883195":1509788624890,"1025278883189":1509788624889,"1007806457829":1478686804025,"1024114225690":1509788624606,"1024114225692":1509788624606,"1024114225694":1509788624606,"1014342658156":1465470268319,"1024114225681":1509788624606,"1024114225683":1509788624606,"1024114225685":1509788624606,"1024735581409":1509788624813,"1024114225673":1509788624606,"1024114225677":1509788624606,"1024114225678":1509788624606,"1024114225679":1509788624606,"1024114225665":1509788624606,"1016655918748":1480585069075,"1020793991143":1509788624960,"2027224011":1491634246513,"1010025802226":1478686804067,"1024114225725":1509788624606,"1024114225726":1509788624606,"1022209065900":1478686417191,"1024156432315":1509788667500,"1024114225705":1509788624606,"1024114225710":1509788624606,"4985891352":1509788624154,"1025522026041":1509788624295,"1024114225700":1509788624606,"1024114225702":1509788624606,"1024114225703":1509788624606,"1019042643968":1509788625079,"1024735581352":1509788624813,"1024114225745":1509788624606,"1022338960257":1509788624922,"1024114225747":1509788624606,"1023956151080":1509788624519,"1024114225736":1509788624606,"1021769311630":1478686417254,"1025660702104":1509788624393,"1021769311628":1478686417254,"1024114225741":1509788624606,"1024114225729":1509788624606,"1025660702103":1509788624393,"1025607747954":1509788625001,"1021997248580":1478686416987,"1025607747959":1509788624998,"1022721301878":1509788624985,"1022721301879":1509788624985,"1021615038087":1478686417116,"1022379723024":1478686417205,"1022379723028":1478686417205,"1024719328649":1509788624342,"1022721301871":1509788624985,"1022721301868":1509788624985,"1022721301869":1509788624985,"1022379723010":1478686417205,"1021931973744":1478686417010,"1022379723015":1478686417205,"768913067":1491634246534,"1022931281944":1509788625073,"1025607747990":1509788625084,"1024735581285":1509788624813,"1021048010836":1478686417093,"1025660702043":1509788624393,"1022721301900":1509788624983,"1025607747975":1509788625001,"1025282684135":1509788625158,"1025660702044":1509788624393,"1021568112975":1509788624401,"1021048010830":1478686417093,"1025282684133":1509788625158,"1025282684136":1509788625158,"1025282684137":1509788625158,"1022721301891":1509788624983,"1022721301889":1509788624986,"1025282684141":1509788625158,"1021488289314":1478686417046,"1227016931":1444487341738,"1019963963832":1478686804021,"1018546791728":1480585069063,"1024735581229":1509788624813,"1021485012584":1509788624814,"1015242482184":1480585069068,"1022343154521":1478686417288,"1020173222953":1509788624321,"1001309643144":1444487341755,"1020173222952":1509788624321,"1020173222949":1509788624321,"1020173222948":1509788624321,"1010024491287":1491634246521,"1020173222951":1509788624321,"1020173222950":1509788624321,"1018546791725":1480585069063,"1020173222947":1509788624320,"4947748107":1509788624153,"1024153155397":1509788667495,"1227016904":1444487341748,"1022038930759":1478686417268,"1022721301993":1509788624986,"1022444866914":1478686417214,"1019218283209":1509788625020,"949009555":1444487341742,"1024735581163":1509788624813,"1022950156412":1509788625051,"1024789323474":1509788624453,"1024789323473":1509788624459,"1214958694":1444487341741,"1024789323478":1509788624459,"1024789323476":1509788624458,"1024789323467":1509788624458,"1024789323464":1509788624458,"1024789323465":1509788624458,"1024789323470":1509788624458,"1024789323469":1509788624458,"1024886315784":1509788624185,"1024789323462":1509788624458,"1024789323514":1509788624233,"1000526082249":1444487341737,"1022389030893":1478686417205,"1024789323515":1509788624233,"1024789323513":1509788624233,"1024789323506":1509788624233,"1024789323507":1509788624233,"1023835039122":1491634246536,"1024789323509":1509788624233,"1024577636673":1509788624926,"1021695255835":1509788624396,"1022287184321":1478686417286,"1024789323420":1509788624458,"1024156561620":1509788667500,"1022461119431":1480585069076,"1018700147687":1465470268320,"1024789323411":1509788624459,"1024789323409":1509788624459,"1024156561625":1509788667500,"1024789323406":1509788624458,"1022226367947":1478686417192,"1024789323407":1509788624459,"1682104341":1491634246534,"1024156561614":1509788667500,"1664411498":1491634246519,"1024156561612":1509788667500,"1021597998961":1509788624909,"1024789323448":1509788624458,"1024789323449":1509788624458,"1021239902765":1478686417236,"1021597998965":1509788624909,"1021597998967":1509788624909,"1024789323453":1509788624458,"1021597998966":1509788624909,"1021597998969":1509788624909,"142773483":1444487341710,"1022255728565":1478686417067,"1024789323441":1509788624458,"1024789323446":1509788624458,"1021597998973":1509788624909,"1021597998972":1509788624909,"1210109006":1444487341743,"1024789323444":1509788624458,"1021597998974":1509788624909,"1024789323433":1509788624458,"1024789323437":1509788624458,"1021597998957":1509788624909,"1024789323431":1509788624458,"1021597998956":1509788624909,"1024789323429":1509788624458,"4947747435":1509788624153,"1021597998977":1509788624909,"1021597998976":1509788624909,"1021597998979":1509788624909,"1010011647258":1491634246525,"1021597998981":1509788624909,"1022037619272":1478686417167,"1021597998980":1509788624909,"1021597998983":1509788624909,"1023537368044":1509788667501,"1021597998985":1509788624909,"1023537368034":1509788667501,"1021597998984":1509788624909,"1021597998986":1509788624909,"1021846122160":1509788625077,"1024587467353":1509788625095,"1021110794881":1478686417095,"1022074977319":1478686804039,"1023735029526":1509788624970,"1023537368018":1509788667501,"1021809552604":1478686417256,"1022273683462":1480585069094,"1016298349661":1480585069073,"1001517525853":1444487341750,"1021809552602":1478686417256,"1021196255317":1478686417038,"1024950544268":1509788625178,"1023537368014":1509788667501,"139627670":1444487341738,"601663252":1444487341745,"1023822193832":1491634246536,"1019272549697":1509788624287,"1019272549699":1509788624287,"1000237721320":1444487341762,"1016254437702":1480585069075,"1020941316334":1465470268236,"2006250356":1491634246533,"1012423605551":1478686416994,"4985892290":1509788624156,"1017230283696":1478686804022,"1021832096797":1478686804027,"1023858501460":1509788624213,"1022438181882":1478686417295,"486054399":1444487341734,"1143259437":1491634246519,"1023306417205":1509788624406,"1021491040381":1478686417243,"1022869676597":1509788625144,"1019384356351":1480585069073,"1021156148311":1478686416975,"1019384356347":1480585069073,"1023858501449":1509788624213,"1024578160727":1509788624925,"1024578160733":1509788624925,"1022146541939":1478686417277,"1006559223367":1480585069064,"1024578160690":1509788624925,"1018805399587":1509788624929,"1021082089600":1478686417036,"1021650426528":1478686417049,"1022065668706":1478686417175,"1019023247165":1480585069072,"1024578160678":1509788624925,"1022295048250":1478686417286,"1003975623701":1478686417221,"1003975623700":1478686417221,"1003975623702":1478686417221,"1003975623696":1478686417221,"1003975623699":1478686417221,"1003975623698":1478686417221,"1023438670900":1509788625082,"1003975623704":1478686417221,"1003975623684":1478686417221,"166497438":1444487341732,"1003975623686":1478686417221,"1003975623681":1478686417221,"1003975623680":1478686417221,"1023835432128":1491634246536,"1003975623693":1478686417221,"1003975623692":1478686417221,"1003975623688":1478686417221,"4985891922":1509788624154,"1025627670975":1509788624430,"1023353995721":1509788624257,"1024789323611":1509788624568,"1024789323608":1509788624568,"1023365529658":1509788625040,"1023353995723":1509788624257,"1024789323614":1509788624568,"1023353995725":1509788624257,"1024789323612":1509788624568,"1024789323613":1509788624568,"1021004758465":1478686417089,"1023353995716":1509788624256,"1024789323606":1509788624568,"1023353995717":1509788624257,"949009664":1444487341746,"1023353995738":1509788624256,"1024789323598":1509788624568,"1023353995741":1509788624257,"1024789323596":1509788624568,"1024789323597":1509788624568,"1023353995728":1509788624257,"1023353995731":1509788624257,"1023353995732":1509788624257,"371495866":1444487341751,"1023353995734":1509788624257,"1024973348957":1509788624288,"1023353995752":1509788624256,"1021995022056":1509788624466,"1023353995758":1509788624257,"1023353995744":1509788624257,"1023353995746":1509788624257,"1023353995747":1509788624257,"1023353995749":1509788624257,"1020803295681":1509788624605,"1023353995773":1509788624256,"1023353995760":1509788624256,"1024789323618":1509788624568,"1024789323616":1509788624568,"1023353995763":1509788624257,"1024789323617":1509788624568,"1023353995766":1509788624256,"1020803295667":1509788624605,"1020803295666":1509788624605,"1021161653460":1478686417038,"1022233183477":1478686417065,"1020803295664":1509788624605,"1024789323550":1509788624233,"1020803295670":1509788624605,"1016831949507":1478686804058,"1024789323538":1509788624233,"1020803295675":1509788624605,"1024789323539":1509788624233,"1020803295674":1509788624605,"1020803295672":1509788624605,"2006250073":1491634246533,"1020803295678":1509788624605,"1024789323540":1509788624233,"1020803295676":1509788624605,"1024789323530":1509788624233,"1020803295651":1509788624605,"1024789323534":1509788624233,"1024789323535":1509788624233,"1024789323533":1509788624233,"1024789323522":1509788624233,"1020803295659":1509788624605,"1021161653453":1478686417038,"1020803295657":1509788624605,"1020803295656":1509788624605,"1020803295663":1509788624605,"1024789323527":1509788624233,"1020803295662":1509788624605,"1020803295661":1509788624605,"1011943217546":1509788624915,"1024886315770":1509788624185,"1024789323570":1509788624233,"1019208452233":1480585069068,"1024106886279":1509788667890,"1024789323562":1509788624233,"1021836816165":1509788625082,"1024789323563":1509788624233,"1021836816167":1509788625082,"2006250087":1491634246533,"1024789323561":1509788624233,"1021836816166":1509788625082,"1024789323566":1509788624233,"1024789323567":1509788624233,"1024789323564":1509788624233,"1024886315749":1509788624185,"1024789323555":1509788624233,"1024789323558":1509788624233,"1021836816169":1509788625082,"1024789323559":1509788624233,"1021836816168":1509788625082,"1024789323556":1509788624233,"1022464526668":1509788624280,"1023536974178":1509788624459,"1022464526666":1509788624300,"1022464526667":1509788624281,"1022464526660":1509788624319,"1020294203554":1465470268296,"1022464526661":1509788624319,"1012144680551":1478686417073,"1022464526662":1509788624281,"1023536974187":1509788624437,"1024114226963":1509788624835,"1022464526656":1509788624280,"1022464526657":1509788624299,"1022464526659":1509788624280,"1023536974192":1509788624459,"1023536974193":1509788624459,"1022464526686":1509788624299,"379490438":1444487341702,"1022086381549":1478686417062,"1024114226945":1509788624835,"1022464526678":1509788624311,"1023864530400":1509788624357,"1011898130213":1509788624366,"1023864530401":1509788624357,"1022464526672":1509788624319,"1021832097539":1478686804047,"1023536974147":1509788624459,"1022464526696":1509788624290,"1023864530399":1509788624357,"1023536974151":1509788624459,"1022464526692":1509788624299,"1025671186432":1509788624455,"1020991254804":1478686417034,"1022464526688":1509788624319,"1024114226996":1509788624835,"1022464526689":1509788624288,"1023536974158":1509788624459,"1023536974163":1509788624459,"333485528":1491634246508,"1021468627603":1509788624398,"1024114226978":1509788624835,"1023536974174":1509788624459,"1062123791":1478686804051,"1025270755404":1509788624553,"1025732531396":1509788624922,"1025270755407":1509788624553,"1023536974121":1509788624459,"1021156148999":1478686416975,"1023536974126":1509788624459,"1024114227016":1509788624843,"1025270755417":1509788624849,"1025270755418":1509788624849,"1021647935560":1478686804069,"1024114227019":1509788624843,"1025270755419":1509788624849,"1025270755420":1509788624849,"1023536974133":1509788624459,"1025270755421":1509788624849,"1022165810031":1478686417186,"2006249923":1491634246533,"1025270755408":1509788624553,"1025270755409":1509788624553,"1021937219203":1478686417055,"1022474884852":1478943089486,"1025270755411":1509788624553,"1024114227011":1509788624868,"1022192548317":1478686417188,"1021647935559":1478686804069,"1024937829761":1509788625170,"1023536974083":1509788624459,"379490554":1444487341702,"1021912705080":1478686417140,"1022464526654":1509788624281,"1025523860327":1509788625167,"1023536974102":1509788624459,"1022395059693":1478686417206,"1022086119303":1478686417272,"1021432321166":1478686416980,"1022008652313":1478686417158,"1023821276908":1491634246536,"1023353995978":1509788624260,"1024937829730":1509788625170,"379490328":1444487341702,"1021647935635":1478686804071,"1023353995968":1509788624260,"1024937829737":1509788625171,"1021866306972":1478686417136,"1023353995971":1509788624260,"1024937829740":1509788625171,"1021647935637":1478686804071,"1021647935636":1478686804071,"1024937829746":1509788625171,"1021729203643":1509788624395,"1024937829752":1509788625170,"1023353995986":1509788624260,"1022169479290":1509788624924,"1024937829758":1509788625171,"1024937829759":1509788625170,"1019307021600":1465470268273,"1020930962036":1478686417082,"1020915365133":1478686416999,"1025767133758":1509788624438,"1024937829708":1509788625170,"1020930962041":1478686417083,"1024937829711":1509788625170,"1024937829715":1509788625171,"1024937829726":1509788625171,"1023353995912":1509788624260,"1020444152090":1478686804033,"1023353995914":1509788624260,"1022511322182":1480585069126,"1022770456564":1509788624994,"1010069711606":1491634246534,"1025627671044":1509788624868,"1023353995908":1509788624260,"1023353995909":1509788624260,"1023353995910":1509788624260,"1023353995928":1509788624260,"1025767133762":1509788624438,"1024936387782":1509788625006,"1023353995929":1509788624260,"1023353995930":1509788624260,"1023353995932":1509788624260,"1023353995933":1509788624260,"1023353995934":1509788624260,"1025767133764":1509788624438,"1023353995935":1509788624260,"1023353995920":1509788624260,"1025767133769":1509788624438,"1025883921728":1509788667403,"1023353995925":1509788624260,"1025767133773":1509788624438,"1019384356359":1480585069073,"1019384356355":1480585069073,"1019384356354":1480585069073,"1019384356353":1480585069073,"1023353995951":1509788624260,"1022073536094":1509788624280,"1023353995941":1509788624260,"1021197566466":1495284743407,"1021948622590":1509788624390,"1022453254379":1478686417302,"1000237720781":1444487341762,"1023353995966":1509788624260,"1025902402200":1509788667465,"1022067765738":1509788624183,"1025902402201":1509788667457,"1023353995958":1509788624260,"1021001088903":1478686417089,"1021949802271":1478686417145,"1022501492287":1509788624538,"1022301340180":1478686417199,"1024226688855":1509788625032,"1016399536592":1480585069069,"1025593069036":1509788624929,"1018379803630":1509788625079,"1023924429155":1509788624969,"1021832097321":1478686804047,"1021949802284":1478686417145,"1021949802287":1478686417145,"1021949802273":1478686417145,"1025520452126":1509788624297,"1019272550064":1509788624287,"1019272550066":1509788624287,"1025270755660":1509788624215,"1022607007626":1509788624821,"1025270755661":1509788624215,"1025270755662":1509788624215,"1025270755663":1509788624215,"1012238788992":1458304307281,"1012238788995":1458304307281,"1023927181684":1491634246529,"1012238788994":1458304307281,"225741368":1478686804032,"1025270755654":1509788624215,"1012238788998":1458304307281,"1022599270428":1509788624569,"1003127572644":1478686804054,"1019121553363":1509788624314,"1021903399355":1478686417139,"1022087691949":1478686417012,"1016963940422":1478686804067,"1016963940421":1478686804067,"1022086381186":1478686417062,"1023536974049":1509788624459,"1023536974050":1509788624459,"1021778092497":1480585069073,"1023536974053":1509788624459,"1020526336887":1465470268322,"1020785732857":1509788624383,"1021778092509":1480585069073,"1016101737217":1509788624941,"1023536974066":1509788624459,"1023536974068":1509788624459,"1022957104006":1509788625101,"1023536974076":1509788624459,"1021778092535":1480585069073,"1023995211156":1491634246529,"1021778092530":1480585069073,"1025530151194":1509788624335,"1025767134010":1509788624453,"1021778092537":1480585069073,"1000527917915":1444487341714,"1025703303151":1509788624298,"1023924429304":1509788624969,"1021778092516":1480585069073,"1023536974035":1509788624459,"1023536974038":1509788624459,"1020582041652":1478686416995,"1023536974040":1509788624459,"1021778092524":1480585069073,"1021778092526":1480585069073,"1023536974045":1509788624459,"1023536974046":1509788624459,"1009965244853":1491634246523,"1012155821593":1478686417025,"1024210956444":1509788624915,"1016681083341":1478686804018,"1021242262013":1478686417003,"1022072225652":1478686417176,"1023353996178":1509788624214,"1022957104077":1509788624533,"1021944559528":1478686417010,"1021778092468":1480585069073,"1021778092471":1480585069073,"1021687785049":1509788624396,"1024114226939":1509788624916,"1022543172447":1509788625075,"1021778092465":1480585069073,"1021778092467":1480585069073,"1024114226942":1509788624835,"1025569607600":1509788624349,"1025531068781":1509788624338,"1021778092472":1480585069073,"1022354951684":1509788624928,"1024114226922":1509788624916,"4985892572":1509788624156,"1021778092449":1480585069073,"1022354951683":1509788624928,"1021691455131":1478686417009,"1021778092460":1480585069073,"1025625443101":1509788624915,"1021807587181":1478686417255,"1022068031248":1478686417176,"1021807587178":1478686417255,"1024114227480":1509788625233,"1024114227481":1509788625233,"1012199334695":1478686417223,"1010864149725":1478686804025,"1025180318057":1509788624225,"1025180318053":1509788624225,"1024114227473":1509788625235,"1021096900345":1478686804067,"1025180318054":1509788624225,"1025180318055":1509788624225,"1024114227475":1509788625234,"1024114227477":1509788625234,"1025180318050":1509788624225,"1000526085370":1444487341750,"1001175290440":1478950494934,"1024114227467":1509788625235,"1015071038986":1478686804062,"1024631380017":1509788624938,"1024114227469":1509788625234,"1024114227471":1509788625234,"1022324674490":1478686417200,"1019184858322":1509788624959,"1024114227457":1509788625234,"1025569603650":1509788624349,"1024210960206":1509788624608,"1024114227460":1509788625234,"1024114227462":1509788625234,"1024293008465":1509788667902,"1024293008468":1509788667902,"1024293008469":1509788667902,"1021002657866":1478686417089,"1009663384672":1478686804030,"1018296836088":1478686804053,"1021816365506":1478686417256,"1024293008448":1509788667903,"1019444253508":1509788624921,"1024293008456":1509788667903,"362323417":1444487341751,"1020150156574":1478686804031,"362323423":1444487341737,"1020402342940":1478686804028,"1024293008444":1509788667903,"1024735584163":1509788624508,"1024293008446":1509788667903,"142770381":1444487341710,"1014753840311":1465470268313,"1020150156556":1478686804057,"1025019227991":1509788625007,"1021760662800":1478686417254,"1021848871496":1509788624993,"362323406":1444487341744,"1018739996949":1509788624367,"1020150156545":1478686804023,"1020150156544":1478686804057,"1024333510534":1509788624468,"1021096900248":1478686804067,"1024985410939":1509788624279,"1021037523466":1478686417092,"1024985410943":1509788624279,"1024985410941":1509788624279,"1022055055187":1478686417173,"1024985410944":1509788624279,"1021409908896":1478686804065,"1021259304876":1465470268198,"1024735584097":1509788624508,"1022469638028":1478686417219,"1021761973690":1478686417127,"1021761973688":1478686417127,"1021761973687":1478686417127,"1022164759984":1478686417186,"142770207":1444487341711,"1022895235328":1509788624927,"1022043389633":1478686417170,"1019033865070":1509788624388,"1022895235334":1509788624927,"1022895235336":1509788624927,"1023987868201":1509788625036,"1022895235340":1509788624927,"1019302566772":1509788624312,"1022895235347":1509788624927,"1022895235348":1509788624942,"1022895235350":1509788624927,"1022895235351":1509788624927,"1022895235354":1509788624927,"1022895235356":1509788624927,"1019082493532":1509788625018,"1020626086493":1478686804071,"1024333510488":1509788624429,"1022895235358":1509788624927,"1020294071912":1465470268287,"1012322417462":1480585069061,"1025524518444":1509788624193,"1023722050227":1509788624384,"1023722050228":1509788624384,"1020764365428":1478686417076,"1025296314455":1509788624978,"1022138545167":1478686417184,"1025627014165":1509788625167,"1022021893494":1478686417162,"1024114227704":1509788625237,"1020596856927":1478686416976,"1024114227706":1509788625237,"1024114227708":1509788625237,"1024114227709":1509788625237,"1024114227711":1509788625237,"1022231873987":1478686417282,"1024114227698":1509788625238,"1021243576029":1478686417100,"1024114227700":1509788625237,"1024114227702":1509788625237,"1024114227690":1509788625237,"1024114227694":1509788625238,"1025406940947":1509788624507,"1024735584020":1509788624508,"1024114227683":1509788625237,"1022255729442":1478686417067,"1024114227685":1509788625238,"1024114227686":1509788625238,"1022192940896":1478686417279,"1024114227687":1509788625237,"1019204519098":1478686804038,"1019204519097":1478686804038,"1019204519096":1478686804038,"1019204519095":1478686804038,"1022147065168":1478686417013,"1022511324047":1480585069127,"1022434378793":1480585069097,"1022895235252":1509788624927,"1022895235259":1509788624927,"1022434378788":1480585069097,"1022434378789":1480585069097,"1022434378790":1480585069097,"1023957066089":1509788624519,"1022434378776":1480585069097,"1022939931190":1509788625052,"1022434378780":1480585069097,"1022434378768":1480585069097,"1024157220160":1509788624459,"1024157220161":1509788624459,"1024157220163":1509788624459,"1022434378772":1480585069097,"1022434378761":1480585069097,"1022434378765":1480585069097,"1025585725559":1509788624352,"1024576717919":1509788624439,"1021999217201":1478686417157,"1022434378756":1480585069097,"1022895235302":1509788624927,"1564791820":1444487341737,"1022895235305":1509788624927,"1022238821258":1509788624947,"1022238821259":1509788624930,"1022895235308":1509788624927,"1020440092507":1464448510787,"1022895235310":1509788624927,"1003975624741":1478686417222,"1022434378856":1480585069097,"1003975624740":1478686417222,"1022434378858":1480585069097,"1003975624742":1478686417222,"1022895235315":1509788624927,"1003975624737":1478686417222,"1000935032285":1509788624469,"1024157220157":1509788624459,"1003975624739":1478686417222,"1022895235320":1509788624927,"1024735583924":1509788624508,"1003975624745":1478686417222,"1022895235324":1509788624927,"1003975624744":1478686417222,"1003975624747":1478686417222,"1021708888875":1478686804046,"1022434378842":1480585069097,"1024114227323":1509788625232,"1022895235270":1509788624927,"1024114227327":1509788625233,"1003975624732":1478686417221,"1022434378833":1480585069097,"1024114227313":1509788625233,"1003975624734":1478686417221,"1022895235275":1509788624928,"1003975624729":1478686417221,"1003975624728":1478686417221,"1022895235278":1509788624927,"1003975624730":1478686417221,"1022895235280":1509788624927,"1022434378825":1480585069097,"1022895235283":1509788624927,"1024114227307":1509788625232,"1022434378828":1480585069097,"1024114227308":1509788625233,"1019204519114":1478686804038,"1022434378829":1480585069097,"1019204519113":1478686804038,"1022895235286":1509788624927,"1019204519112":1478686804038,"1019204519111":1478686804038,"1019204519110":1478686804038,"1019204519109":1478686804038,"1019204519108":1478686804038,"1022895235291":1509788624927,"1019204519107":1478686804038,"1024244379690":1509788624948,"1019204519106":1478686804038,"1019204519105":1478686804038,"1021309895490":1465470268202,"1021293772872":1478686416981,"1019204519104":1478686804038,"1022434378823":1480585069097,"1021454998042":1478686417107,"1022245899253":1478686417195,"1021473218019":1478686417045,"1024114227354":1509788625232,"1020875651462":1478686417031,"1009785541253":1478686804025,"1024114227344":1509788625232,"1024114227349":1509788625232,"1024114227336":1509788625232,"1024114227339":1509788625232,"1024114227341":1509788625232,"1024114227329":1509788625233,"1024114227331":1509788625233,"1024114227334":1509788625232,"1020150156541":1478686804031,"1025214659264":1509788624536,"1024114227384":1509788625233,"1024189988660":1509788667888,"1022031723679":1509788624466,"1024114227388":1509788625233,"1024114227389":1509788625233,"1020937125331":1478686417083,"1024114227390":1509788625232,"1024114227378":1509788625233,"1024114227380":1509788625233,"1022511323951":1480585069127,"1020551763171":1478686804035,"1023730831964":1509788624960,"1024114227373":1509788625233,"1024114227361":1509788625232,"1020937125327":1478686417083,"1024114227365":1509788625233,"1021157591279":1478686804064,"1024028501492":1509788624517,"1024114227416":1509788625233,"1024937830945":1509788625171,"1024028501488":1509788624517,"1024114227420":1509788625235,"1024028501489":1509788624517,"1026223924881":1514456869766,"1024937830956":1509788625171,"1024653400890":1509788624178,"1021847299046":1509788624510,"1024937830964":1509788625170,"1024937830965":1509788625170,"1019300076094":1509788624281,"1024114227392":1509788625232,"1024028501486":1509788624517,"1024028501487":1509788624517,"1024028501480":1509788624517,"1024937830972":1509788625171,"1025627669788":1509788624866,"1024937830974":1509788625171,"1024028501483":1509788624517,"1021847299029":1509788624510,"1024114227449":1509788625234,"1020801721736":1478686417030,"1020763579214":1478686417224,"1019386712359":1509788624317,"1024114227453":1509788625234,"1024114227455":1509788625234,"1024028501471":1509788624517,"1024114227444":1509788625234,"1021229944592":1478686416978,"1021631550688":1509788624396,"1024937830930":1509788625171,"1024114227434":1509788625234,"1024114227435":1509788625234,"1024114227437":1509788625233,"1016298350849":1480585069073,"1022067769062":1509788624183,"1024735583769":1509788624508,"1024937830936":1509788625171,"1024114227424":1509788625235,"1022456661565":1478686417016,"1024114227425":1509788625234,"1024114227427":1509788625234,"1019033864759":1509788624374,"1024114227993":1509788625238,"1024114227995":1509788625238,"1025180580728":1509788625163,"1025180580729":1509788625163,"1025546276270":1509788624523,"1025180580730":1509788625163,"1025546276271":1509788624517,"1022132515105":1478686417063,"1025546276264":1509788624523,"1020925196569":1478686417228,"2069295425":1444487341745,"1025772117567":1509788625114,"1020833965189":1478686417031,"1024114227971":1509788625238,"1025180580724":1509788625162,"1020925196562":1478686417228,"1025546276257":1509788624518,"1024114227973":1509788625238,"1025546276258":1509788624518,"1021972871321":1478686417150,"1011803889397":1478686804015,"1024114228016":1509788625239,"1024114228017":1509788625238,"1024114228019":1509788625238,"1025019227434":1509788625006,"1024114228021":1509788625238,"1008521730640":1478686804015,"1024028501508":1509788624517,"1022896808889":1509788625018,"1024028501510":1509788624517,"1024114228011":1509788625239,"1024028501504":1509788624517,"1022502148922":1509788624936,"1022502148923":1509788624936,"1020294202525":1465470268296,"1024114228014":1509788625239,"1024028501507":1509788624517,"1022502148921":1509788624935,"1024114228015":1509788625239,"1024114228000":1509788625238,"1024028501518":1509788624517,"1024114228003":1509788625239,"1021746376197":1478686417254,"1024028501512":1509788624517,"1024028501514":1509788624517,"1024114228006":1509788625239,"1024028501515":1509788624517,"1022502148943":1509788624935,"1022239869074":1478686416989,"1022502148935":1509788624935,"1022502148930":1509788624936,"1022502148958":1509788624936,"1022502148959":1509788624936,"1022502148957":1509788624936,"1022502148954":1509788624936,"1022502148955":1509788624936,"1022502148952":1509788624936,"1248510013":1491634246505,"1022502148950":1509788624936,"1022502148949":1509788624936,"1025627670175":1509788624845,"1022502148947":1509788624936,"1025627670172":1509788624845,"1025627670178":1509788624845,"1025772117570":1509788625106,"1025772117571":1509788625087,"1025627670180":1509788624845,"1025627670181":1509788624845,"1010011382749":1491634246525,"1025627670185":1509788624845,"1022502148965":1509788624936,"1024587072676":1509788667888,"1022502148963":1509788624936,"1025627670188":1509788624845,"1022502148960":1509788624936,"1021644133411":1509788624818,"4957842932":1509788624156,"1025636058677":1509788625019,"1022197003556":1478686417064,"1025623736734":1509788624366,"1025623736735":1509788624366,"1025623736733":1509788624366,"1012905172921":1478950494940,"1022391255352":1478686417070,"1020801984243":1478686417077,"1025798200364":1509788624203,"1664412067":1491634246519,"1021981915307":1478686417263,"1022391255348":1478686417070,"1023856011484":1491634246537,"1023856011485":1491634246533,"1025623736764":1509788624365,"1025623736762":1509788624365,"1025623736763":1509788624365,"1023856011482":1491634246537,"1025623736760":1509788624366,"1025623736761":1509788624365,"1025623736758":1509788624366,"1025623736759":1509788624366,"1021981915289":1478686417263,"1021981915294":1478686417263,"1021981915293":1478686417263,"1021981915292":1478686417263,"1801773524":1444487341739,"1021011833681":1478686416988,"1023946452392":1491634246531,"1023946452394":1491634246531,"1023946452395":1491634246531,"1025027482161":1509788624945,"1023988523052":1509788625036,"1025523863465":1509788624867,"309106897":1491634246533,"1022384177395":1478686417015,"1021338732194":1478686417005,"1021860929932":1509788624992,"1012605143519":1478686416994,"1021755551553":1478686417126,"1021580038383":1478686416992,"1025180580743":1509788625162,"142770802":1444487341710,"1019146060745":1509788624313,"1021644133538":1509788624420,"4973437577":1509788624154,"1025623736806":1509788624365,"1008957153435":1478686804030,"1025623736807":1509788624365,"1025623736804":1509788624365,"1025623736805":1509788624365,"1025623736803":1509788624365,"1001517524239":1444487341750,"1022473706434":1478943089223,"1007103440868":1478686804023,"1021460633638":1478686417108,"1024114227729":1509788625237,"1024114227730":1509788625237,"1679879980":1491634246510,"1024114227720":1509788625238,"1020985621632":1478686804039,"1024114227721":1509788625238,"1024114227723":1509788625238,"1024114227724":1509788625238,"1024114227726":1509788625238,"1025772117809":1509788624203,"1024730733888":1509788624507,"1024114227713":1509788625237,"1024114227714":1509788625238,"1021467975630":1478686417007,"1024114227719":1509788625238,"328243376":1478686804024,"1021906675118":1478686417140,"1023856273755":1491634246537,"1018387142480":1478686804066,"1022252845249":1478686417066,"1021939448718":1478686417260,"1020933849021":1478686417033,"1021906675121":1478686417140,"1021906675120":1478686417140,"1025524518359":1509788624193,"1664411767":1491634246519,"1025524518317":1509788624193,"1022049680704":1509788624439,"1021681232725":1509788624400,"1019372821756":1509788624354,"1021012226739":1465470268305,"1021912704287":1478686417140,"1021647934805":1478686804069,"1025685101":1478686417020,"1021883213632":1478686417137,"1022213786372":1478686417064,"1021609662236":1509788624404,"1022154667685":1478686417185,"1012186882199":1478686416994,"1021865255038":1509788624402,"1024245166672":1509788624948,"1022473706427":1478943089223,"1022473706428":1478943089223,"1021291545131":1478686417102,"1022336992102":1478686417201,"1021700499825":1478686804032,"1022235282079":1478686417193,"1862329484":1444487341727,"1024167575144":1509788667829,"1021687786008":1509788624396,"1022072615693":1478686417060,"142770991":1444487341710,"1021663007902":1509788624997,"1025524518233":1509788624193,"1022450894217":1478686417215,"1021647934883":1478686804069,"1021157198565":1478686417038,"1022032772789":1478686417166,"1009983859951":1478686804061,"1021500480771":1509788624398,"1024114227932":1509788625238,"1227014885":1444487341745,"1021701417217":1478686416989,"1021701417220":1478686416989,"1862329555":1444487341727,"1021963565816":1478686417148,"1025007561741":1509788624343,"1025857311460":1509788667843,"1025857311461":1509788667844,"1021575188887":1509788625084,"1022236461316":1478686417282,"1024114227960":1509788625239,"1022236461318":1478686417282,"1024114227962":1509788625239,"1024114227963":1509788625238,"1024114227966":1509788625238,"1024114227967":1509788625238,"1024114227944":1509788625238,"1025798200649":1509788624425,"1024062580217":1509788624326,"1024114227949":1509788625238,"1024114227937":1509788625239,"1025524518164":1509788624193,"1000526085909":1444487341712,"1024114227941":1509788625239,"1023722051199":1509788624384,"1022400956199":1478686417207,"1025049371977":1509788625097,"1025049371982":1509788625097,"1021806797972":1478686417131,"1025646543290":1509788624337,"1025049371970":1509788625097,"1022400956207":1478686417207,"1025049371971":1509788625097,"1016502821052":1478686804022,"1022400956202":1478686417207,"1022178128476":1478686417278,"1022511324842":1480585069127,"1021920699390":1509788625019,"1022146539634":1478686417277,"1021385917431":1478686417042,"1025798200053":1509788624827,"1017545909973":1480585069078,"1019118797972":1509788624317,"1012582469163":1478686417026,"1020951280067":1478686417085,"1021428391250":1478686417106,"1021014717879":1478686416987,"1022400956226":1478686417207,"1023924431408":1509788624969,"1024024043526":1509788624277,"1017770572723":1478686804022,"1025627668548":1509788624230,"1022238690899":1509788624947,"1022238690900":1509788624971,"1022238690901":1509788624930,"1022295968224":1478686417199,"1021833143878":1478686417134,"1021833143872":1478686417134,"1023924431614":1509788624969,"1021385917196":1478686417042,"1022094243266":1478686417274,"1001056935822":1478686804029,"1021320120133":1465470268210,"1021952294194":1478686417146,"1022094243252":1478686417274,"1022094243254":1478686417274,"1021833143868":1478686417134,"1021833143870":1478686417134,"1021428522458":1478686417044,"1022237249056":1509788624288,"1022239739405":1478686417014,"1022237249048":1509788624299,"1022237249041":1509788624300,"1022237249042":1509788624301,"1022237249033":1509788624300,"1022237249036":1509788624301,"1023722051200":1509788624384,"1023722051201":1509788624384,"1023722051202":1509788624384,"1023722051203":1509788624384,"1023722051204":1509788624384,"1022237249029":1509788624300,"1023722051205":1509788624384,"1022237249031":1509788624300,"1022457447128":1480585069105,"1020136655117":1480585069063,"1023835040958":1491634246533,"1020616649872":1478686417027,"1022457447133":1480585069105,"1021501004767":1478686804071,"1022457447120":1480585069105,"1022457447121":1480585069105,"1022457447122":1480585069105,"1022718153508":1509788624367,"1022457447124":1480585069105,"1022457447125":1480585069105,"1022457447126":1480585069105,"1503581329":1444487341717,"1022457447116":1480585069105,"1022457447118":1480585069105,"1022457447119":1480585069105,"1021027431479":1478686417231,"1021561033733":1509788624397,"1024156432816":1509788667500,"1025489784380":1509788625082,"1021396140599":1478686417240,"1025879987945":1509788667404,"1021529578035":1509788624912,"1021501004769":1478686804071,"1021501004768":1478686804071,"1021501004771":1478686804071,"1020294071186":1465470268287,"1020783503014":1478686417029,"1021501004770":1478686804071,"1022457447139":1480585069105,"1021475969383":1478686417109,"1021647934246":1478686804046,"1022457447141":1480585069105,"1022457447143":1480585069105,"1022457447065":1480585069112,"1023937276613":1509788667833,"417109406":1478950494909,"1022457447066":1480585069112,"1022457447067":1480585069112,"1022457447068":1480585069112,"1022457447069":1480585069112,"1008959383302":1478686804054,"1022457447071":1480585069112,"1022457447059":1480585069112,"1022457447060":1480585069112,"1022457447061":1480585069112,"1021534557591":1478686417113,"1022457447062":1480585069112,"1021314221735":1478686417102,"1022457447042":1480585069112,"1022483537268":1478943089488,"1008733409465":1444487341757,"1776215226":1478686417017,"1008733409470":1444487341757,"1021529578092":1509788624912,"1021160868973":1478686417038,"1021641118476":1509788624206,"1021816366237":1478686417256,"1022457447083":1480585069112,"1022457447084":1480585069112,"1022457447085":1480585069112,"1022457447086":1480585069112,"1025772116305":1509788624828,"1024007792135":1509788667830,"1023577873514":1509788624939,"1000116606475":1478686804033,"1024002942657":1491634246518,"1022457447079":1480585069112,"1022331751122":1509788625082,"1022331751123":1509788625082,"1025627668804":1509788624212,"1022331751120":1509788625082,"1022331751121":1509788625082,"1025627668810":1509788624212,"1025627668812":1509788624212,"1022457446984":1480585069112,"1022457446985":1480585069112,"1021156805838":1478686417234,"1021160344732":1478686417097,"1018669473812":1509788625017,"1022457446977":1480585069112,"1022331751119":1509788625082,"1022457446979":1480585069112,"1009839805012":1491634246518,"1022457446980":1480585069112,"1024632823186":1509788625008,"1022457447032":1480585069112,"1022511324967":1480585069127,"1022457447038":1480585069112,"228229170":1444487341748,"1022457447024":1480585069112,"1022457447025":1480585069112,"1022457447026":1480585069112,"1012322418270":1480585069061,"1022457447027":1480585069112,"1022457447028":1480585069112,"1022457447029":1480585069112,"1022457447017":1480585069112,"1022457447019":1480585069112,"1022457447020":1480585069112,"1022096733421":1478686417275,"1022457447022":1480585069112,"4973438411":1509788624153,"1022078383567":1478686417272,"1022457447012":1480585069112,"1022457447013":1480585069112,"1022346036664":1478686804042,"1022346036665":1478686804042,"1021387489883":1478686417006,"1021160344781":1478686417097,"1022346036666":1478686804042,"1022346036667":1478686804042,"1022346036662":1478686804042,"1022404493613":1478686417015,"1022346036652":1478686804042,"1022346036653":1478686804042,"1000237723626":1444487341762,"1022346036654":1478686804042,"1022346036655":1478686804042,"1022346036648":1478686804042,"1022032771294":1478686417166,"1022346036649":1478686804042,"1022346036650":1478686804042,"1022032771292":1478686417166,"1022346036651":1478686804042,"1022346036645":1478686804042,"1022346036646":1478686804042,"1022346036647":1478686804042,"1022346036640":1478686804042,"1022346036641":1478686804042,"1023924431765":1509788624969,"1022346036642":1478686804042,"1022346036643":1478686804042,"1022346036636":1478686804041,"1022457446968":1480585069112,"1000527788307":1444487341756,"1022346036637":1478686804041,"1021469153602":1478686804050,"1022457446969":1480585069112,"1022346036638":1478686804041,"1022346036639":1478686804041,"1020857295583":1478686417227,"1022346036632":1478686804041,"1022346036633":1478686804041,"1022346036634":1478686804041,"1022346036635":1478686804041,"1022346036628":1478686804041,"1022457446960":1480585069112,"1022346036629":1478686804041,"1022346036630":1478686804041,"1022346036631":1478686804041,"1022457446963":1480585069112,"1022346036625":1478686804041,"1022346036626":1478686804041,"1022346036627":1478686804041,"1022457446967":1480585069112,"1022457446954":1480585069112,"1022346036617":1478686804041,"1025627668791":1509788624212,"1022346036618":1478686804041,"1022457446944":1480585069112,"1025627668794":1509788624212,"1022065146560":1478686417174,"1020573127665":1478686417074,"1022457446946":1480585069112,"1022346036615":1478686804041,"1025627668793":1509788624212,"1022457446948":1480585069112,"1025627668798":1509788624212,"1022457446951":1480585069112,"4985890605":1509788624153,"1021470726798":1509788624405,"1024632823298":1509788625008,"1021535737508":1478686417113,"1020945251305":1478686417084,"1020945251307":1478686417084,"1022470291719":1478686417073,"1020148845413":1509788624302,"1008375056682":1478686804023,"1020945251299":1478686417084,"1022457446904":1480585069112,"1025910789058":1509788667579,"1022457446906":1480585069112,"4973438546":1509788624153,"1022457446908":1480585069112,"1025798592660":1509788624420,"1025910789061":1509788667579,"1024461375598":1509788624217,"1022454825417":1478686417297,"1024461375599":1509788624217,"1021860930927":1509788624992,"1022457446900":1480585069112,"1022457446902":1480585069112,"1017143385275":1465470268268,"1022457446888":1480585069111,"1020853494083":1478686417078,"1022457446891":1480585069111,"1024461375602":1509788624217,"1022457446894":1480585069111,"1024461375600":1509788624217,"1022457446895":1480585069112,"1024461375601":1509788624217,"1022457446881":1480585069111,"1022457446883":1480585069111,"1022457446884":1480585069111,"1022457446885":1480585069111,"1022457446886":1480585069111,"1022457446887":1480585069111,"1019384223396":1509788624933,"1022434378619":1480585069096,"1022457446811":1480585069111,"1024735582637":1509788624915,"1022434378620":1480585069097,"1022434378623":1480585069097,"1022457446815":1480585069111,"1022457446804":1480585069111,"1024005170645":1491634246533,"1024005170646":1491634246533,"1776215953":1478686417017,"1022457446792":1480585069111,"225739558":1478686804032,"1022457446794":1480585069111,"1022251928650":1509788624304,"1022457446784":1480585069111,"1015982982136":1478686804046,"1022457446788":1480585069111,"1022384571473":1478686417205,"1021173451809":1465470268184,"1021173451808":1465470268184,"1024735582605":1509788624915,"1021173451814":1465470268185,"1021173451813":1465470268184,"1021173451816":1465470268185,"1022434378683":1480585069097,"1022343677450":1478686417289,"1024735582562":1509788624915,"1022248258754":1478686417196,"1022457446730":1480585069111,"1021769050193":1509788624395,"1022457446720":1480585069111,"1022457446721":1480585069111,"1022457446722":1480585069111,"1022457446723":1480585069111,"1022457446724":1480585069111,"1022457446725":1480585069111,"1000249126152":1478950494932,"1022457446727":1480585069111,"1022434378648":1480585069097,"1022457446777":1480585069111,"1021715311798":1509788624395,"1025214660037":1509788624197,"1022595602745":1509788624384,"1020833833013":1478686416998,"1022457446768":1480585069111,"1025798592538":1509788624534,"1022021892868":1478686417162,"1022434378641":1480585069097,"1022457446771":1480585069111,"1022434378645":1480585069097,"1022434378646":1480585069097,"1022457446774":1480585069111,"1020712462711":1509788624363,"1022434378632":1480585069097,"1022434378633":1480585069097,"1018546792513":1480585069063,"1022434378634":1480585069097,"1022457446762":1480585069111,"1022457446765":1480585069111,"1018599352088":1509788624359,"1022434378638":1480585069097,"1022434378626":1480585069097,"1025798199298":1509788624523,"1022457446757":1480585069111,"1022434378630":1480585069097,"1022457446759":1480585069111,"1024184219660":1509788624551,"1024735582510":1509788624915,"1801774501":1444487341742,"1022443159667":1478686417295,"1019949676432":1509788624386,"1016847945459":1478686804018,"1022457446683":1480585069111,"1021151432567":1509788624933,"1021151432566":1509788624933,"1022434378750":1480585069097,"1022434378751":1480585069097,"1021151432564":1509788624933,"1022457446672":1480585069111,"1801774509":1444487341737,"1006037021273":1478686804049,"1024194443418":1509788625250,"1022457446675":1480585069111,"1021151432568":1509788624933,"1022457446676":1480585069111,"1022457446677":1480585069111,"1022457446678":1480585069111,"1022457446679":1480585069111,"1022439489563":1478686417214,"1022457446665":1480585069111,"1025798592608":1509788624195,"1025497516626":1509788624367,"1022457446671":1480585069111,"1022457446658":1480585069111,"1022457446659":1480585069111,"1022457446660":1480585069111,"1022457446661":1480585069111,"1020883255121":1478686417227,"1022457446662":1480585069111,"1008054844149":1480585069062,"1022147064506":1478686417013,"1021869449766":1478686804026,"1022457446713":1480585069111,"1022434378714":1480585069097,"1022457446714":1480585069111,"1023830191876":1509788667494,"1022434378715":1480585069097,"1022434378716":1480585069097,"1022457446717":1480585069111,"1022434378718":1480585069097,"1022457446718":1480585069111,"1022434378719":1480585069097,"1022457446704":1480585069111,"1022457446706":1480585069111,"1022457446709":1480585069111,"1022434378711":1480585069097,"1022434378696":1480585069097,"1021860930999":1509788624992,"1021985324300":1478686417057,"1022434378703":1480585069097,"1022434378688":1480585069097,"1022434378692":1480585069097,"1022434378693":1480585069097,"1022434378695":1480585069097,"1025584678514":1509788624297,"1025465929062":1509788624349,"1021154446944":1478686417002,"1021906542991":1509788624194,"795254894":1491634246517,"795254893":1491634246517,"1022766394974":1509788625056,"1025605387558":1509788625104,"1010024621543":1491634246521,"1010024621542":1491634246521,"1021965008404":1509788624997,"795254848":1491634246517,"1025772116744":1509788624540,"1022087165688":1478686417179,"1021609923437":1478686417246,"1022224010896":1509788624938,"1021906543032":1509788624817,"1021154446936":1478686417002,"1021618836113":1509788624401,"1022594554051":1480585069074,"1021948362603":1478686417145,"1022470553674":1478686417219,"795254843":1491634246517,"1022065670254":1478686417175,"1017800062482":1478686804016,"1000814447290":1478686804059,"1000814447294":1478686804059,"1025879463079":1509788667669,"1022811483094":1509788624389,"1025879463080":1509788667674,"1022069602200":1509788624943,"1024782374486":1509788625019,"1024735582361":1509788624915,"1024451414409":1509788624957,"1022119539847":1478686417183,"1688005602":1480585069060,"1024194443740":1509788625249,"1024194443741":1509788625249,"1024194443742":1509788625249,"1024194443743":1509788625249,"1022998388744":1509788625049,"1018556230102":1509788624309,"1025607746948":1509788625083,"1021751224943":1509788624395,"1025772116923":1509788624431,"1023881440091":1509788625038,"1019033865324":1509788624388,"1024194443744":1509788625249,"1024194443745":1509788625249,"1024194443746":1509788625249,"1010024621430":1491634246521,"1010024621437":1491634246527,"1019949676161":1509788624386,"1021741525942":1478686417125,"1025473531339":1509788624352,"1022191366252":1478686416976,"1023096568385":1509788625162,"1023096568386":1509788625162,"1023096568387":1509788625162,"1023096568388":1509788625162,"143689594":1444487341720,"1023924431266":1509788624969,"1020654136486":1478686804057,"1025322399461":1509788624309,"887798557":1444487341732,"1022658253881":1509788625074,"1018989563795":1509788624314,"887798551":1444487341726,"1023008088295":1509788624538,"1024763627584":1509788625069,"1021153923437":1478686417300,"1023049376411":1509788624358,"1023049376413":1509788624358,"1023049376414":1509788624358,"1021346733563":1478686417041,"1013564468697":1478686804030,"1022543430822":1509788625064,"1021659598693":1509788624615,"1021659598695":1509788624616,"1021635350271":1478686417049,"1021966180646":1509788624464,"1024434247105":1509788625216,"1021659598700":1509788624616,"1022816728165":1509788625074,"1025815234463":1509788667452,"1021659598697":1509788624616,"1017583139951":1478686804019,"1021659598710":1509788624616,"1021997114143":1478686417265,"1021659598704":1509788624616,"1021774689886":1509788624534,"1021659598706":1509788624616,"1021659598716":1509788624615,"1021659598718":1509788624615,"1021659598713":1509788624616,"1022240920221":1478686417066,"1021537700022":1509788624397,"1025874610762":1509788667581,"1024434247077":1509788625216,"1021283555729":1465469681395,"1020734879781":1509788624959,"1024434247079":1509788625216,"1024434247072":1509788625216,"1025874610765":1509788667581,"1024434247085":1509788625216,"1025033910381":1509788624451,"1024434247087":1509788625216,"1025593858699":1509788624566,"1024434247083":1509788625216,"1024434247094":1509788625217,"1025487426411":1509788624367,"1025033910384":1509788624427,"1024434247090":1509788625216,"1020971197973":1478686417086,"1024434247097":1509788625216,"1020556873053":1478686417017,"1024215935158":1509788625033,"1024434247098":1509788625217,"1024434247099":1509788625216,"1020938429475":1478686416975,"1023846445707":1491634246537,"1023846445702":1491634246520,"1024434247052":1509788625216,"1024244640059":1509788624948,"1022067369840":1478686417012,"1023646680730":1509788624817,"1024434247062":1509788625217,"1024434247063":1509788625217,"1020176111525":1509788624361,"1024434247056":1509788625217,"1020176111524":1509788624361,"1024434247059":1509788625217,"1022177734175":1478686417278,"1024434247068":1509788625216,"1025033910367":1509788624510,"1524681371":1444487341749,"1025033910365":1509788624509,"1024434247064":1509788625217,"1024434247065":1509788625216,"1524681374":1444487341723,"1024434247066":1509788625217,"1024434247067":1509788625216,"1024557980673":1509788624412,"1024557980675":1509788624412,"1023207320459":1509788625043,"1025033910405":1509788624434,"1025033910400":1509788624434,"572175026":1478950494911,"329679628":1509788625019,"1025033910413":1509788624434,"1022164757895":1478686417186,"1025033910408":1509788624434,"1020854157307":1478686416999,"1020928992323":1478686417082,"1021933289383":1509788624195,"1025188307364":1509788624273,"1025530156548":1509788624335,"1025033910431":1509788624456,"1025033910426":1509788624434,"1021769315938":1509788624395,"1025023948899":1509788624974,"1021659598724":1509788624615,"1021659598726":1509788624615,"1022067763156":1509788624183,"1009012342270":1478686804069,"1025593858560":1509788624550,"1021659598722":1509788624615,"1025593858561":1509788625000,"1021659598733":1509788624615,"1021659598732":1509788624615,"1021659598734":1509788624616,"1020799499332":1478686417030,"1023630034234":1491634246515,"1021659598743":1509788624616,"1021659598737":1509788624616,"1021972865644":1478686417150,"1005946971930":1480585069062,"1018947481089":1509788624282,"1018908552110":1509788624930,"5025610620":1514456869764,"1022327428972":1478686417200,"1022469382142":1478686417219,"1024434246885":1509788624497,"1023919978382":1509788624969,"1024434246881":1509788624497,"1021659598413":1509788624564,"1021700371440":1478686804046,"1024434246895":1509788624497,"1022086375672":1478686417062,"1024434246890":1509788624497,"1021986890440":1478686417154,"1024434246900":1509788624497,"1021166244796":1465470268184,"1024434246901":1509788624497,"1024434246902":1509788624497,"1024689178054":1509788624467,"1023919978392":1509788624969,"1023919978393":1509788624969,"1024519576539":1509788625027,"1024434246898":1509788624498,"1024434246899":1509788624497,"1023919978388":1509788624969,"1021659598427":1509788624552,"1023919978386":1509788624969,"1024434246854":1509788624497,"1024434246861":1509788624497,"1024434246856":1509788624497,"1024434246857":1509788624497,"1024434246858":1509788624497,"1024434246868":1509788624497,"1024434246865":1509788624497,"1024154330498":1509788667659,"1021761975316":1478686417127,"1024434246873":1509788624497,"1021761975313":1478686417127,"5025610418":1514456869765,"1022208676295":1478686804066,"550023558":1478686417019,"1021659598356":1509788624552,"1025090796952":1509788624959,"1024434246847":1509788624497,"1024434246840":1509788624497,"1024434246841":1509788624498,"5000313685":1509788667392,"1024434246843":1509788624498,"1022233317463":1478686416976,"1016930391109":1478686804016,"1017955652479":1509788624372,"1025405759340":1509788625020,"1022470430304":1478686417299,"1020556872821":1478686417017,"1022389164721":1478686417205,"1022450245465":1478686417296,"1016847946164":1478686804018,"1021659598541":1509788624564,"1024154330428":1509788667658,"1024434771062":1509788624465,"1024154330430":1509788667659,"1025879984726":1509788667404,"1017828633133":1509788625080,"1022157024317":1478686417185,"1021659598554":1509788624552,"1024723650315":1509788667888,"1022016644524":1509788624867,"1020863455594":1509788625002,"1022069074250":1478686417060,"1021811784094":1478686417131,"1012144814504":1478686417223,"1021156544657":1478686417038,"1024154330469":1509788667658,"1021156544659":1478686417038,"1021156544662":1478686417038,"1020791634649":1478686417077,"1024154330477":1509788667658,"1024154330478":1509788667659,"1024154330475":1509788667659,"1024154330453":1509788667659,"1024154330454":1509788667659,"1021968540444":1509788625068,"1024154330451":1509788667658,"1025910918155":1509788667579,"1024154330463":1509788667659,"1025910918156":1509788667579,"1024154330456":1509788667659,"1025910918157":1509788667579,"1025910918158":1509788667579,"1024154330458":1509788667658,"1022208676195":1478686804066,"1025910918159":1509788667579,"1024154330459":1509788667659,"1024154330438":1509788667659,"1009714890410":1491634246520,"1024154330435":1509788667658,"1012144683413":1478686417073,"1009714890405":1491634246520,"1024999438249":1509788624996,"1024154330441":1509788667658,"1024154330443":1509788667659,"1018993103444":1478686804053,"1025509054454":1509788667537,"1020145178508":1509788624276,"1025509054451":1509788667537,"1023171537700":1509788624254,"1025509054456":1509788667830,"1021989904827":1478686417155,"1018597260227":1509788624171,"1025509054459":1509788667537,"1023171537722":1509788624254,"1024557981334":1509788624412,"1025714963350":1509788625123,"1004789588176":1480585069067,"1025714963349":1509788625114,"1025902661221":1509788667466,"327451032":1444487341726,"1021537700500":1509788624401,"1024557981338":1509788624412,"1022208676526":1478686804066,"1024557981351":1509788624412,"1022318646331":1478686417200,"1024557981346":1509788624412,"1022470816453":1478686804065,"1024557981358":1509788624412,"1000527783646":1444487341712,"1024557981354":1509788624412,"1024557981355":1509788624412,"1025556370739":1509788624341,"1021047220726":1478686417036,"1724052726":1444487341754,"1022005110425":1478686417266,"1023171537692":1509788624254,"1024557981361":1509788624412,"1023171537682":1509788624254,"1024557981374":1509788624412,"1024557981368":1509788624412,"1021409509996":1509788624179,"1024557981381":1509788624412,"1018850749072":1509788625079,"1021409509998":1509788624179,"1023171537771":1509788624254,"1024587996318":1509788624170,"1024557981378":1509788624412,"1023171537775":1509788624254,"1024434247587":1509788624258,"1024434247592":1509788624258,"1020735404594":1478686416984,"1023171537765":1509788624254,"1018993103365":1478686804051,"1018993103364":1478686804051,"1022208676573":1478686804066,"1018993103366":1478686804051,"1021409510014":1509788624178,"1023626626651":1509788624552,"1023171537789":1509788624254,"1018993103363":1478686804051,"1018993103362":1478686804051,"1021409510010":1509788624179,"1021659598098":1509788624552,"1023820624577":1491634246535,"1021409510004":1509788624179,"1021409510006":1509788624179,"1023171537779":1509788624254,"1018805397304":1509788624929,"1021409510003":1509788624179,"1023171537782":1509788624254,"1021409510002":1509788624179,"1024434247556":1509788624258,"1024434247558":1509788624258,"1021659598118":1509788624567,"1024434247552":1509788624258,"1021045385607":1478686417092,"1020863455935":1509788625002,"1023171537743":1509788624254,"1024434247564":1509788624258,"1018404441895":1509788625076,"1024434247566":1509788624258,"4798319722":1509788624155,"1024434247561":1509788624258,"1024434247563":1509788624258,"1024557981419":1509788624412,"1023171537752":1509788624254,"1024557981428":1509788624412,"1001517530496":1444487341754,"1013772753672":1478686804068,"1024557981424":1509788624412,"1023171537758":1509788624254,"1024434247570":1509788624258,"1013772753668":1478686804068,"1024557981436":1509788624412,"1013772753669":1478686804068,"1024434247581":1509788624258,"1013772753670":1478686804068,"1024557981438":1509788624412,"1013772753671":1478686804068,"1023171537747":1509788624254,"1024557981439":1509788624412,"1022470816402":1478686804065,"1013772753666":1478686804068,"1013772753667":1478686804068,"1022478156317":1478943089487,"1005686273531":1478686804054,"1023171537835":1509788624893,"1022492312352":1478943089316,"1023171537837":1509788624893,"1025593858126":1509788624213,"5025609989":1514456869765,"1021933288860":1509788624819,"597078300":1478686417019,"1024434247534":1509788624258,"1016799309713":1478686804032,"1022208676359":1478686804066,"1023171537831":1509788624893,"1022001571447":1478686417265,"1025593858134":1509788624213,"1024434247540":1509788624258,"1023171537848":1509788624893,"1023171537849":1509788624893,"1024434247543":1509788624258,"1024434247536":1509788624258,"1025593858131":1509788624213,"1024434247537":1509788624258,"1024434247538":1509788624258,"1023171537854":1509788624893,"1025593858129":1509788624213,"1024434247539":1509788624258,"1024434247548":1509788624258,"1023171537840":1509788624893,"1024434247551":1509788624258,"1023171537844":1509788624893,"1024434247545":1509788624258,"1020863455812":1509788625002,"1021822794513":1478686417133,"1024434247546":1509788624258,"1024434247492":1509788624262,"1021409510028":1509788624179,"1021409510025":1509788624179,"1021409510024":1509788624178,"1024434247489":1509788624262,"1024557981217":1509788624412,"1022474617460":1478943089315,"1021573089483":1509788624388,"1024557981218":1509788624412,"1024434247491":1509788624262,"1024557981219":1509788624412,"1021409510021":1509788624178,"1021409510022":1509788624178,"1024557981231":1509788624412,"1023171537796":1509788624254,"1024557981224":1509788624412,"1021409510016":1509788624178,"1024434247497":1509788624262,"1021409510019":1509788624178,"1024434247498":1509788624262,"1024557981226":1509788624412,"1022471209545":1478686417219,"1024434247499":1509788624262,"1024557981239":1509788624412,"1021659598326":1509788624564,"1024557981234":1509788624412,"1024557981244":1509788624412,"1016799309735":1478686804032,"1024434247460":1509788624262,"1024557981253":1509788624412,"1024434247456":1509788624262,"1024557981249":1509788624412,"1024434247458":1509788624262,"1024557981250":1509788624412,"1023310221346":1509788624847,"1021260223997":1478686417040,"1023171537891":1509788624893,"1024434247464":1509788624262,"1022490477326":1478943089490,"1024434247479":1509788624262,"1021475964557":1478686417242,"1023171537918":1509788624893,"1024434247475":1509788624262,"1024557981276":1509788624412,"1024434247485":1509788624262,"1019212390398":1509788624316,"1024557981277":1509788624412,"1024557981278":1509788624412,"1024225241760":1509788624556,"1024434247480":1509788624262,"1024225241766":1509788624556,"1024434247481":1509788624262,"1024557981273":1509788624412,"1024225241764":1509788624217,"1019680717753":1509788624317,"1024225241754":1509788624556,"1024225241755":1509788624217,"1021484615478":1509788624402,"1024557981280":1509788624412,"1024225241758":1509788624556,"1024225241759":1509788624556,"1023171537869":1509788624893,"1024225241756":1509788624217,"1024225241757":1509788624217,"1024557981283":1509788624412,"1023171537871":1509788624893,"1024557981292":1509788624412,"1023171537856":1509788624893,"1024434247437":1509788624262,"1023171537857":1509788624893,"1012769120191":1478686417224,"1025505384167":1509788624336,"1023171537859":1509788624893,"920429616":1491634246517,"1021620801368":1478686416992,"1024225241751":1509788624217,"1024434247434":1509788624262,"1023171537863":1509788624893,"1022777143365":1509788625074,"1024557981300":1509788624412,"1024557981301":1509788624412,"1024434247447":1509788624262,"1024557981296":1509788624412,"1024557981297":1509788624412,"1024434247442":1509788624262,"1024557981298":1509788624412,"1023171537873":1509788624893,"1024434247448":1509788624262,"1024434247449":1509788624262,"1024434247451":1509788624262,"1023064711302":1509788624217,"1023064711303":1509788624217,"1023064711300":1509788624217,"1022483530537":1478943089531,"1023064711301":1509788624217,"1010024626634":1491634246527,"1023064711305":1509788624217,"1024212657194":1509788624575,"5025609885":1514456869765,"1023049376129":1509788624357,"1023049376130":1509788624357,"1023049376131":1509788624357,"1023049376132":1509788624357,"1024212657198":1509788624575,"1025322396161":1509788624305,"1023049376133":1509788624357,"1024212657199":1509788624575,"1021984268537":1478686417152,"1023049376134":1509788624358,"1023049376135":1509788624358,"1024212657184":1509788624575,"1025289102347":1509788624311,"1025874348309":1509788667833,"1022470816752":1478686804065,"1024212657189":1509788624575,"1022018217668":1478686417160,"1024212657177":1509788624575,"1022018217667":1478686417160,"1019355907475":1509788624313,"1024212657181":1509788624575,"1021659597922":1509788624849,"915449276":1491634246505,"1524681166":1444487341737,"1025513772707":1509788624427,"1023005735995":1509788624462,"1024913977981":1509788667845,"1025593858558":1509788625000,"1023496478451":1509788624363,"1025593858556":1509788624550,"1025593858557":1509788625000,"1025593858555":1509788624550,"1025593858553":1509788625000,"1024255912377":1509788667496,"1021919001778":1509788624921,"1025714963148":1509788624822,"1025714963149":1509788624616,"1021919001776":1509788624921,"1021919001780":1509788624921,"1024557981644":1509788624411,"1024557981643":1509788624411,"1020505098596":1478686804031,"1024557981653":1509788624411,"1025779320460":1509788624294,"1024557981649":1509788624411,"1021919001766":1509788624921,"1021919001771":1509788624921,"1021919001773":1509788624921,"1020005641886":1480585069151,"1025767131121":1509788624866,"1021919001744":1509788624921,"1021937869751":1478686804072,"1021937869750":1478686804072,"1021919001750":1509788624921,"1021937869749":1478686804072,"1024557981666":1509788624411,"1021919001748":1509788624921,"1021937869755":1478686804072,"1022125172972":1478686417183,"1021594323008":1509788624405,"1024557981677":1509788624411,"1022490477228":1478943089490,"1024557981674":1509788624411,"1024557981675":1509788624411,"1021919001756":1509788624921,"1022985551153":1509788625073,"1021919001731":1509788624921,"1024557981685":1509788624411,"1025699103729":1509788667576,"1024557981687":1509788624411,"1021919001728":1509788624921,"1021722783991":1478686417051,"1021919001733":1509788624921,"1021919001739":1509788624921,"1022780944873":1509788624194,"1021919001737":1509788624921,"1024557981688":1509788624411,"1024557981689":1509788624411,"1013772753660":1478686804068,"1021919001715":1509788624921,"1024557981445":1509788624412,"1024557981446":1509788624412,"1021299939670":1480585069071,"1024557981440":1509788624412,"1013772753657":1478686804068,"1024557981442":1509788624412,"1013772753652":1478686804068,"1021919001722":1509788624921,"1013772753648":1478686804068,"1024557981448":1509788624412,"1024557981449":1509788624412,"1021919001725":1509788624921,"1013772753644":1478686804068,"1021919001700":1509788624921,"1013772753639":1478686804068,"1021919001704":1509788624921,"1024632554415":1509788667473,"1013772753634":1478686804068,"1024557981476":1509788624411,"1013772753629":1478686804068,"1024597695879":1509788624937,"1024557981479":1509788624411,"1024557981473":1509788624411,"1021958316605":1478686417147,"1024557981484":1509788624411,"1024557981485":1509788624411,"1024557981486":1509788624411,"1024736101451":1509788625020,"1024557981482":1509788624411,"1024557981483":1509788624411,"1024557981495":1509788624411,"1021958316591":1478686417147,"1024557981488":1509788624411,"1024557981490":1509788624411,"1024557981496":1509788624411,"1021700501812":1478686804032,"1022346304444":1478686417202,"1021262058719":1478686804035,"1021262058718":1478686804035,"1021262058717":1478686804035,"1017894038546":1478686804053,"1022249046510":1478686417196,"1017894038545":1478686804053,"1023171537636":1509788624254,"1025620728032":1509788624946,"1025620728033":1509788624933,"1022672539433":1509788625019,"4997167636":1509788667392,"1021958316619":1478686417147,"1021886496274":1478686417054,"1021958316618":1478686417147,"1018089216484":1478686804026,"1024313192173":1509788624927,"1025908297689":1509788667448,"1021958316617":1478686417147,"1016847422442":1478686804018,"1021958316623":1478686417147,"1023171537661":1509788624254,"1021958316614":1478686417147,"1001959381593":1478686417023,"1024313192148":1509788624927,"1017063956155":1478686804032,"1024313192144":1509788624927,"1017063956157":1478686804023,"1021958316651":1478686417147,"1022470816540":1478686804039,"1024212657355":1509788624575,"1023171537626":1509788624254,"1017063956135":1478686804032,"1021588031601":1478686417246,"1021271104404":1478686417237,"1021262058722":1478686804035,"1021262058721":1478686804035,"1021958316640":1478686417147,"1021262058720":1478686804035,"1021588031605":1478686417246,"1021294828812":1478686417238,"1021811784775":1478686417131,"1021848878604":1509788624993,"1025783120271":1509788624999,"1022183369240":1478686417187,"1712648756":1444487341735,"1021545040922":1478686417245,"1023820625085":1491634246535,"1004873212882":1444487341757,"1025767129279":1509788624565,"1009775579009":1478686804025,"1023444049616":1509788624970,"1021985712072":1478686417153,"1022292300275":1478686804071,"1022457453469":1480585069112,"1010093832943":1491634246528,"1025299983366":1509788624297,"602847163":1444487341742,"1020962939546":1478686417001,"1021700372135":1478686804046,"1009965249064":1491634246523,"1021014715830":1478686416987,"1020160774864":1465470268316,"1021767873182":1509788624395,"4798319220":1509788624155,"1020806051922":1478686417030,"1024144369499":1509788624276,"1019931454519":1509788624312,"1021283425622":1465469681395,"1024225242352":1509788624445,"1021028478572":1478686417091,"1024225242353":1509788625149,"1024225242346":1509788624445,"1024225242347":1509788624445,"1024225242345":1509788624445,"1024225242350":1509788625149,"1024225242351":1509788624852,"1024225242348":1509788625149,"1022986992319":1509788624175,"1024225242349":1509788625149,"1022169475704":1509788624924,"1024225242337":1509788624445,"1020863456322":1509788625002,"1024225242342":1509788624852,"1024225242343":1509788624852,"1024225242340":1509788625149,"1024225242341":1509788624852,"1024225242335":1509788624852,"1023254506227":1509788625021,"1021011438935":1478686417035,"1012407086207":1478686417074,"713604682":1444487341701,"1001959382340":1478686417023,"1022879120499":1509788625052,"1020556872140":1478686417017,"1021163099688":1478686417234,"1020007606538":1478686804065,"1022481826972":1478943089315,"1021163099684":1478686417234,"1018888367692":1509788624930,"1024785518025":1509788624467,"1012144684172":1478686417073,"1012225030488":1478686804028,"1022986992331":1509788624175,"1022986992325":1509788624175,"1025090795571":1509788624959,"1983570750":1444487341722,"1024206889620":1509788625033,"1983570749":1444487341736,"1024934426428":1509788624402,"1022273294809":1478686417285,"1021968017398":1478686417149,"1023171537977":1509788625206,"1022062125657":1478686417060,"1025900562829":1509788667472,"1023171537980":1509788625206,"1023171537982":1509788625205,"1022062125650":1478686417060,"1023171537969":1509788625205,"1012435790865":1478686417074,"1021492084827":1478686417111,"1001959382171":1478686417023,"1022062125653":1478686417060,"1023171537975":1509788625206,"1025883918012":1509788667406,"1001517529808":1444487341750,"1025883918013":1509788667405,"1025188308016":1509788624273,"1025883918014":1509788667403,"1011851985624":1444487341758,"1025883918004":1509788667406,"1025883918006":1509788667440,"1023171537926":1509788624893,"1021932894762":1478686417055,"1010812243143":1509788624277,"1021815192885":1509788624403,"1024752487899":1509788667502,"1021956220035":1478686417147,"1010812243145":1509788624277,"1012795333276":1478686416995,"1010812243144":1509788624277,"1022321529550":1478686417015,"1010093833187":1491634246528,"1023171538017":1509788625205,"1020810115232":1478686417077,"1023171538021":1509788625206,"1025068908387":1509788624307,"1025068908388":1509788624307,"1023171538044":1509788625206,"1025068908389":1509788624307,"1022451161954":1478686417296,"1025068908399":1509788624307,"1023171537992":1509788625205,"1023171537996":1509788625205,"1023171537998":1509788625205,"1025068908375":1509788624307,"1023171537999":1509788625205,"1023171537988":1509788625206,"1023171537989":1509788625205,"1024998781744":1509788625020,"1846999929":1444487341740,"1023171538011":1509788625205,"1025068908359":1509788624307,"1019273594084":1509788624315,"1023171538001":1509788625205,"1023171538003":1509788625205,"1025068908364":1509788624307,"1023171538006":1509788625205,"1025068908367":1509788624295,"1021972866852":1478686417150,"1021429171361":1509788624827,"1025120942259":1509788624330,"1021700372305":1478686804046,"1022379859914":1478686417205,"1021008555396":1478686417231,"1025880510051":1509788667465,"1024806620775":1509788624816,"1016506366417":1509788624976,"1001959382082":1478686417023,"1021933288157":1509788624535,"1022065664742":1478686417174,"1020556871897":1478686417017,"1016710311327":1478686804051,"1016710311329":1478686804051,"1021755813989":1478686417051,"1021755813991":1478686417051,"1015327552302":1478686804058,"1022472128251":1478943089531,"1025551389003":1509788624341,"1021545041463":1478686417245,"1023531997621":1509788625039,"1025533562978":1509788625083,"1022257960354":1478686417067,"1022697179981":1509788625015,"1024778571606":1509788624441,"1022697179975":1509788625016,"1025629379201":1509788625087,"1022697179972":1509788625016,"1024778571598":1509788624452,"1020116735337":1509788625076,"1025645370348":1509788624428,"1024778571590":1509788624434,"1025645370349":1509788624431,"1022697179991":1509788625015,"1025645370350":1509788624425,"1025645370351":1509788624406,"1024778571587":1509788624440,"1020956779368":1478686417033,"1021886626719":1509788624465,"1022697179949":1509788625015,"1020556872519":1478686417017,"1020924011897":1478686417082,"1024806620564":1509788625100,"1024778571575":1509788624430,"1023725325420":1491634246523,"1020978667953":1478686417087,"1024806620573":1509788624533,"1025900563153":1509788667474,"1021395360081":1478686417240,"1020956779379":1478686417033,"1021982696541":1478686417152,"1022697179953":1509788625016,"1025900563190":1509788667474,"1022921587815":1509788624298,"1024927085812":1509788624182,"1022697179932":1509788625016,"1023934001571":1491634246529,"1024927085820":1509788624182,"1022697179926":1509788625016,"1024927085821":1509788624182,"1024927085823":1509788624182,"1020562376915":1509788624320,"1024927085818":1509788624182,"1022697179920":1509788625016,"1016399540302":1480585069069,"338461357":1444487341741,"1020723868039":1478686416996,"1023995608199":1491634246532,"1024806620483":1509788624194,"1017973216667":1509788624924,"1021955565368":1509788624464,"1023150960381":1509788624978,"1019375698377":1509788625076,"1025062878406":1509788624294,"1021262057904":1478686804065,"1019375698375":1509788625077,"1019674165117":1509788625076,"1019674165118":1509788625076,"1023820625494":1491634246535,"1024352589324":1509788624178,"1019375698363":1509788625076,"1025394223231":1509788624972,"1025629379195":1509788625114,"1025629379196":1509788625123,"1025629379197":1509788625107,"1012225031014":1478686804028,"1025585471406":1509788624351,"1025033256635":1509788624602,"1025516262283":1509788624337,"1024672793948":1509788624435,"1010024496185":1491634246526,"1010024496184":1491634246526,"1010024496187":1491634246521,"1010024496186":1491634246521,"1019167694132":1509788624287,"1019167694128":1509788624287,"1019167694131":1509788624287,"1019167694130":1509788624287,"1024557980549":1509788624414,"1024557980545":1509788624414,"1025703167815":1509788624828,"1024557980556":1509788624414,"1024557980557":1509788624414,"1025703167819":1509788624745,"1024557980559":1509788624414,"1024557980552":1509788624413,"1024557980554":1509788624413,"1024557980560":1509788624414,"1024856295878":1509788624949,"1024557980582":1509788624411,"1019931193196":1509788624373,"1024557980579":1509788624411,"1024557980590":1509788624411,"1024557980586":1509788624411,"1024557980596":1509788624411,"1021809557319":1509788624399,"1024557980599":1509788624411,"1024557980593":1509788624411,"1024557980595":1509788624411,"1021075532555":1478686417093,"1024557980603":1509788624411,"1021127436381":1478686417095,"1024557980612":1509788624411,"1023637766717":1509788624170,"1024557980608":1509788624411,"1024557980611":1509788624411,"1021631941025":1478686417119,"1021631941024":1478686417119,"1022511318477":1480585069126,"1021955172088":1509788624466,"1024332720456":1509788625032,"1024557980639":1509788624411,"1000497898983":1478686416993,"1022354955924":1509788624928,"1024557980645":1509788624412,"1024557980647":1509788624412,"1024557980642":1509788624412,"1024557980650":1509788624412,"1024557980658":1509788624412,"1024557980659":1509788624411,"1024557980668":1509788624411,"1024557980669":1509788624411,"1024557980671":1509788624411,"1020663051218":1478686804039,"1020662919981":1478686804027,"1024927085828":1509788624182,"1025900563231":1509788667474,"1025703167936":1509788624200,"1025703167942":1509788624186,"1024927085826":1509788624182,"1022052163685":1509788625066,"1025901874156":1509788667791,"1024927085827":1509788624182,"1022161218284":1478686417301,"1025900563208":1509788667474,"1003975497444":1478950494937,"1020556872347":1478686417017,"1024557980446":1509788624413,"1024961295111":1509788624970,"1024557980442":1509788624413,"1024557980443":1509788624413,"1021795659912":1509788624394,"1025629379337":1509788624540,"1025629379338":1509788624542,"1025629379339":1509788624537,"1025629379340":1509788624523,"1024557980451":1509788624413,"1025900563257":1509788667474,"1024557980463":1509788624413,"1024557980458":1509788624413,"1022511318321":1480585069126,"1024557980471":1509788624413,"1024205840438":1509788625033,"1024557980473":1509788624413,"1024557980475":1509788624413,"1024557980485":1509788624413,"1024557980482":1509788624413,"1001517529146":1444487341755,"1023217281957":1509788624336,"1025900563285":1509788667474,"318014756":1480585069064,"318014752":1480585069064,"318014753":1480585069064,"318014754":1480585069064,"318014755":1480585069064,"1013015661383":1478686417026,"1016569800516":1465470268266,"1022390869049":1478686417015,"1024557980525":1509788624413,"1023526230511":1509788624388,"1024557980527":1509788624414,"1022860767299":1509788624378,"1022285878269":1478686417198,"1024557980532":1509788624414,"1024557980535":1509788624414,"1023217281944":1509788624342,"1021832098077":1478686804064,"1024687869126":1509788624491,"1019023252072":1480585069072,"1024687869127":1509788624491,"1022631117183":1509788625061,"1024687869124":1509788624491,"1021627745579":1478686417247,"1024687869122":1509788624491,"1021381466111":1478686417006,"1024687869121":1509788624491,"1021627745575":1478686417247,"1022395061145":1478686417206,"1024687869133":1509788624491,"1024687869131":1509788624491,"1024687869128":1509788624491,"1024687869129":1509788624491,"1024687869140":1509788624491,"1024687869141":1509788624491,"1023988789896":1509788625036,"1022237252326":1478686417065,"1024673188742":1509788624854,"1024673188740":1509788624855,"1024673188741":1509788624855,"1021736942732":1478686417024,"1024673188739":1509788624854,"1025349264211":1504776656205,"1023734891422":1509788624932,"1024673188744":1509788624854,"1016357469047":1465470268254,"1020703817318":1478686416996,"1022921585202":1509788624292,"1021046039494":1478686417232,"1024434249124":1509788624596,"1012128563002":1478686417073,"1024434249125":1509788624596,"1024434249127":1509788624596,"1021815189575":1478686804046,"1019655811217":1509788624316,"1024434249120":1509788624596,"1024434249122":1509788624596,"1024434249123":1509788624596,"1024434249132":1509788624596,"1024434249133":1509788624596,"1024434249134":1509788624596,"1021614113876":1478686417116,"1024434249135":1509788624595,"1024434249130":1509788624596,"1021736942841":1478686417251,"1021736942840":1478686417251,"1019208455474":1480585069068,"1024673188855":1509788624558,"1024673188852":1509788624558,"1024673188853":1509788624558,"1024673188850":1509788624558,"1024673188851":1509788624558,"1024434249137":1509788624596,"1021736942833":1478686417251,"1021736942832":1478686417251,"1021736942835":1478686417251,"1021736942834":1478686417251,"1021736942837":1478686417251,"1021736942836":1478686417251,"1021702208129":1478686417122,"1021736942839":1478686417251,"1021736942838":1478686417251,"1015291641003":1480585069068,"1018335101199":1478686804022,"1021167164097":1478686804064,"1024673188814":1509788624219,"1024673188812":1509788624219,"1024673188810":1509788624219,"1024673188811":1509788624219,"1024673188808":1509788624219,"1024434249108":1509788624596,"1025907115082":1509788667463,"1024687869111":1509788624491,"1024687869108":1509788624491,"1024434249110":1509788624596,"1021763812672":1478686417127,"1010002735172":1491634246525,"1024434249105":1509788624595,"1024687869104":1509788624491,"1024434249106":1509788624596,"1024434249107":1509788624596,"1024687869118":1509788624491,"1024434249116":1509788624596,"1024434249118":1509788624596,"1025009139677":1509788624330,"1024434249113":1509788624596,"1010001948763":1491634246518,"1024434249114":1509788624596,"1021239778864":1480585069071,"1024687869113":1509788624491,"1024434249115":1509788624596,"1022953043025":1509788624610,"1021087196651":1478686417094,"1021815189646":1478686804046,"1022700717526":1509788624973,"1016862890424":1478686804016,"1022215362751":1478686417191,"1024781582798":1509788625020,"1024434249031":1509788624595,"1024434249027":1509788624595,"1021702208119":1478686417122,"1024434249036":1509788624595,"1019365478061":1509788624313,"1024434249039":1509788624595,"1025703168238":1509788625124,"1024434249033":1509788624595,"1024434249035":1509788624595,"1020871977195":1478686417031,"1024434249044":1509788624595,"1020556871090":1478686417017,"1024434249045":1509788624595,"1024434249046":1509788624595,"1024434249047":1509788624595,"1024434249040":1509788624595,"1260573591":1478686804029,"1024434249041":1509788624595,"1024434249042":1509788624595,"1014828945616":1478686804023,"1024434249052":1509788624595,"1024434249053":1509788624595,"1024434249055":1509788624595,"1024244638185":1509788624949,"1024434249048":1509788624595,"1024434249050":1509788624595,"1019426947782":1480585069091,"1024434249051":1509788624595,"1021354595668":1465470268233,"1019824106094":1509788625079,"1025616139093":1509788624929,"1021244497611":1478686417100,"1020879186180":1478686417227,"1021244497621":1478686417100,"1024434249014":1509788624595,"1021815189722":1478686804046,"1024434249022":1509788624595,"1024434248964":1509788624594,"1024434248967":1509788624594,"1024434248960":1509788624594,"1012799657885":1478686417026,"1022184810226":1478686417063,"1024434248974":1509788624594,"1024434248969":1509788624594,"1024434248970":1509788624594,"1024434248971":1509788624594,"1024434248980":1509788624594,"1024434248981":1509788624594,"1024434248982":1509788624594,"1024434248976":1509788624594,"1024434248977":1509788624594,"1024434248979":1509788624594,"1024412228526":1509788624462,"1017133156400":1478686804016,"1025447581855":1509788624369,"1024434248948":1509788624594,"1024434248949":1509788624595,"1024434248951":1509788624594,"379490186":1444487341702,"1024434248945":1509788624594,"1021504802708":1478686417047,"1022065667625":1478686417174,"1024434248957":1509788624594,"379490180":1444487341702,"1024434248958":1509788624594,"1024434248952":1509788624594,"1024434248954":1509788624594,"1024434248955":1509788624594,"1024785383479":1509788624481,"1024785383476":1509788624481,"1024785383486":1509788624480,"1024785383485":1509788624481,"1024785383483":1509788624481,"1024785383481":1509788624481,"1024785383463":1509788624480,"1022244068263":1478686417283,"1024785383469":1509788624481,"1024785383467":1509788624481,"1024785383464":1509788624481,"1024673188582":1509788624444,"1024673188583":1509788624444,"1944251046":1444487341719,"1024785383519":1509788624481,"1024785383516":1509788624481,"1024673188586":1509788624444,"1024673188584":1509788624444,"1024673188585":1509788624444,"1022125695692":1478686417276,"1024785383495":1509788624480,"1024785383492":1509788624481,"1024785383493":1509788624480,"1024785383488":1509788624480,"1024785383489":1509788624480,"1024785383497":1509788624480,"1019524348384":1509788624315,"1024667814758":1509788625213,"1024785383529":1509788624481,"1021208321449":1478686804027,"1024785383583":1509788624584,"1024785383578":1509788624584,"1014828945894":1478686804028,"1025890861730":1509788667404,"1021622633484":1478686417008,"1025890861736":1509788667404,"1021224836296":1478686417099,"1025890861741":1509788667404,"1022197524213":1478686417189,"1024785383606":1509788624584,"1016357468911":1465470268254,"1024785383602":1509788624584,"1024785383600":1509788624584,"1024785383614":1509788624584,"1024785383615":1509788624584,"1021646096284":1509788625084,"1024785383610":1509788624584,"1024785383611":1509788624584,"4986679435":1509788624156,"1016399675259":1480585069069,"1021037257671":1478686417092,"1024735317934":1509788667494,"1024785383593":1509788624584,"1024785383638":1509788624584,"1020869749176":1478686417227,"1025394091887":1509788667826,"1024785383636":1509788624584,"1021906155379":1478686417139,"1025412834932":1509788624442,"1025412834933":1509788624442,"1021221952697":1478686417038,"1025412834934":1509788624442,"1024785383632":1509788624584,"1025412834935":1509788624442,"1024785383646":1509788624584,"1022066454223":1478686417175,"1021545038322":1478686417245,"1025412834939":1509788624442,"1024785383643":1509788624584,"1024785383640":1509788624584,"1024785383620":1509788624584,"1020117523076":1465470268242,"1021244235731":1478686417100,"1024785383630":1509788624584,"1024785383629":1509788624584,"1024785383627":1509788624584,"1024785383625":1509788624584,"379490174":1444487341702,"1021695391938":1509788624404,"1020915100226":1478686417227,"919646007":1478686804024,"1022472522011":1478943089486,"1019823188789":1509788624354,"1025714964605":1509788624565,"1021515288090":1509788624401,"1016473990017":1478686804022,"1025628198603":1509788624430,"1018364723642":1509788624172,"1021167163575":1478686804065,"1025712737224":1509788624308,"1025078604167":1509788624292,"1020940791324":1478686417084,"1024798097526":1509788624473,"1009785536807":1478686804025,"735228410":1478950494915,"707964956":1444487341708,"1025712737256":1509788624307,"1015291641549":1480585069068,"1016301632158":1480585069066,"1020556871484":1478686417017,"1024687869574":1509788624901,"1024565057146":1509788667890,"1025516527393":1509788624343,"1024687869570":1509788624901,"1024687869571":1509788624900,"1019868278343":1478686804065,"1024687869582":1509788624901,"1021290500876":1478686417102,"1024687869583":1509788624901,"1016942844964":1465470268267,"1024687869576":1509788624901,"1025048982286":1509788625017,"1025048982291":1509788625017,"1024687869584":1509788624901,"1024687869585":1509788624901,"1025879458200":1509788667912,"1022986990705":1509788624175,"1022986990706":1509788624175,"1025879458202":1509788667909,"1022986990707":1509788624175,"1022986990708":1509788624175,"1022986990709":1509788624175,"1022986990710":1509788624175,"1022270414494":1480585069093,"1021446867061":1509788624399,"1022270414491":1480585069093,"1020150161205":1478686804021,"1022270414486":1480585069093,"1022270414487":1480585069093,"1022270414485":1480585069093,"1022270414483":1480585069093,"1025412834752":1509788624857,"1025412834753":1509788624858,"1023711822693":1509788624997,"1025412834754":1509788624858,"1020294206680":1465470268297,"1025412834755":1509788624858,"1025412834756":1509788624857,"1021100696768":1478686417095,"1022242625777":1478686417195,"1000526081680":1444487341714,"1000526081684":1444487341713,"1021872338628":1478686417257,"1025862942813":1509788667488,"1025862942814":1509788667488,"1025862942815":1509788667488,"1025712737108":1509788624306,"1872950585":1478686417021,"1017869395955":1509788624286,"1025412834577":1509788624561,"1025412834578":1509788624561,"1023807899129":1509788624206,"1025412834579":1509788624561,"1025412834581":1509788624561,"1024687869551":1509788624901,"1024687869549":1509788624900,"1021900649563":1478686417139,"1024687869558":1509788624900,"1024687869559":1509788624901,"1017869395937":1509788624284,"1024687869557":1509788624901,"1024687869554":1509788624901,"1025879982444":1509788667404,"1021762895752":1478686417127,"1024687869553":1509788624901,"1024687869566":1509788624901,"1025862942821":1509788667488,"627097562":1478686804024,"1025862942822":1509788667488,"1024687869562":1509788624901,"1025862942816":1509788667488,"1744764227":1491634246518,"1025862942817":1509788667488,"1025412834575":1509788624560,"1025862942819":1509788667488,"1021493399534":1509788624515,"1868887486":1444487341755,"1025412834666":1509788624221,"1025412834668":1509788624221,"1021700372518":1478686804046,"1025412834669":1509788624221,"1023646682155":1509788624419,"1025412834670":1509788624221,"1020571419902":1478686417026,"1025412834671":1509788624221,"1872950599":1478686417021,"1022453257470":1478686417215,"1020636838061":1478686416995,"1025712868187":1509788624345,"1022775834663":1509788624462,"1025712737070":1509788624306,"1025712736977":1509788624307,"1025412834483":1509788625155,"1025412834484":1509788625155,"1025412834485":1509788625155,"1021860802637":1509788624402,"1025412834486":1509788625155,"1025412834488":1509788625155,"1025879458004":1509788667596,"1020241121489":1478686804065,"1019230344471":1509788624367,"1022238693867":1509788624947,"1022238693871":1509788624941,"1022238693869":1509788624932,"1022238693874":1509788624931,"1022238693875":1509788624931,"1022238693873":1509788624931,"1868887122":1444487341756,"1022467281941":1478686417218,"1022195557455":1478686417189,"1025153315894":1509788625007,"1018364723432":1509788624172,"1023830457007":1509788625006,"1021442541825":1478686417107,"1018509441116":1509788624426,"1025230778172":1509788625007,"1024798097716":1509788624472,"1024798097718":1509788624472,"1024798097712":1509788624472,"1024798097713":1509788624472,"1024798097714":1509788624472,"1024798097720":1509788624472,"1022472522655":1478943089486,"1022028705332":1478686417267,"1016092297292":1509788624941,"1025712736934":1509788624309,"1022353118058":1478686417203,"1024798097711":1509788624472,"1023239431745":1509788625042,"1025879457858":1509788667408,"1021631547026":1478686417119,"1022310391058":1478686417200,"1004731004382":1478686804041,"1019148947831":1509788624366,"1025015561413":1509788624408,"1022038666544":1478686417168,"1025015561408":1509788624432,"1025015561409":1509788624426,"1004731004395":1478686804052,"1022192411685":1478686417279,"1004731004393":1478686804052,"1004731004392":1478686804052,"1025009138691":1509788624287,"1004731004398":1478686804052,"1004731004397":1478686804052,"1025818905818":1509788667443,"1004731004387":1478686804041,"1004731004386":1478686804041,"1004731004384":1478686804041,"1004731004391":1478686804041,"1004731004389":1478686804041,"1004731004411":1478686804052,"1004731004410":1478686804052,"1016299273077":1480585069062,"1004731004409":1478686804052,"1004731004408":1478686804052,"1024687214404":1509788625083,"1004731004403":1478686804052,"1004731004401":1478686804052,"548190992":1444487341738,"1004731004407":1478686804052,"1020573124022":1478686417074,"1022501489285":1509788624538,"1004731004405":1478686804052,"1004731004404":1478686804052,"1024687869702":1509788624590,"4997165599":1509788667392,"1022414329743":1478686417208,"1024687869699":1509788624590,"1024687869696":1509788624590,"1024966410219":1509788624419,"1024687869710":1509788624590,"1024687869711":1509788624590,"1024687869708":1509788624590,"1024687869709":1509788624590,"1024687869706":1509788624590,"1024687869707":1509788624590,"1024687869704":1509788624590,"1024687869718":1509788624590,"1022766660248":1509788624994,"1022766660249":1509788624994,"1024687869715":1509788624590,"1024687869712":1509788624590,"1022766660252":1509788624994,"1024687869713":1509788624590,"1022766660253":1509788624994,"1022501489377":1509788624538,"1024687869720":1509788624590,"1022766660266":1509788624994,"1025015561407":1509788624429,"1022766660269":1509788624994,"1020393033514":1465470268258,"1018364723271":1509788624172,"1021490515599":1509788624405,"1021327331535":1478686417005,"1025629378384":1509788624828,"1022766660274":1509788624994,"1021561029340":1509788624397,"1025629378385":1509788624832,"1025629378386":1509788624822,"1021565485341":1478686417114,"1025629378388":1509788624746,"1024434248164":1509788624903,"1024510006626":1509788667550,"1025672106559":1509788624942,"1024510006627":1509788667550,"1025796360913":1509788624274,"1010024494789":1491634246521,"1010024494788":1491634246526,"1010024494790":1491634246526,"1025784301927":1509788624349,"1024434248169":1509788624903,"1021848876563":1509788624993,"1021848876562":1509788624994,"1024434248180":1509788624903,"1024434248182":1509788624903,"1021246200826":1478686417100,"1020015993161":1465470268276,"1024434248177":1509788624903,"1024434248190":1509788624903,"1024434248184":1509788624902,"1022501489959":1509788624538,"1024445258111":1509788624830,"1008662758451":1478686804030,"1020771055224":1478686417076,"1024434248143":1509788624902,"1021369930425":1478686804031,"1024434248148":1509788624903,"1024434248144":1509788624903,"1024434248159":1509788624903,"1024434248152":1509788624903,"1024434248153":1509788624903,"1024434248154":1509788624903,"1024434248155":1509788624903,"1024680136474":1509788625070,"1003661963855":1478686417299,"1021485140450":1509788624402,"1022321662893":1478686417288,"1022321662894":1478686417288,"1022109837047":1478686417182,"1021385921490":1478686417042,"1023947633804":1491634246529,"1009744381427":1491634246512,"1023947633803":1491634246529,"1010024494781":1491634246526,"1020970150653":1478686417086,"1020803166449":1509788625230,"1024062583437":1509788624326,"1020803166448":1509788625230,"1020803166451":1509788625230,"1020616391956":1478686416980,"1020803166450":1509788625230,"1025531075074":1509788624336,"1020803166455":1509788625229,"1022079558869":1478686417178,"1020803166457":1509788625229,"1020803166456":1509788625229,"1020803166459":1509788625230,"1020803166458":1509788625229,"1020803166461":1509788625230,"1020803166460":1509788625230,"1020803166463":1509788625230,"1024732957369":1509788625081,"1020803166462":1509788625230,"1025508268400":1509788624340,"1025508268401":1509788624339,"1024117501524":1509788624186,"1024117501525":1509788624186,"1025672106664":1509788624942,"1022264909767":1478686417067,"1023336570852":1509788625072,"1008849025121":1478686804064,"1020803166444":1509788625230,"1020803166446":1509788625230,"1021385921304":1478686417042,"1022296103362":1478686417199,"1025679708944":1509788624349,"1025585731067":1509788624352,"1025585731071":1509788624350,"1022178124469":1478686417063,"1022296103359":1478686417199,"1025523866075":1509788624230,"1022700978589":1509788624973,"1021457223614":1478686417044,"1022482746522":1478943089223,"1020294206073":1465470268297,"1021795924979":1478686417130,"1020526329882":1465470268322,"1021493529028":1509788624398,"1019208454543":1480585069068,"1021452504915":1478686416983,"1022482746529":1478943089223,"1008628288255":1478686804030,"1025767131245":1509788624844,"1023235235954":1509788624354,"1008628288273":1478686804030,"1020990728766":1478686417088,"1022464528977":1509788624280,"1018469203085":1509788624428,"1022032767009":1478686417166,"1024920272832":1509788624489,"1021273855349":1478686416991,"1730214426":1444487341723,"1022188872351":1478686417188,"1024920272811":1509788624489,"1024920272807":1509788624489,"1023947109794":1491634246532,"1021517253261":1509788624398,"1024920272800":1509788624489,"1024195488620":1509788625034,"1023947109793":1491634246532,"1021076054358":1478686417002,"1024920272818":1509788624489,"1022076020198":1478686417061,"1023947109791":1491634246531,"1020803166467":1509788625230,"1024920272799":1509788624489,"1020803166466":1509788625230,"1025672106824":1509788624942,"1022076020194":1478686417061,"1024920272793":1509788624489,"1024920272794":1509788624489,"1021563782247":1478686417113,"1021575841599":1509788624401,"1000237727559":1444487341761,"1022076020200":1478686417061,"1022188872358":1478686417188,"1025731743499":1509788624297,"1025712737367":1509788624304,"1019023253472":1480585069072,"1022700847327":1509788624972,"1021385921062":1478686417042,"1020801069317":1478686417030,"1010919195142":1444487341761,"1010024494938":1491634246526,"1010024494933":1491634246526,"1010024494932":1491634246526,"1025593857883":1509788624229,"1023646681942":1509788624195,"1022205271402":1478686417191,"1024887766359":1509788625003,"1022700847330":1509788624972,"1022700847331":1509788624972,"1025784301786":1509788624349,"1022700847328":1509788624972,"1022700847329":1509788624972,"1020556869817":1478686417017,"1010057392457":1491634246534,"1020962941698":1478686417085,"1020855464590":1478686417078,"1021188791977":1465470268188,"1022449718256":1478686417295,"1025672106979":1509788624942,"1023485727153":1509788625038,"1025509054470":1509788667537,"1022065666765":1478686417270,"1023235235968":1509788624354,"1021715054566":1478686417123,"1022426386511":1478686417294,"1022953042387":1509788624915,"947431019":1444487341707,"1022455091690":1478686417216,"947431009":1444487341706,"1003975499628":1478950494937,"1000526211785":1444487341733,"1016853061600":1465470268266,"1021179223492":1478686417098,"1022283782662":1478686417286,"947430979":1444487341707,"1025524521172":1509788624418,"1023853132982":1491634246515,"1023135361333":1509788624445,"1300812750":1478686804029,"1019023907877":1480585069072,"1023135361335":1509788624445,"1023135361336":1509788624445,"1023135361337":1509788624445,"1001517265328":1444487341699,"1023135361341":1509788624445,"1024360586780":1509788624501,"1021774690364":1509788624817,"1023988004040":1509788625036,"1001517527443":1444487341753,"1014797752362":1509788624453,"1021562472256":1478686417113,"1021974441207":1509788624452,"1022052952463":1478686417172,"1021974441211":1509788624452,"1021395882337":1509788625083,"1025524521110":1509788624418,"1020556870531":1478686417017,"1023646681202":1509788624534,"1021774690540":1509788624420,"1016928689099":1478686804058,"1016928689100":1478686804058,"1016928689101":1478686804058,"1023583898668":1509788624434,"1019194823375":1478686804047,"1021606511153":1478686417008,"1005662812261":1480585069065,"1020782064923":1478686416997,"1025524521050":1509788624418,"1021714922714":1509788625082,"1022953042662":1509788625084,"1020896357385":1478686416987,"1025524520970":1509788624418,"1026507710125":1515854751199,"1024434248455":1509788624903,"1024434248448":1509788624903,"1024434248451":1509788624903,"1024434248461":1509788624903,"1022084671224":1509788624319,"1024434248463":1509788624904,"1024434248459":1509788624903,"1022483271390":1509788625149,"1024781191076":1509788624435,"1024434248470":1509788624904,"1022483271388":1509788625149,"1022483271389":1509788625149,"1022483271387":1509788625149,"1024434248466":1509788624903,"1024434248472":1509788624903,"1022233845745":1478686417014,"1024434248473":1509788624903,"1024434248420":1509788624904,"1024434248421":1509788624903,"1022935479384":1490882721866,"1024434248419":1509788624904,"1006976166806":1478686804025,"1021618176725":1509788624404,"1024434248426":1509788624903,"1024434248437":1509788624903,"1024434248432":1509788624903,"1022953698097":1509788624291,"1024662441311":1509788624471,"1021460630583":1478686417108,"1022467149875":1478686417218,"1025784433265":1509788624348,"102406406":1444487341736,"1024434248440":1509788624903,"1001644796262":1444487341753,"1022407775113":1478686417208,"1019007393367":1509788624314,"1019007393365":1509788624317,"1019007393361":1509788624317,"1020556870188":1478686417017,"1022464528505":1509788624311,"1021553428111":1509788624405,"1024434248412":1509788624904,"1024434248415":1509788624904,"1024434248409":1509788624903,"1024434248411":1509788624904,"1021626565145":1509788624941,"1021695000188":1480585069067,"1016530743874":1478686804016,"1017612628422":1478686804046,"1006872883654":1478686804025,"1021468888004":1478686416986,"1025573148519":1509788624336,"1010919194870":1444487341761,"1022932071431":1509788625051,"1020800807929":1478686416997,"1000484531740":1480585069061,"1021468494810":1509788624402,"1024211347545":1509788625033,"1022919488854":1509788624385,"1023646681486":1509788625101,"1022919488853":1509788624385,"1460848748":1491634246509,"1024587469245":1509788625095,"1021974441218":1509788624441,"1021974441221":1509788624436,"1021974441224":1509788624436,"1022828395062":1509788625074,"1021974441226":1509788624436,"1021854381093":1509788624402,"1021974441229":1509788624436,"1021974441228":1509788624436,"1021974441231":1509788624427,"194286595":1444487341724,"1021485009463":1478686417243,"1021485009462":1478686417243,"1025910784583":1509788667579,"1025910784584":1509788667579,"1022039582988":1478686417169,"1016710309877":1478686804063,"1021928304769":1478686417142,"1021965790916":1509788624464,"1004731003279":1478686804041,"1024117894409":1509788624325,"1004731003291":1478686804041,"1020871192469":1478686416989,"1004731003289":1478686804041,"1024673188980":1509788625153,"1004731003288":1478686804041,"1024673188981":1509788625153,"1004731003295":1478686804041,"1025524521276":1509788624418,"1024673188978":1509788625153,"1004731003294":1478686804041,"1024673188979":1509788625153,"1004731003293":1478686804041,"1021744937860":1478686417051,"1004731003292":1478686804041,"1024673188977":1509788625153,"1004731003286":1478686804041,"1024434248197":1509788624902,"1024434248198":1509788624903,"1022208679791":1478686417280,"1024434248199":1509788624902,"1024434248192":1509788624903,"1024434248193":1509788624903,"1024434248195":1509788624903,"1004731003299":1478686804041,"1004731003298":1478686804041,"1004731003297":1478686804041,"1004731003296":1478686804041,"1024879231122":1509788625162,"1024434248201":1509788624902,"1004731003300":1478686804041,"1024879231118":1509788625162,"1024879231119":1509788625162,"1024879231116":1509788625162,"1024055636322":1509788624330,"1024879231113":1509788625162,"1024055636332":1509788624327,"1020401290171":1509788624393,"1018812732692":1478686804038,"1025322391829":1509788624306,"1023064707975":1509788624533,"1018812732689":1478686804038,"1018812732688":1478686804038,"1018812732691":1478686804038,"1018812732690":1478686804038,"1025265768051":1509788624344,"1025902410860":1509788667406,"1024462956065":1509788625083,"1025714581925":1509788624453,"1025714581926":1509788624440,"1018812732685":1478686804038,"1025714581932":1509788624426,"1018812732684":1478686804038,"1025714581933":1509788624434,"1018812732687":1478686804038,"1018812732686":1478686804038,"1018812732683":1478686804038,"1025714581911":1509788624429,"1025714581904":1509788624429,"4985882888":1509788624156,"1024798112380":1509788625176,"1021699310272":1478686417122,"1025714581914":1509788624429,"5001742865":1509788667393,"1025714581895":1509788624440,"1024462956059":1509788625083,"1025714581890":1509788624511,"1021699310300":1478686417122,"1025714581891":1509788624509,"1025714581903":1509788624429,"1025714581896":1509788624440,"1021185123275":1478686417098,"1025051068775":1509788624457,"1025051068776":1509788624458,"1025051068777":1509788624458,"1025714582013":1509788624511,"1025051068778":1509788624458,"1025051068780":1509788624458,"1019385804928":1480585069073,"4961241081":1509788624158,"1025051068783":1509788624458,"1021940355289":1478686416987,"1016779119743":1478686804017,"1025051068786":1509788624458,"1025714581984":1509788624426,"1021653450738":1478686804026,"1021653450737":1478686804046,"1025714581987":1509788624434,"1019728415800":1509788624315,"1025714581972":1509788624429,"1022054520766":1478686417173,"1025714581973":1509788624429,"1025714581974":1509788624455,"1022054520764":1478686417173,"1006923862495":1478686804054,"1025714581975":1509788624427,"1022423117216":1478686417210,"1025714581968":1509788624429,"1025714581969":1509788624429,"1017354157955":1478686804049,"1025714581980":1509788624424,"1025714581981":1509788624438,"1025714581976":1509788624454,"1025714581978":1509788624440,"1025714581979":1509788624437,"1022065923965":1478686417012,"1025714581956":1509788624440,"1025714581957":1509788624440,"1025714581958":1509788624440,"1022054520748":1478686417173,"1025714581959":1509788624427,"1021655810039":1509788624616,"1025714581953":1509788624511,"1025714581954":1509788624509,"1025714581955":1509788624440,"1021655810043":1509788624801,"1025714581965":1509788624429,"1025714581966":1509788624429,"1021655810041":1509788624801,"1021655810040":1509788624801,"1025714581961":1509788624429,"1021655810046":1509788624801,"1025714581963":1509788624429,"1021655810044":1509788624801,"1018673139146":1509788625019,"1023132735259":1509788625144,"1020748761403":1478686417028,"1024778975729":1509788625024,"1021323799493":1478686417103,"1020917453580":1478686417081,"1025714581796":1509788624469,"1025714581798":1509788624469,"1025714581799":1509788624469,"1025714581793":1509788624469,"1025714581805":1509788624469,"1025714581806":1509788624469,"1022421413221":1509788624849,"1025714581800":1509788624469,"1025714581801":1509788624469,"1025714581803":1509788624469,"1019932498170":1509788624922,"1022421413208":1509788624436,"1025714581778":1509788624469,"1021058358168":1478686417036,"1025714581788":1509788624469,"1025714581790":1509788624469,"1025714581791":1509788624469,"1025714581784":1509788624469,"1023132735285":1509788625166,"1025714581786":1509788624469,"1025714581764":1509788624469,"1020997015667":1478686417088,"1025714581773":1509788624469,"1025714581775":1509788624469,"1025714581768":1509788624469,"1025714581769":1509788624469,"1013026946359":1478686804040,"1025478124396":1509788625116,"1025478124397":1509788625126,"1025478124398":1509788625109,"1024798112406":1509788625176,"1024798112400":1509788625177,"1021566155326":1478686417114,"1024798112401":1509788625177,"1022866261940":1509788624439,"1018812732869":1478686804038,"1024798112388":1509788625177,"1018812732868":1478686804038,"1018812732871":1478686804038,"1018812732870":1478686804038,"1025714581863":1509788624438,"1025714581856":1509788624427,"1025714581857":1509788624453,"1018812732867":1478686804038,"1025714581858":1509788624440,"1024798112386":1509788625177,"1018812732866":1478686804038,"1021629595114":1478686417119,"1008297861903":1478686804023,"1018812732873":1478686804038,"1024798112392":1509788625177,"1008297861899":1478686804032,"1018812732872":1478686804038,"1025714581865":1509788624426,"929470392":1478686804029,"1018812732875":1478686804038,"1025478124402":1509788625089,"1018812732874":1478686804038,"1018517029973":1478686804065,"1025714581844":1509788624429,"1025714581846":1509788624429,"1025714581847":1509788624429,"1573190947":1491634246509,"1024134140705":1509788667504,"1025714581854":1509788624429,"1025714581828":1509788624509,"1025714581830":1509788624440,"1024322887293":1509788667457,"1025714581827":1509788624511,"1023064707967":1509788625100,"1020235885274":1465470268181,"1025714581833":1509788624440,"1025714581835":1509788624427,"1020235885358":1465470268181,"1024724973474":1509788624290,"1021869575637":1478686804047,"1024462956346":1509788625083,"1021869575639":1478686804047,"1021869575638":1478686804047,"1021869575641":1478686804047,"1021869575640":1478686804047,"1021869575643":1478686804047,"1021869575642":1478686804047,"1021869575645":1478686804047,"1021869575644":1478686804047,"1021869575647":1478686804047,"1021869575646":1478686804047,"1021869575649":1478686804047,"1024724973456":1509788624289,"1021869575648":1478686804047,"1021869575651":1478686804047,"1021869575650":1478686804047,"4950623805":1509788624158,"1025731752871":1509788624181,"1025524524996":1509788625099,"1021961326695":1509788624899,"1024724973442":1509788624290,"1025001522957":1509788624465,"1021428002827":1478686804026,"1021428002826":1478686804026,"1021428002824":1478686804026,"1024886702509":1509788624472,"1022511330246":1480585069129,"1016301617639":1480585069066,"1022112586498":1509788624943,"1025714581757":1509788624469,"1025714581759":1509788624469,"1025714581753":1509788624469,"1024886702497":1509788624472,"1022306985856":1509788624959,"1024886702525":1509788624472,"1021887138951":1478686804069,"1019601143107":1478686804067,"1019601143106":1478686804067,"1019601143105":1478686804067,"1019601143104":1478686804067,"1021582277306":1509788624397,"1019601143108":1478686804067,"1024886702478":1509788624472,"929469954":1478686804029,"1022229258261":1478686417014,"1017165148751":1478686804020,"1024706229447":1509788624170,"1024134140579":1509788667504,"1022713053168":1509788624234,"1025007027886":1509788624334,"1024745027088":1509788624342,"1025522033784":1509788624296,"1024886702484":1509788624472,"1025524524944":1509788625099,"1024886702485":1509788624472,"1024518007708":1509788625028,"1024886702487":1509788624472,"1025007027900":1509788624334,"1020463298877":1480585069065,"1021764846728":1478686417127,"1025874623387":1509788667581,"1025874623384":1509788667581,"1022021751883":1509788625144,"1410135443":1478950494922,"1022454443591":1478686417216,"1020463298846":1480585069065,"1022439108443":1478686417071,"1023783927559":1491634246535,"1025524524891":1509788625099,"1022021751904":1509788625168,"1025731752761":1509788624273,"1020894253858":1478686417032,"1006826867362":1478686804022,"1024724973437":1509788624290,"1021869575449":1478686804047,"1003127582243":1478686804054,"1021869575450":1478686804047,"1021869575453":1478686804047,"1021869575452":1478686804047,"1021869575455":1478686804047,"1021869575454":1478686804047,"1019023909820":1480585069072,"1021869575457":1478686804047,"1021869575456":1478686804047,"1025505388013":1509788624336,"1021869575459":1478686804047,"1021869575458":1478686804047,"1021869575460":1478686804047,"1021869575463":1478686804047,"1021869575462":1478686804047,"1022371605265":1509788624362,"1021869575465":1478686804047,"1021869575464":1478686804047,"1020463298909":1480585069065,"1021984003065":1509788624565,"1023443921667":1509788624970,"1025315969158":1509788624376,"1020542467080":1509788625077,"1025524524817":1509788625099,"1022438715145":1478686417213,"1009490634943":1480585069065,"1023002971479":1509788624393,"1025714582455":1509788625245,"1025714582462":1509788625142,"1020346643334":1465470268247,"1025714582457":1509788625243,"1020346643333":1465470268247,"1022540691148":1509788625063,"1025714582458":1509788625141,"1021722509715":1509788624403,"1870187874":1444487341709,"1023307473681":1509788624534,"1009326006863":1478686804061,"4950623540":1509788624156,"1021788308888":1509788624399,"1025714582421":1509788625142,"1021949923897":1478686417145,"1009326006861":1478686804061,"1025714582422":1509788625136,"1025714582416":1509788625168,"1025714582417":1509788625111,"1019006739266":1509788624313,"1025714582419":1509788625167,"1021065174781":1478686417093,"1025714582424":1509788625138,"1025714582427":1509788625128,"1023002971493":1509788624393,"1016682124324":1465470268240,"1000926652735":1478686804033,"1025714582402":1509788625118,"1025714582414":1509788625119,"1025714582410":1509788625118,"1024490089103":1509788625028,"1025714582517":1509788625142,"1021239780364":1480585069071,"1025688890747":1509788624348,"1025714582524":1509788625118,"1025714582525":1509788625118,"1025714582521":1509788625118,"1021645061239":1478686417248,"1021645061238":1478686417248,"1021645061237":1478686417248,"1021645061247":1478686417248,"1025714582508":1509788625243,"519486639":1478686417019,"1021645061246":1478686417248,"1008601954287":1478686804030,"1021645061245":1478686417248,"1021645061244":1478686417248,"1021645061243":1478686417248,"1021645061241":1478686417248,"1025714582506":1509788625245,"1021645061240":1478686417248,"1022432423735":1478686417071,"1025714582485":1509788625111,"1022432423733":1478686417071,"1025714582483":1509788625118,"1025714582488":1509788625136,"1022261108994":1478686417067,"1003655269378":1478686417018,"1022511329522":1480585069129,"1025714582469":1509788625119,"1025714582478":1509788625118,"1030659859":1444487341750,"1022432423723":1478686417071,"1022432423720":1478686417071,"1025714582475":1509788625119,"1025711174472":1509788624345,"1025849719558":1509788667476,"1025711174473":1509788624345,"1025849719559":1509788667476,"1025849719557":1509788667476,"1023042162810":1509788625073,"4560432475":1465469681388,"1025711174465":1509788624345,"1025714582333":1509788625243,"1025849719560":1509788667476,"1025714582331":1509788625245,"1870188010":1444487341709,"1022395329022":1478686417302,"1025714582310":1509788625105,"1025714582311":1509788625138,"1025714582304":1509788625168,"1025714582305":1509788625112,"1022089911092":1478686417273,"1025902542585":1509788667464,"1016682124424":1465470268240,"1021869575775":1478686804047,"1021869575774":1478686804047,"1021869575777":1478686804047,"1025714582292":1509788625120,"1021869575776":1478686804047,"1023816286843":1509788624366,"1025714582293":1509788625119,"1021869575779":1478686804047,"1021869575778":1478686804047,"1021869575781":1478686804047,"1021869575780":1478686804047,"1021869575783":1478686804047,"1025714582290":1509788625120,"1021869575782":1478686804047,"1021869575785":1478686804047,"1021330353740":1478686417239,"1021869575784":1478686804047,"1020797521409":1478686417029,"1021869575787":1478686804047,"1025714582302":1509788625119,"1021869575786":1478686804047,"1022498878443":1480585069130,"1025714582296":1509788625119,"1021869575788":1478686804047,"1019023909070":1480585069072,"1025714582297":1509788625119,"1025714582277":1509788625243,"1007647211048":1478686804025,"1007647211049":1478686804034,"1025714582275":1509788625245,"1025714582284":1509788625142,"1023999396144":1509788625017,"1022208811595":1480585069075,"1023307473869":1509788625101,"1025714582385":1509788625245,"1870187966":1444487341709,"1025714582387":1509788625243,"1311173870":1491634246512,"929469871":1478686804033,"1025714582393":1509788625140,"1025714582394":1509788625142,"1025714582395":1509788625111,"1025849719638":1509788667475,"1025849719636":1509788667476,"1025849719637":1509788667475,"1021791585715":1478686417255,"1025714582356":1509788625167,"1025714582357":1509788625142,"1025711174442":1509788624345,"1025714582352":1509788625118,"1025714582354":1509788625168,"1020194335320":1509788625077,"1025714582355":1509788625111,"1025714582364":1509788625128,"1025714582360":1509788625137,"1025714582361":1509788625110,"1025714582341":1509788625141,"1025714582336":1509788625141,"1025711174463":1509788624345,"1025714582339":1509788625141,"1025714582348":1509788625119,"1025714582345":1509788625119,"1016682124521":1465470268240,"1025478123689":1509788624407,"1025478123685":1509788624429,"1025714582205":1509788625141,"1025478123686":1509788624431,"1025478123687":1509788624425,"1025714582201":1509788625245,"1019023253863":1480585069072,"1025714582202":1509788625243,"1025714582181":1509788624437,"1025714582183":1509788624424,"1025714582177":1509788624455,"1025714582178":1509788624427,"1025714582179":1509788624453,"1021887139531":1478686804069,"1016322327108":1509788624367,"1021982560557":1509788625198,"5001742605":1509788667393,"1016682124600":1465470268240,"1021980332293":1478686417151,"1017973219380":1509788624936,"1021186433187":1465469681393,"1018805524060":1509788624928,"1025522034252":1509788624295,"4646025134":1478686416965,"1022932191273":1509788625007,"1025849719503":1509788667476,"1024028626814":1509788624517,"1017229505594":1509788625076,"1022432947808":1478686417212,"749244408":1444487341724,"1021887139461":1478686804069,"1024804403364":1509788624211,"1025714582244":1509788625105,"1025849719506":1509788667476,"1024056282426":1509788624328,"1025849719504":1509788667476,"1025849719505":1509788667476,"1025731752405":1509788624178,"1025714582251":1509788625110,"1025714582224":1509788625120,"1021803776964":1478686417052,"1025714582235":1509788625142,"1025714582215":1509788625120,"1025714582221":1509788625120,"1025714582219":1509788625120,"1016474896847":1478686804023,"999725074":1444487341745,"1016682124688":1465470268241,"1025714582072":1509788624424,"1021099253025":1478686416985,"1025714582075":1509788624426,"1025478123583":1509788624201,"1022047704496":1478686417059,"1025714582060":1509788624429,"1025714582062":1509788624429,"1025714582058":1509788624429,"1025714582059":1509788624429,"1024134139991":1509788667504,"1025714582033":1509788624440,"5001742724":1509788667393,"1025714582035":1509788624427,"1020898971927":1478686417032,"1025478123525":1509788624800,"1025714582040":1509788624429,"1025478123520":1509788624829,"1025714582041":1509788624429,"1025478123521":1509788624834,"1021982560680":1509788625198,"1025478123522":1509788624824,"1025714582043":1509788624429,"1025714582022":1509788624440,"1012802153710":1465470268318,"1019151313278":1509788624316,"1025714582018":1509788624509,"1021183156246":1478686417003,"1022511329595":1480585069129,"4994796046":1509788667393,"1025714582025":1509788624440,"1022220608054":1478686417192,"1025062734252":1509788624294,"1022770578125":1509788624994,"1025062734250":1509788624294,"1016474896777":1478686804016,"1025714582129":1509788624429,"1025062734248":1509788624294,"1019302965275":1509788624317,"1025714582130":1509788624429,"1021153927854":1478686417097,"1025714582131":1509788624429,"1019302965269":1509788624315,"1023976327834":1509788624276,"1023976327835":1509788624276,"1023976327836":1509788624276,"1023976327837":1509788624276,"1025062734243":1509788624294,"1014242379443":1478686804064,"1025714582118":1509788624440,"1020235885042":1465470268181,"1025714582112":1509788624509,"1025714582125":1509788624429,"1025714582122":1509788624440,"1025714582123":1509788624427,"1021472438152":1478686417045,"1015222172925":1480585069068,"1015222172927":1480585069074,"1021887139389":1478686804069,"1025714582111":1509788624511,"1025478123584":1509788624205,"1025478123585":1509788624198,"1020977746951":1478686417230,"1025478123586":1509788624186,"1024999818714":1509788624859,"1024999818710":1509788624860,"1009748327074":1491634246511,"1024999818711":1509788624859,"1024999818709":1509788624860,"1021763274439":1509788624395,"1024999818707":1509788624859,"1018513490127":1509788624906,"1018136799554":1509788624299,"1025714582967":1509788624916,"1025714582972":1509788624847,"1025714582973":1509788624848,"1022511330953":1480585069129,"1025714582975":1509788624826,"1021887007191":1478686804027,"1008869327274":1509788625016,"1025714582969":1509788624915,"1021661707051":1509788624534,"1025714582970":1509788624847,"1025714582950":1509788624198,"1021761962300":1478686417051,"1025714582944":1509788624199,"1025714582945":1509788624229,"1022462176135":1478686416991,"1025714582947":1509788624211,"1024098489843":1509788625036,"1021960803695":1478686417056,"1022382353997":1478686417069,"1025714582932":1509788624201,"1004352994514":1444487341707,"1020911687642":1478686416974,"1022258489239":1478686417196,"1025714582935":1509788624201,"1024491662523":1509788624972,"1025714582928":1509788624213,"1025714582940":1509788624201,"1021758161225":1478686417009,"1025714582936":1509788624201,"1023076372678":1509788624533,"1020870267971":1509788624931,"1020870267972":1509788624930,"1021470339258":1478686416973,"1020870267977":1509788624930,"1025714582926":1509788624213,"1020870267979":1509788624941,"1020870267978":1509788624941,"1025714582920":1509788624270,"1020870267981":1509788624959,"1020870267980":1509788624941,"1025714582922":1509788624269,"1021758161242":1509788624395,"1018513490063":1509788624906,"1022238697090":1509788624932,"1025902671932":1509788667452,"1022238697089":1509788624971,"1021794992914":1509788624394,"1018513490058":1509788624906,"1020870267961":1509788624941,"1022278672425":1478686417198,"1020870267963":1509788624941,"4968320104":1509788624157,"1020870267965":1509788624941,"1014886494035":1478686804028,"1022511331023":1480585069129,"1021833924271":1478686417053,"1020870267967":1509788624971,"1018513490079":1509788624906,"1023946572612":1491634246531,"1025714583008":1509788624845,"1018513490075":1509788624906,"1018513490074":1509788624906,"1024274915122":1509788624294,"1025714583010":1509788624824,"1018513490072":1509788624906,"1025902409781":1509788667406,"1018513490071":1509788624906,"1021635361410":1478686417049,"1021955429886":1509788624256,"1021955429883":1509788624256,"1018513490067":1509788624906,"1021955429882":1509788624256,"1025714582996":1509788624866,"1025714582999":1509788624848,"1025714582992":1509788624868,"621838715":1478686417020,"1023132734441":1509788625144,"1025714582982":1509788624830,"1022053864374":1480585069084,"1025714582983":1509788624830,"1021955429842":1509788624565,"1023995072074":1491634246532,"1025714582989":1509788624830,"1021661707103":1509788624195,"1025714582990":1509788624830,"1016502683684":1478686804017,"1025902672127":1509788667466,"1025714582839":1509788624213,"1025902672122":1509788667465,"1025902672123":1509788667457,"1025714582834":1509788624214,"1022149941383":1478686417277,"1025714582844":1509788624202,"1025714582841":1509788624214,"1025714582842":1509788624199,"1025714582828":1509788624269,"1025714582831":1509788624214,"1021661707193":1509788624818,"1025714582825":1509788624270,"1021068711938":1478686417093,"1024838089042":1509788624949,"1025714582805":1509788624214,"1008678895034":1478686804030,"1025714582807":1509788624211,"1025714582802":1509788624199,"1025714582803":1509788624229,"1025714582808":1509788624197,"1024370287992":1509788624926,"1025714582809":1509788624212,"1025714582789":1509788624199,"1025714582791":1509788624202,"1025714582787":1509788624213,"1022238697082":1509788624947,"1025714582799":1509788624202,"1025714582792":1509788624202,"1022238697086":1509788624931,"1025714582793":1509788624202,"1025714582794":1509788624202,"1022238697085":1509788624930,"1024737424185":1509788625021,"1025714582880":1509788624206,"1012655481550":1478686417074,"1021402313823":1478686416981,"1025714582868":1509788624230,"1025714582869":1509788624199,"1025714582870":1509788624229,"1025714582864":1509788624202,"1025714582865":1509788624202,"1025714582866":1509788624201,"1025714582877":1509788624197,"1025714582878":1509788624212,"1025714582879":1509788624198,"1025714582872":1509788624214,"1025714582875":1509788624211,"1019601141995":1478686804050,"1019601141994":1478686804050,"1025714582855":1509788624201,"1021049577301":1478686417093,"1025714582850":1509788624201,"1025714582862":1509788624202,"1006863567273":1478686804030,"1020988363701":1478686417088,"1025714582859":1509788624201,"1025902540959":1509788667450,"1024961282459":1509788624969,"1025714582711":1509788624214,"1025714582707":1509788624199,"1025714582718":1509788624212,"1021746233652":1478686417126,"1025714582719":1509788624198,"1023606322773":1509788625144,"1025714582694":1509788624202,"1023307473944":1509788624818,"1014742836884":1480585069062,"1025714582702":1509788624202,"1025714582703":1509788624202,"1025714582696":1509788624202,"1021865643521":1509788624512,"1021865643520":1509788624512,"1018513490386":1509788624906,"1025714582699":1509788624202,"1025714582676":1509788624270,"1025714582678":1509788624269,"1012210207137":1478686417223,"1013026945232":1478686804028,"1022945298819":1509788625073,"1153360278":1444487341747,"1023995203353":1491634246529,"4961239705":1509788624157,"1025714582683":1509788624213,"1022502679604":1509788625007,"1021848866602":1509788624993,"1025714582772":1509788624214,"1025714582775":1509788624197,"1025714582770":1509788624199,"1024576202790":1509788667500,"1025714582782":1509788624270,"1024576202788":1509788667501,"1025714582783":1509788624269,"4994796794":1509788667393,"1024576202787":1509788667501,"1015292543365":1478686804067,"1025269830502":1509788624342,"1022067757632":1509788624183,"1025714582758":1509788624202,"1021604952543":1478686417116,"1010024484760":1491634246526,"1025714582753":1509788624202,"1025714582755":1509788624202,"1025714582764":1509788624202,"1022921576279":1509788624298,"1016396382276":1478686804017,"1020542466211":1509788625077,"1016664690813":1478686804042,"1021865643644":1509788624512,"1016664690809":1478686804063,"1020294081487":1465470268287,"1025714582738":1509788624270,"1025714582739":1509788624269,"1025714582748":1509788624213,"1025714582750":1509788624214,"1000906460":1444487341745,"1025714582721":1509788624206,"1021921348311":1478686417141,"1021865643677":1509788624513,"1025714582583":1509788624269,"1021865643678":1509788624513,"1025714582577":1509788624270,"1025796371281":1509788624274,"1021865643672":1509788624513,"1021865643675":1509788624513,"1021865643674":1509788624513,"1020781268523":1478686416997,"1021865643669":1509788624512,"1021865643671":1509788624513,"1021865643665":1509788624512,"1021865643667":1509788624512,"1021865643663":1509788624512,"1021865643662":1509788624512,"1021865643656":1509788624512,"1021865643659":1509788624513,"1017181008333":1478686804066,"1021865643658":1509788624513,"1021865643654":1509788624513,"1025686923974":1509788624304,"1021865643649":1509788624513,"1021865643651":1509788624513,"1021865643650":1509788624513,"1025714582544":1509788625136,"1025714582546":1509788625138,"1008751115021":1478686804030,"1020781137421":1478686417029,"1025609199184":1509788624746,"1023307474110":1509788624195,"4994796551":1509788667393,"1025609199183":1509788624833,"1016682124194":1465470268240,"1022454835797":1478686417016,"1018513490296":1509788624906,"1025714582537":1509788625168,"1025714582645":1509788624214,"1025714582646":1509788624211,"1025714582640":1509788624202,"1025714582641":1509788624230,"1021195085535":1478686417235,"1025714582648":1509788624212,"1025714582629":1509788624202,"1025714582630":1509788624202,"1022038922110":1478686417168,"1022038922099":1478686417168,"1022644109154":1480585069132,"1022038922098":1478686417168,"1025714582639":1509788624202,"1021323800212":1478686417103,"1021114325537":1478686416992,"1022921576426":1509788624298,"1020294212428":1465470268297,"1018513490215":1509788624906,"1025714582621":1509788624202,"1025714582623":1509788624202,"1018513490209":1509788624906,"1022038922072":1478686417168,"1025782476924":1509788624174,"1008907731588":1465470268235,"1025714583473":1509788624541,"1025714583475":1509788624541,"1014496924255":1478686804032,"1022465059151":1478686417299,"1025714583487":1509788624549,"1862977799":1444487341731,"1025714583481":1509788624541,"5001743404":1509788667393,"1025714583482":1509788624566,"1025714583461":1509788624541,"1021031488710":1478686416988,"1023932154342":1491634246529,"1025714583457":1509788624538,"1024134141405":1509788667504,"1012810544835":1478686804062,"1025714583453":1509788624551,"1025714583454":1509788624551,"1020294211718":1465470268297,"1025714583449":1509788624612,"1025714583450":1509788624611,"1014070427021":1478686804062,"1021640472669":1509788624819,"1020389897504":1478686804022,"1022278672988":1478686417197,"1025620733200":1509788624970,"1017181008484":1478686804066,"1017181008411":1478686804066,"1012210207437":1478686417223,"1023596098992":1509788624516,"1023173238595":1509788625083,"1025714583524":1509788624551,"1018513490591":1509788624906,"1025620733309":1509788624946,"1025714583527":1509788624541,"1025620733311":1509788624932,"1012607247013":1478686417026,"1025714583523":1509788624551,"1025714583533":1509788624541,"1021342673522":1478686417103,"1025051070335":1509788624568,"4961239509":1509788624157,"1022866260253":1509788624467,"1025714583516":1509788624612,"1025714583519":1509788624611,"1022236206232":1478686417065,"1587738838":1444487341727,"1025714583490":1509788624538,"1022709119151":1509788624349,"1025714583491":1509788624544,"1022270153370":1480585069091,"1019324068578":1509788624282,"1018513490510":1509788624906,"1025714583356":1509788624551,"1025551393223":1509788624343,"1025714583357":1509788624551,"1021629594553":1478686417119,"1022511330319":1480585069129,"1025714583353":1509788624612,"1025607888031":1509788624229,"1025714583355":1509788624611,"1025714583333":1509788624866,"1025714583334":1509788624848,"1022943857231":1509788624291,"1022943857229":1509788624291,"1023122509997":1509788625046,"1022918036701":1509788625052,"1025051070336":1509788624568,"1025051070337":1509788624568,"1024779501521":1509788624878,"1020443898237":1478686804047,"1012810544767":1478686804062,"1025051070338":1509788624568,"1025051070339":1509788624568,"1025051070340":1509788624568,"261269815":1444487341735,"1025051070342":1509788624568,"4950622642":1509788624157,"1020437999773":1478686804066,"1025714583324":1509788624830,"1025714583320":1509788624830,"1025620733312":1509788624941,"1025714583321":1509788624830,"1025714583322":1509788624830,"1025714583323":1509788624830,"227453758":1478950494906,"1023173238719":1509788625083,"1025714583303":1509788624916,"1023064708402":1509788624194,"1025714583296":1509788624836,"1023064708403":1509788624419,"1025714583308":1509788624847,"1025714583304":1509788624915,"1025714583306":1509788624847,"1021938652696":1478686417055,"1025714583307":1509788624847,"1022488131361":1478943089489,"1025505125112":1509788624342,"1019601142481":1478686804067,"1025505125114":1509788624346,"1022270415410":1480585069093,"1025505125116":1509788624343,"1021510316258":1478686417112,"1022270415411":1480585069093,"1022270415408":1480585069093,"1018513490433":1509788624906,"1022270415409":1480585069093,"1021652531486":1509788624867,"1022270415403":1480585069093,"1022270415401":1480585069093,"1025714583405":1509788624536,"1025714583406":1509788624549,"1022234896320":1478686417065,"1021975352393":1509788624464,"1025714583402":1509788624551,"1025714583403":1509788624549,"1021865643517":1509788624512,"1024796933286":1509788625024,"1023173238766":1509788625083,"1021865643516":1509788624512,"1025714583381":1509788624541,"1021865643519":1509788624512,"1025478124878":1509788624541,"1021865643518":1509788624512,"1025478124879":1509788624543,"1021865643512":1509788624512,"1021865643515":1509788624512,"1021865643514":1509788624512,"1021865643508":1509788624512,"1025714583389":1509788624538,"1025714583391":1509788624565,"1025714583384":1509788624541,"1021865643504":1509788624512,"1025714583386":1509788624541,"1021865643506":1509788624512,"1025714583364":1509788624551,"1021959755664":1478686417056,"1021865643500":1509788624512,"1021822783356":1478686417133,"1021865643502":1509788624512,"1025714583360":1509788624551,"1021865643498":1509788624512,"1021865643493":1509788624512,"1012880405105":1478686417224,"1021865643495":1509788624512,"1025478124880":1509788624537,"1025478124881":1509788624524,"1025714583371":1509788624541,"1025714583220":1509788624883,"1025714583221":1509788624883,"1025714583222":1509788624883,"1025714583223":1509788624883,"1025714583218":1509788624883,"1024779501179":1509788624878,"1025714583224":1509788624883,"1016474766717":1478686804034,"1024779501183":1509788624878,"1025714583204":1509788624883,"1025714583205":1509788624883,"1025714583206":1509788624883,"1025714583207":1509788624883,"1023064708243":1509788624815,"1025714583201":1509788624883,"1025714583202":1509788624883,"1025714583203":1509788624883,"1025714583214":1509788624883,"1025714583215":1509788624883,"1025784312432":1509788624349,"1025714583208":1509788624883,"1025714583210":1509788624883,"1025714583188":1509788624883,"1025714583190":1509788624883,"1024919733815":1509788624531,"1023878284332":1491634246512,"1025714583184":1509788624883,"1024919733809":1509788624531,"1830865415":1444487341711,"1025714583198":1509788624883,"1024919733823":1509788624531,"1021652531452":1509788624826,"1025714583193":1509788624883,"1025505125120":1509788624341,"1025505125122":1509788624345,"1025714583175":1509788624883,"1025714583177":1509788624884,"1025714583179":1509788624884,"1025714583284":1509788624825,"1025714583285":1509788624866,"1025051070050":1509788624232,"1025714583286":1509788624848,"1022310654427":1478686417287,"1025714583280":1509788624830,"1025714583281":1509788624830,"1025628335007":1509788624431,"1025714583283":1509788624868,"1025714583295":1509788624824,"1024134141059":1509788667504,"1025714583290":1509788624822,"1024919733828":1509788624531,"1024028625763":1509788624517,"1024919733824":1509788624531,"1025714583276":1509788624830,"1025714583272":1509788624830,"1025714583255":1509788624830,"1025714583250":1509788624848,"1022018998929":1478686417161,"1006492512288":1509788624310,"1010766639588":1478950494939,"1020803681083":1478686416971,"1022270415756":1480585069094,"1016664691304":1478686804051,"1025051070036":1509788624232,"1022270415755":1480585069094,"1025051070037":1509788624232,"1014743098620":1480585069067,"1024460071180":1509788625030,"1025051070039":1509788624232,"1025628335008":1509788624425,"1025714583244":1509788624847,"1025628335009":1509788624428,"1025714583245":1509788624847,"1022270415749":1480585069094,"1025051070043":1509788624232,"1025628335011":1509788624406,"1022270415746":1480585069094,"1025051070045":1509788624232,"1022270415744":1480585069094,"1025051070046":1509788624232,"1025714583242":1509788624916,"1022270415745":1480585069094,"1025714583243":1509788624916,"1025714583088":1509788624824,"1025714583090":1509788624836,"1021955429920":1509788624256,"1021620681271":1478686417247,"1022943857493":1509788624291,"1022208812827":1478686417191,"1025714583077":1509788624826,"1025714583072":1509788624830,"1024117495123":1509788624429,"1021620681260":1478686417247,"1025714583075":1509788624868,"1025714583085":1509788624822,"1025714583086":1509788624845,"1021955429949":1509788625166,"1021955429894":1509788624256,"1025714583062":1509788624830,"1021955429892":1509788624228,"1025714583056":1509788624848,"1021955429889":1509788624256,"1025714583058":1509788624830,"1021955429888":1509788624256,"1021889366544":1509788624394,"1021955429902":1509788624256,"1021955429900":1509788624256,"1021955429899":1509788624256,"1025714583064":1509788624830,"1025714583066":1509788624830,"1021955429896":1509788624256,"1025714583044":1509788624916,"1022270153553":1480585069092,"1021955429908":1509788624256,"1021955429907":1509788624256,"1019815712409":1509788624285,"1021955429904":1509788624256,"1025714583043":1509788624916,"1021955429919":1509788624256,"1021955429918":1509788624256,"1025900313400":1509788667457,"1021955429916":1509788624256,"1025513775664":1509788624451,"1025714583048":1509788624847,"1021955429914":1509788624256,"1021955429913":1509788624256,"1021955429912":1509788624256,"1025714583156":1509788624824,"1025714583157":1509788624836,"1022347882372":1478686417202,"1025714583152":1509788624848,"1025714583154":1509788624822,"4968321003":1509788624159,"4994797182":1509788667394,"1022344867745":1478686417202,"1022943857429":1509788624291,"1022192932943":1478686417279,"1021955430006":1509788624452,"1207754794":1491634246519,"1025714583138":1509788624830,"1025714583139":1509788624830,"1025714583151":1509788624866,"1025714583145":1509788624830,"1025714583146":1509788624868,"1019601142779":1478686804067,"1019601142778":1478686804067,"1022457456697":1480585069113,"1019601142780":1478686804067,"1025714583123":1509788624848,"1022943857459":1509788624291,"1022270153487":1480585069091,"1025714583129":1509788624830,"1024779501185":1509788624878,"1021936949039":1478686416989,"1024779501186":1509788624878,"1024779501187":1509788624878,"1022943857455":1509788624291,"1020932395851":1478686417083,"1024779501190":1509788624878,"1022943857453":1509788624291,"1021936949029":1478686416989,"1025714583116":1509788624916,"1024779501193":1509788624878,"1025714583117":1509788624916,"1021936949030":1478686416989,"1022067757292":1509788624183,"1022426785164":1478686417294,"1022747379859":1509788624222,"1022747379863":1509788624222,"1022747379864":1509788624222,"1021340312644":1478686417239,"1022747379865":1509788624222,"1021713467964":1509788624195,"1023064710038":1509788624447,"1023064710039":1509788624447,"1023064710036":1509788624447,"1023064710037":1509788624447,"1024919734581":1509788624192,"1024919734576":1509788624192,"1024919734578":1509788624192,"1023064710048":1509788624447,"1025331434048":1509788624852,"1025331434052":1509788624851,"1024919734587":1509788624192,"1024919734565":1509788624192,"1024919734567":1509788624192,"1024919734572":1509788624192,"1026448184771":1514827444365,"1024919734575":1509788624192,"1021362201918":1478686417239,"1022747379887":1509788624222,"1021632476839":1478686417248,"1022343160013":1478686417289,"1019290778322":1509788625079,"1015242082692":1480585069068,"1025018826591":1509788624886,"1025331434046":1509788624852,"1024919734593":1509788624192,"1025331434047":1509788624852,"1024204922854":1509788625034,"1025331434045":1509788624851,"1016301619450":1480585069066,"1022058192858":1478686417059,"5001740924":1509788667394,"1024919734645":1509788624418,"1022747379955":1509788624562,"1020235883077":1465470268181,"1022747379956":1509788624562,"1022747379957":1509788624562,"1024919734642":1509788624418,"1022747379958":1509788624562,"1024919734652":1509788624418,"1022747379960":1509788624562,"1024919734648":1509788624418,"1024919734649":1509788624418,"1024919734628":1509788624418,"1021283557792":1465469681396,"1024244633895":1509788624948,"1024919734639":1509788624418,"1024919734632":1509788624418,"1024919734634":1509788624418,"1023064709895":1509788624851,"1023064709892":1509788624851,"1021775597305":1478686417254,"1022136177786":1478686417276,"1025331434210":1509788624442,"1024919734684":1509788625098,"1025331434208":1509788624442,"1024919734686":1509788625098,"1025331434209":1509788624442,"1023064709898":1509788624851,"1024919734680":1509788625098,"1024919734681":1509788625098,"1021652531039":1509788624199,"1025331434212":1509788624442,"1023064709896":1509788624851,"1024919734682":1509788625098,"1023064709897":1509788624851,"1023018178799":1509788625100,"1021713468054":1509788624817,"1023932026706":1491634246530,"1020542465367":1509788625077,"1024919734717":1509788624531,"1020542465366":1509788625077,"1024919734718":1509788624531,"1025513778467":1509788624511,"1024919734693":1509788625098,"1024919734688":1509788625098,"1024919734689":1509788625098,"1025331434204":1509788624442,"1024919734690":1509788625098,"1022609502239":1509788625002,"1021924755235":1478686417141,"1023932026702":1491634246530,"1021090862563":1478686417036,"1022432421275":1478686417071,"1021351060857":1509788624178,"1020364601924":1478686804027,"1025018826718":1509788624886,"1022074048611":1509788624924,"1024781988344":1509788625021,"1024919734720":1509788624531,"1024919734723":1509788624531,"1021786345219":1509788624816,"1024325244600":1509788624811,"1022467418052":1478686417218,"1025018826728":1509788624886,"1024930089619":1509788624875,"1025018826729":1509788624886,"1022467418054":1478686417218,"1024930089616":1509788624875,"1024930089617":1509788624875,"1025018826731":1509788624886,"1025018826725":1509788624886,"1020779168553":1478686417225,"1018034433939":1478686804046,"1025018826727":1509788624886,"1025018826722":1509788624886,"1021880845509":1509788624433,"1022432421281":1478686417071,"1024930089614":1509788624875,"1024930089615":1509788624875,"1024930089612":1509788624875,"1024930089613":1509788624875,"1010551939195":1509788624277,"1025608016616":1509788625140,"1025714583740":1509788624551,"1025714583742":1509788624551,"1025714583737":1509788624612,"1025714583738":1509788624611,"1025714583716":1509788624537,"1025714583712":1509788624551,"1025714583713":1509788624548,"1025608016632":1509788625139,"1025714583715":1509788624549,"1025608016633":1509788625139,"1022335299099":1478686417201,"1025714583700":1509788624541,"1025714583701":1509788624541,"1025714583703":1509788624541,"1024789328895":1509788625090,"1025714583698":1509788624541,"1025714583710":1509788624538,"1025714583704":1509788624541,"1025714583706":1509788624541,"1024789328884":1509788625090,"1025714583707":1509788624541,"1024225235273":1509788625100,"1024789328878":1509788625090,"1024460730181":1509788625029,"1023172055063":1509788625044,"1025714583695":1509788624538,"4976837017":1509788624158,"1022431765505":1478686417294,"1022638601135":1509788624986,"1012199195241":1478686416982,"1021195086417":1478686417235,"1021283557529":1465469681396,"1022579097549":1480585069123,"465351398":1491634246534,"1017648404766":1478686804019,"1024734543742":1509788624342,"1025714583764":1509788624541,"1025714583766":1509788624566,"1020235883333":1465470268181,"1025569481022":1509788624351,"1025714583773":1509788624537,"1025714583768":1509788624565,"1021014053038":1478686417089,"1024887228809":1509788624435,"1024225235221":1509788624533,"1025714583771":1509788624536,"1022356136115":1478686417289,"1024887228816":1509788624452,"1021775597319":1478686417254,"1022999037676":1509788625049,"1025714583754":1509788624541,"1023756531146":1509788625038,"1025331434475":1509788624217,"1025331434478":1509788624217,"1025331434476":1509788624217,"1025331434477":1509788624217,"1024930089969":1509788624875,"1025714583612":1509788624550,"1023064709646":1509788624555,"1008744559807":1478686804030,"1023064709647":1509788624555,"1022138275158":1478686417184,"1023064709645":1509788624555,"1025714583608":1509788624612,"1021831823500":1478686417009,"1025714583609":1509788624611,"1024546579164":1509788624958,"1016930921650":1478686804019,"1009715429059":1491634246511,"1021772189472":1478686417128,"1025714583584":1509788624544,"1023064709651":1509788624555,"1024679492307":1509788624958,"1023064709648":1509788624555,"1025331434481":1509788624217,"1021197708624":1495284743407,"1017318110638":1465470268237,"1021911648225":1478686417140,"1021786345080":1509788624194,"1025714583571":1509788624565,"1002896893969":1478686804068,"1025714583580":1509788624549,"1002896893968":1478686804068,"1022379729878":1478686417205,"1012042828588":1478686804024,"1009022551857":1478686804030,"1025524001957":1509788625158,"1025524001958":1509788625158,"1002896893966":1478686804068,"1025524001959":1509788625158,"1025524001960":1509788625158,"1025714583565":1509788624566,"1025524001962":1509788625158,"1021733260634":1509788624395,"1025714583561":1509788624541,"1025714583670":1509788624612,"1025714583671":1509788624611,"1010024743689":1491634246527,"1025714583673":1509788624551,"1022747380033":1509788624562,"1021786344969":1509788624533,"1022747380034":1509788624562,"1022747380035":1509788624562,"1022747380036":1509788624562,"1021790015062":1509788624403,"1022747380037":1509788624562,"1025714583636":1509788624566,"1021748989424":1509788624508,"1020911688219":1478686416974,"1025714583638":1509788624565,"1025714583633":1509788624541,"1021923837539":1478686417301,"1021652530744":1509788624551,"4994793564":1509788667393,"1025714583641":1509788624536,"1025714583643":1509788624549,"1025569612201":1509788624349,"1025714583623":1509788624538,"1022943855918":1509788624291,"1012261717661":1478686416991,"1024225235340":1509788624815,"1025714583619":1509788624550,"1025714583629":1509788624541,"1025714583624":1509788624541,"1025714583626":1509788624541,"1025714583627":1509788624541,"1025585734466":1509788624351,"1024535175651":1509788625027,"1025585734468":1509788624350,"1019001760726":1480585069069,"1015060298921":1478686804022,"1025585734473":1509788624350,"1020797126328":1478686417029,"1021984397808":1478686417057,"1022401618198":1478686417070,"1009555776710":1509788624361,"1012206667469":1478686417223,"1021806133929":1478686417131,"1021674408520":1478686417120,"1326507297":1480585069060,"1019826460862":1465470268321,"1024840316904":1509788624969,"273594996":1444487341717,"1018089218057":1478686804026,"5001740319":1509788667393,"1025798208767":1509788625087,"1021351847925":1478686417104,"1021411883585":1509788624447,"1021411883587":1509788624447,"1021411883586":1509788624447,"1025428843255":1509788625171,"1021411883589":1509788624447,"1025428843246":1509788625171,"1021370459346":1478686417104,"1025428843247":1509788625171,"1025428843238":1509788625171,"1025018826071":1509788624480,"1025428843239":1509788625171,"1022390346169":1478686417206,"1021288801025":1478686416979,"1024156557041":1509788667500,"1024156557051":1509788667500,"1024156557048":1509788667500,"1021118911982":1478686417233,"1023018179105":1509788624533,"1012353736295":1478686804015,"1024225235466":1509788624194,"149201553":1444487341746,"1021783461231":1478686417128,"1021499047026":1478686417007,"1021651481931":1478686417120,"1025428843058":1509788624467,"1021651481934":1478686417120,"1025428843053":1509788624467,"1025428843051":1509788624466,"1950408418":1444487341761,"1022427440942":1478686417070,"1023064709430":1509788625146,"1023064709431":1509788625146,"1022094365645":1478686417274,"1023064709429":1509788625146,"1024299816796":1509788624293,"1018746935387":1509788624373,"1023064709436":1509788625146,"1023064709432":1509788625146,"1018617823351":1444487341760,"1021397727777":1509788624399,"1025078985042":1509788624280,"1025078985040":1509788624280,"1023018179204":1509788624815,"1025078985051":1509788624280,"1019889507332":1478686804021,"1023878285785":1491634246510,"1023375634381":1509788625084,"1025078985027":1509788624280,"1022472665638":1478943089486,"1025078985025":1509788624280,"1025078985038":1509788624280,"1025078985037":1509788624280,"1025078985032":1509788624280,"1018250051169":1509788624286,"1024804401424":1509788624548,"1021073168040":1478686417093,"1024687750715":1509788625024,"1020627388473":1478686416982,"1025078985056":1509788624280,"1022633620387":1480585069095,"1022932189591":1509788624569,"1021001733022":1478686416979,"1022039055779":1478686417169,"1023396605137":1509788625080,"1023946443785":1491634246531,"1025215436902":1509788624536,"1018034433121":1478686804046,"1022039055794":1478686417169,"1024491660161":1509788624971,"1024491660162":1509788624971,"1024491660164":1509788624972,"1950408541":1444487341761,"1024491660165":1509788624972,"1021921739960":1509788625166,"1025473931468":1509788624352,"1022039055758":1478686417168,"1016243435286":1465470268265,"1022039055771":1478686417168,"1023018179452":1509788624419,"1021546361654":1478686417300,"1017229900809":1509788624941,"1021283951342":1465469681396,"1022324550883":1478686417200,"1022235814305":1478686417193,"1022452082011":1478686417296,"1025018825823":1509788624480,"1020815607522":1478686417030,"1022030274171":1478686417058,"1024496771919":1509788625070,"1950408487":1444487341761,"1022442120653":1478686417295,"1013328659584":1465470268239,"1020384786487":1480585069079,"1023602784273":1509788624933,"1021713467828":1509788624534,"1024156557056":1509788667500,"5001740726":1509788667394,"1025164057593":1509788624329,"1023602784306":1509788624933,"1022511331627":1480585069130,"1025428843280":1509788625171,"1021197709178":1495284743407,"1018617823502":1444487341760,"1022189130857":1478686417064,"1022700861162":1509788624973,"1023602784299":1509788624933,"1022747511726":1509788624552,"1021967620389":1509788624464,"1002896894569":1478686804059,"1002896894568":1478686804059,"1002896894571":1478686804059,"1023602784326":1509788624933,"1002896894570":1478686804059,"1025874227683":1509788667406,"1025597268331":1509788624363,"1002896894564":1478686804059,"1002896894567":1478686804059,"1021783854115":1509788624400,"1002896894566":1478686804059,"1005736984978":1509788624383,"1024491660152":1509788624972,"1024491660156":1509788624972,"1024491660159":1509788624971,"1024780153519":1509788624436,"1025597268312":1509788624368,"1024491660147":1509788624972,"1022511331694":1480585069130,"1024491660148":1509788624971,"1024491660151":1509788624971,"1020824651513":1509788624971,"1024491660137":1509788624972,"1024491660138":1509788624972,"1024491660139":1509788624972,"1024491660141":1509788624972,"1025597268293":1509788624368,"1025412830281":1509788625101,"1022324681817":1478686417200,"1025597268297":1509788624368,"1024491660132":1509788624971,"1836106097":1478950494926,"1023734773684":1509788624969,"1016949402119":1478686804020,"1024434514404":1509788624465,"1019932496990":1509788624922,"1019601143837":1478686804067,"1022074442881":1478686417061,"1024132440051":1509788624304,"1025018825502":1509788624479,"1022481972311":1478943089531,"1025018825499":1509788624479,"190621508":1478686417023,"1025018825492":1509788624479,"1025018825495":1509788624479,"1025906470970":1509788667458,"1025018825491":1509788624479,"1025754300279":1509788624958,"1021165334268":1478686417097,"1021213698527":1478686417099,"1025018825510":1509788624479,"1025018825506":1509788624479,"1020863454443":1509788625002,"1020863454445":1509788625002,"1020863454444":1509788625002,"1022238830328":1509788624947,"1778828863":1491634246513,"1021852141557":1478686417009,"1022107342472":1478686417275,"1019833671170":1509788624363,"1019833671169":1509788624363,"1019833671168":1509788624363,"1025202200186":1509788624514,"1022001174700":1478686417157,"1022001174691":1478686417157,"1025513777629":1509788624510,"1022080340995":1478686417272,"1014787533490":1478686804028,"1021189320472":1478686417098,"1021755935186":1480585069067,"1025713012169":1509788624305,"1022336347003":1478686417201,"1021189320482":1478686417098,"1020779169708":1478686417225,"1021554619876":1509788624397,"1023996642920":1509788624439,"1025910665622":1509788667463,"1015657321856":1480585069068,"1012812905533":1478686417224,"1022429929965":1478686417211,"1022026865147":1478686417267,"1022429929959":1478686417211,"1022373045871":1478686417204,"1022373045873":1478686417204,"1017171310716":1478686804019,"1022444872284":1478686417214,"1020016644496":1478686804038,"1016907851854":1478686804063,"1024557981769":1509788624413,"1021474273470":1478686417045,"1024557981781":1509788624413,"1020429613664":1465470268317,"1024557981777":1509788624413,"1024557981779":1509788624413,"1020016644495":1478686804038,"1020016644494":1478686804038,"1024557981789":1509788624413,"1020016644493":1478686804038,"1020016644492":1478686804038,"1020016644491":1478686804038,"1021981253349":1509788624199,"1020016644490":1478686804038,"1024557981785":1509788624413,"1021791587253":1478686417255,"1007384535239":1478686804030,"1024557981794":1509788624413,"1024557981806":1509788624413,"1024557981802":1509788624413,"1021981253323":1509788624198,"1022275659901":1478686417285,"1024752497695":1509788667502,"1024557981808":1509788624413,"1023018179764":1509788624194,"1651035793":1444487341726,"1009840730915":1491634246520,"1019867879729":1478686804057,"1025315968119":1509788624381,"1019495248712":1465470268273,"1021519100576":1478686416974,"1010091590603":1491634246516,"1010091590620":1491634246516,"1022407778700":1478686417208,"4843146633":1509788624158,"1010091590634":1491634246516,"1010091590630":1491634246516,"1021368099720":1478686417104,"1021368099723":1478686417104,"1010091590649":1491634246516,"1024116711366":1509788625035,"1022077195607":1478686417061,"1025522034745":1509788624295,"1010091590645":1491634246516,"1021395362367":1478686417240,"1010812384434":1509788624299,"1021197707654":1495284743407,"1022466499198":1478686417299,"1022475943406":1478943089486,"1021937343877":1478686417055,"1010047288887":1478686804069,"1000237715288":1444487341761,"1021403495915":1478686417043,"1023268262406":1509788624916,"1021173198626":1478686417038,"1021415292062":1478686417106,"1010057249178":1491634246534,"1025412829890":1509788624194,"1025516529684":1509788624340,"1021719236268":1478686417123,"1019071097035":1509788624314,"1019932497186":1509788624922,"1021887004836":1478686804027,"1025412829745":1509788624533,"1025412829750":1509788624419,"1021659869902":1509788624396,"1013150664961":1478686804023,"1022079292891":1478686417061,"1020834611978":1478686416984,"1022084928591":1478686417062,"1008522264023":1478686804030,"1022451164059":1478686417296,"1016569797888":1465470268265,"1016779116935":1478686804017,"1024435169375":1509788624465,"1008522264025":1478686804030,"1025477996063":1509788624867,"1022921836476":1509788624294,"1025796373357":1509788624274,"1022921836471":1509788624294,"1023144531204":1509788625154,"1022921836488":1509788624294,"1022271465741":1478686417285,"1023144531207":1509788625154,"5001742310":1509788667392,"1023144531213":1509788625154,"1023144531208":1509788625154,"1021793159870":1478686417129,"1023144531209":1509788625154,"1025902408109":1509788667450,"1021489215673":1478686417110,"1024342413993":1509788625031,"1024064406474":1509788624920,"1022921836497":1509788624294,"1077734872":1444487341749,"1021319210581":1478686417102,"1022479220106":1478943089315,"1022454047236":1478686417297,"1021319210584":1478686417102,"1461385969":1491634246509,"1001660783288":1478686804029,"327466618":1444487341730,"1021234800827":1478686417099,"1022204882636":1480585069086,"1022204882637":1480585069086,"1018539051849":1478686804064,"1022204882634":1480585069086,"1021865379086":1478686417053,"1022204882646":1480585069086,"1022204882647":1480585069086,"1022204882644":1480585069086,"1022204882645":1480585069086,"1022204882643":1480585069086,"1022204882640":1480585069086,"1022204882654":1480585069086,"1024535569888":1509788625027,"1022204882650":1480585069086,"1022204882658":1480585069086,"1022092007333":1478686416975,"1024225236545":1509788624419,"1016871939226":1509788624976,"1025118176097":1509788667888,"1021748726358":1478686804069,"1025412829684":1509788624816,"1022204882563":1480585069086,"734430593":1444487341746,"1022204882574":1480585069086,"1022204882573":1480585069086,"1022204882570":1480585069086,"1022204882582":1480585069086,"1025477996031":1509788624867,"1022204882580":1480585069086,"4994795493":1509788667393,"1022331627787":1478686417068,"1022204882581":1480585069086,"1022204882576":1480585069086,"1022204882577":1480585069086,"1022204882591":1480585069086,"4961241582":1509788624158,"1022204882587":1480585069086,"1021767469222":1509788624395,"1022204882584":1480585069086,"1025796372618":1509788624274,"1024889589429":1509788625023,"1023342079330":1509788624975,"1022928127447":1509788624301,"1022204882502":1480585069085,"1022204882500":1480585069085,"1022204882498":1480585069085,"1022204882510":1480585069086,"1025331434722":1509788625147,"1021118386434":1465470268306,"1025331434723":1509788625147,"1023451784221":1509788667538,"1022204882509":1480585069086,"1023451784223":1509788667538,"1022204882506":1480585069086,"1025331434726":1509788625147,"1023451784216":1509788667538,"1025331434724":1509788625147,"1025331434725":1509788624555,"1023451784219":1509788667538,"1022204882518":1480585069086,"1022204882513":1480585069086,"1022204882524":1480585069086,"1022204882522":1480585069086,"1022204882523":1480585069086,"1021963952063":1478686417148,"1018892293316":1465470268272,"1022204882521":1480585069086,"1023451784246":1509788667538,"1023451784240":1509788667538,"1021866296752":1478686417136,"1023451784243":1509788667538,"4950624700":1509788624158,"1018335115202":1478686804022,"734430582":1444487341743,"1023451784228":1509788667538,"1025331434715":1509788624555,"1021791586776":1478686417255,"1025331434718":1509788624555,"1023451784224":1509788667538,"1025331434719":1509788624555,"1025331434716":1509788624555,"1025331434717":1509788625146,"1022392837384":1478686417291,"1021925802411":1478686804046,"1021556324268":1478686416978,"1021612815093":1478686417116,"1021029389372":1478686417091,"1024273339721":1509788624277,"1024341889468":1509788624276,"1018393047803":1478686804066,"1323753487":1444487341740,"1323753485":1444487341748,"1025524525084":1509788625099,"4985882583":1509788624157,"1016930921435":1478686804019,"1022221004557":1478686417192,"1009746229124":1491634246512,"1021848863970":1509788624993,"1024625098628":1509788625070,"1021981252920":1509788624438,"1025477995689":1509788624849,"1022445789537":1478686417016,"1023946573848":1491634246531,"1019809685148":1509788624353,"1022445789555":1478686417016,"1020551901781":1478686804071,"1016243434269":1465470268265,"1026226536473":1514456869772,"1021652529402":1509788624826,"862362696":1509788625016,"1020886785606":1509788624183,"1021197708172":1495284743407,"1022390346907":1478686417015,"1022579096027":1480585069123,"1022511332807":1480585069130,"1019932497693":1509788624930,"1022074968020":1509788624190,"4994795244":1509788667392,"1025078985975":1509788624280,"1010321757277":1491634246523,"1025078985979":1509788624280,"1019728937748":1509788624393,"1021822781152":1478686417132,"1021713468737":1509788624419,"1021118386431":1465470268306,"1022394148071":1478686417291,"1010295281115":1491634246523,"1010321757263":1491634246523,"1022511332610":1480585069130,"1749075912":1478686804035,"1021870228305":1478686417136,"1021981253033":1509788625128,"1012999287822":1478686804019,"1012285185945":1478686417074,"1019194827716":1478686804047,"1169877543":1480585069060,"1017446288335":1478686804066,"1022085453387":1478686417062,"1021726182624":1478686417051,"1022932190431":1509788624871,"1024953944921":1509788625069,"1021371638058":1509788624933,"166372944":1491634246515,"1024237164132":1509788624176,"1019833671167":1509788624363,"1019833671165":1509788624363,"1024804402230":1509788624437,"1019833671164":1509788624363,"1019833671163":1509788624363,"1019833671162":1509788624363,"1024237164130":1509788624176,"1021941014349":1478686417260,"1025910796855":1509788667579,"1021941014357":1478686417260,"1021941014363":1478686417260,"1022149940183":1478686417277,"1013764367897":1478686804016,"1021941014377":1478686417260,"1021240306091":1478686417100,"1020649933927":1478686417028,"1008047102802":1480585069065,"1025522035450":1509788624297,"1008047102805":1480585069065,"1021240306105":1478686417100,"1022629947792":1509788625074,"1024953816299":1509788625083,"1016399009530":1480585069069,"1022879635586":1509788624544,"1025796892350":1509788624406,"1024501627378":1509788624434,"1025796892337":1509788624428,"1025796892338":1509788624431,"1025796892339":1509788624425,"1022232539394":1478686417065,"1022232539396":1478686417065,"1021249615857":1478686417100,"1024633217069":1509788624991,"1024633217070":1509788624991,"1023926916618":1491634246530,"1014876928933":1478686804032,"1022511325867":1480585069128,"1023926916617":1491634246530,"1023926916622":1491634246530,"1800330080":1444487341735,"1024633217085":1509788624991,"1024633217073":1509788624991,"1024633217076":1509788624992,"1024633217077":1509788624991,"1026227068726":1514456869769,"1025049368858":1509788625097,"1024633217098":1509788624991,"1024633217099":1509788624992,"1021713470071":1509788624447,"1025049368861":1509788625097,"1024633217088":1509788624991,"1021713470074":1509788624447,"1024633217089":1509788624991,"1021713470073":1509788624447,"1021713470072":1509788624447,"1024633217091":1509788624991,"1021173461519":1465470268185,"1021173461523":1465470268185,"1021173461521":1465470268185,"1021173461531":1465470268185,"1025049368835":1509788625097,"1021173461528":1465470268185,"1022226903501":1478686417065,"1025049368839":1509788625097,"1026227068776":1514456869769,"1023277068444":1509788624889,"1025797940959":1509788624866,"1008207662419":1478686804023,"1025530427112":1509788624186,"1014850189635":1478686804028,"1025530427110":1509788624198,"1025530427108":1509788624201,"1025530427109":1509788624204,"1022235685247":1478686417193,"1020891365699":1478686416999,"1022511325939":1480585069128,"1021469156574":1478686804050,"1025049368868":1509788625097,"1023834247464":1491634246533,"1585377018":1444487341727,"1023834247468":1491634246533,"1021242406560":1478686417039,"1021260625798":1465470268200,"1022491271519":1478943089490,"1023834247460":1491634246533,"1022223102302":1478686417064,"1008596444524":1478686804030,"248036934":1491634246533,"1026227068806":1514456869769,"1023471582167":1509788625083,"1026227068819":1514456869769,"1021461029793":1478686417242,"1021461029788":1478686417242,"1026227068832":1514456869769,"1009854222402":1491634246533,"1005149272009":1478686804016,"1021980066459":1478686417263,"1021979280102":1478686417056,"1008118139090":1478686804030,"1022334121869":1478686417201,"1021967745582":1478686417149,"1025530426946":1509788624425,"1025530426947":1509788624407,"1025530426944":1509788624428,"1022203310129":1478686417190,"1024177259929":1509788624419,"1025530426945":1509788624431,"1006011452110":1478686804040,"1021891337543":1478686417054,"1021590531003":1478686417114,"1025908567258":1509788667458,"1025908567259":1509788667460,"1025796892236":1509788624827,"1025505391854":1509788624341,"1025796892238":1509788624822,"1025505391855":1509788624337,"1010002729152":1491634246525,"1020117529505":1465470268242,"1021662621646":1509788624396,"1025874881264":1509788667829,"1009997093016":1491634246520,"1024912003472":1509788624927,"1025505391856":1509788624344,"1025796892240":1509788624616,"1016301621342":1480585069066,"1025513780365":1509788624207,"1019024044927":1480585069072,"1025513780362":1509788624207,"1016422340249":1478686804019,"1016422340254":1478686804034,"1021967089664":1509788624215,"1022297814094":1478686417199,"1025513780379":1509788624230,"1021088894032":1478686417232,"1021088894034":1478686417232,"1022060414529":1478686417012,"1021790672560":1478686417255,"1001517522626":1444487341752,"1021164286970":1478686417038,"1019882423394":1509788624359,"1024226412916":1509788667463,"1021527746147":1478686417047,"1011906259966":1478686804049,"1021912702745":1478686417140,"1021961715729":1509788624452,"1585377062":1444487341745,"1023821402416":1491634246535,"1025513780462":1509788625113,"1021671133654":1478686417120,"1025513780457":1509788625165,"1025513780459":1509788625165,"1022241584095":1478686417066,"1022324684491":1478686417200,"1025513780455":1509788625244,"1023961389400":1509788625037,"1025513780451":1509788625246,"1018274817143":1478686804023,"1024879111703":1509788624442,"1025513780475":1509788625169,"1025513780468":1509788625131,"1024879111705":1509788624442,"1025513780469":1509788625131,"1024879111706":1509788624443,"1024879111707":1509788624442,"1025513780464":1509788625144,"1024879111710":1509788624442,"1025513780466":1509788625131,"1025513780467":1509788625131,"1024752494995":1509788667502,"1025049368798":1509788625097,"1022375541565":1480585069075,"1025049368784":1509788625097,"1025049368788":1509788625097,"1020392252796":1478686804028,"1025049368778":1509788625097,"1026227068570":1514456869768,"1020918497800":1478686416999,"1020918497804":1478686416999,"1020918497807":1478686416999,"1022244336627":1478686417195,"1760483661":1478686804024,"578720729":1478950494912,"1025049368829":1509788625097,"1025049368818":1509788625097,"1024575683643":1509788667836,"1021229299521":1478686417099,"1025049368821":1509788625097,"1025049368810":1509788625097,"1025513780286":1509788624270,"1025513780287":1509788624270,"1025049368813":1509788625097,"1026227068594":1514456869770,"1021763409035":1478686417051,"1021734966537":1509788624403,"1021888191590":1509788624466,"1026227068610":1514456869770,"1025796892541":1509788624537,"1025796892543":1509788624523,"1000922856085":1478686417021,"1022232539387":1478686417065,"1026227068630":1514456869770,"1022232539391":1478686417065,"1256127294":1491634246535,"1256127292":1491634246520,"1022866265753":1509788624439,"1256127290":1491634246520,"1025513780330":1509788624208,"1026227068655":1514456869768,"1021602983244":1509788624862,"1021602983241":1509788624862,"1024660349831":1509788624531,"1021602983243":1509788624862,"1021602983242":1509788624862,"1022470307552":1478686417299,"1256127273":1491634246520,"1020654129834":1478686804057,"1021715173397":1509788624918,"1021715173396":1509788624918,"1021715173393":1509788624918,"1021715173395":1509788624918,"1021715173394":1509788624918,"1021715173405":1509788624918,"1021715173404":1509788624918,"1021715173407":1509788624918,"1021715173401":1509788624918,"1021715173403":1509788624918,"1021715173402":1509788624918,"1022238699730":1509788624932,"1023135352160":1509788625073,"1025712743362":1509788624305,"1022238699728":1509788624947,"1004352989920":1444487341707,"1021392485701":1478686417105,"1022238699734":1509788624931,"1022238699735":1509788624941,"1022238699733":1509788624941,"1016444230202":1480585069061,"1022238699736":1509788624932,"1021848868927":1509788624993,"1022468865327":1478686804049,"1022478820020":1478943089531,"1020742212155":1478686417028,"1021715173412":1509788624918,"1021715173414":1509788624918,"1021715173408":1509788624918,"1021715173411":1509788624918,"1021715173410":1509788624918,"1022268453156":1478686417067,"1022476460687":1478943089315,"1022397692274":1478686417207,"1022375671939":1480585069075,"1010057387723":1491634246534,"1021715173417":1509788624918,"1022375671941":1480585172183,"1021715173416":1509788624918,"1009158603871":1478686804034,"1018246768280":1509788625020,"1022237126838":1478686417194,"1021848082512":1509788624402,"1022108911815":1478686417182,"1021047605661":1478686417092,"1809766847":1444487341729,"182761606":1478686417023,"1022276712185":1509788624958,"1021713469530":1509788624562,"1022191095249":1478686417188,"1021713469529":1509788624562,"1021713469528":1509788624562,"1021392485695":1478686417105,"1021713469533":1509788624562,"1023821402653":1491634246536,"1020918497770":1478686416999,"1021743879873":1509788624561,"1021743879872":1509788624561,"1023121327269":1509788624958,"1018993111772":1478686804067,"1023821402849":1491634246536,"1021114453330":1478686417037,"1024134136157":1509788667504,"1025018828179":1509788624578,"227458863":1478950494907,"1021848475812":1478686417135,"1000922855910":1478686417021,"1009763002582":1478686804025,"1021783332133":1509788624403,"1022092004174":1478686417180,"1008091006166":1478686804015,"1025609070887":1509788624547,"1025609070884":1509788624547,"1010295015539":1491634246522,"1010295015538":1491634246522,"1025609070879":1509788624547,"1025609070875":1509788624539,"472690372":1444487341748,"1025609070871":1509788624551,"1022105110577":1478686417182,"1023405913530":1509788625003,"1021427999705":1478686804026,"1021694989254":1478686416985,"1025609070860":1509788624564,"1021743879871":1509788624561,"1021743879870":1509788624561,"1020975383823":1478686417086,"1021076049670":1478686417002,"1024134136007":1509788667504,"1022436097546":1478686416975,"1021861320794":1509788624399,"1020496980369":1478686804053,"1020496980368":1478686804053,"1024879111233":1509788624220,"1020496980371":1478686804054,"1020496980370":1478686804054,"1025609070813":1509788624547,"1020496980372":1478686804054,"1018888358322":1509788624281,"1025609070809":1509788624547,"1025609070806":1509788624539,"1025609070804":1509788624539,"1025609070799":1509788624552,"1021355392601":1465469681399,"1018993111906":1478686804067,"1025609070793":1509788624564,"1025609070788":1509788624564,"1020496980367":1478686804053,"1020496980366":1478686804053,"1025514960602":1509788624338,"1025514960603":1509788624337,"1024527972614":1509788625027,"1011906259446":1478686804049,"1024879111225":1509788624220,"1024879111227":1509788624220,"1024879111228":1509788624220,"1024879111229":1509788624220,"1023933994164":1491634246531,"1023933994162":1491634246531,"1021713469782":1509788624222,"1018156465502":1509788624929,"1022067754108":1509788624337,"1024879111185":1509788624856,"1024879111186":1509788624856,"1024879111187":1509788624856,"1024879111188":1509788624856,"1021746763586":1478686417254,"1024879111190":1509788624856,"1021713469774":1509788624222,"1021139776319":1478686417096,"1021713469773":1509788624222,"1021713469772":1509788624222,"1021828684334":1509788624402,"1025609070721":1509788624547,"1025018827891":1509788625190,"1025102323633":1509788624307,"1025609070713":1509788624547,"1025609070710":1509788624539,"1025609070711":1509788624539,"1021861320904":1509788624399,"1024444610253":1509788625030,"1025609070706":1509788624564,"1025007555671":1509788624977,"1025161298718":1509788624180,"1018559763864":1478686804015,"1025161298719":1509788624180,"1025609070703":1509788624564,"1025609070700":1509788624564,"1025161298717":1509788624180,"1025102323623":1509788624307,"1025161298710":1509788624180,"1022065132706":1478686417174,"1020294217013":1465470268297,"1020916138006":1478686417032,"1024028630933":1509788624517,"1021743749101":1478686417125,"1025161298722":1509788624180,"1025102323615":1509788624307,"1022601110661":1509788625062,"1022644496642":1509788625061,"1021684372085":1478686416972,"1019165866019":1478686804020,"1019165866018":1478686804026,"578720173":1478950494912,"1025609070637":1509788624566,"1025609070635":1509788624547,"1025609070633":1509788624547,"1021713469924":1509788624801,"1025609070628":1509788624547,"1022601241850":1509788625075,"1025609070624":1509788624539,"1022656030781":1509788624462,"1025609070622":1509788624539,"1009775454276":1478686804025,"1025609070617":1509788624552,"1020077290078":1509788624375,"1025609070610":1509788624564,"1020231956876":1509788624376,"1025609070607":1509788624564,"1019934723012":1509788625078,"1025589410558":1509788624548,"1018993111971":1478686804067,"1020231956875":1509788624376,"1020231956874":1509788624376,"1012821812210":1478686417224,"1017640665870":1509788624284,"1025609070593":1509788624564,"1024587086537":1509788667888,"1021344249912":1478686417041,"1024055630490":1509788624329,"1024055630489":1509788624330,"1025279656847":1509788625161,"1024660350584":1509788624531,"1025279656851":1509788625162,"1025279656852":1509788625162,"1025279656853":1509788625161,"1024055630464":1509788624327,"1025279656855":1509788625161,"1020915484601":1478686417227,"1020915484607":1478686417227,"1024055630474":1509788624329,"1020915484606":1478686417227,"1024055630518":1509788624330,"1022058841021":1478686417173,"1020770262637":1478686417225,"1020800014510":1478686417030,"1025018827582":1509788624577,"1020235890199":1465470268182,"1022208685236":1480585069075,"1024879111003":1509788625156,"1024879111004":1509788625156,"1024879111005":1509788625156,"1024879111006":1509788625156,"1024879111007":1509788625156,"1022208685263":1480585069115,"1024273338329":1509788624277,"1025018827594":1509788624577,"1024117491342":1509788624441,"1025018827588":1509788624577,"1025018827590":1509788624577,"1025018827585":1509788624577,"1025018827586":1509788624577,"1025018827587":1509788624577,"1024055630535":1509788624329,"1025100355586":1509788624181,"1024117491349":1509788624408,"1024055630528":1509788624327,"1021792637740":1478881022015,"1022466636661":1478686417072,"1024117491355":1509788624509,"1009132650570":1478686804054,"1009132650571":1478686804054,"1014720689821":1444487341759,"1020915484608":1478686417228,"1021666546835":1478686417248,"1020915484620":1478686417228,"1021398115465":1509788624994,"1022057268020":1478686417173,"1022421023085":1478686417209,"1022098951614":1509788624416,"1021136630814":1478686417233,"1021965125030":1509788624269,"1017064487345":1478686804019,"1021051670312":1478686417093,"1024879111072":1509788624561,"1021713602249":1509788624533,"1002912495122":1478686417018,"1021983737566":1478686417152,"1012880400450":1478686417224,"1025732535886":1509788624922,"1025018827740":1509788625189,"1025018827741":1509788625189,"1025018827743":1509788625189,"1021351065980":1478686417104,"1025018827738":1509788625190,"1025018827739":1509788625190,"1020294085236":1465470268287,"1025018827744":1509788625189,"1024055630459":1509788624325,"1025018827745":1509788625189,"1025098389691":1509788624298,"991334368":1478686416992,"1022057268038":1478686417173,"1024879111064":1509788624561,"1024879111066":1509788624561,"1023920493182":1509788624972,"1022057268042":1478686417173,"1024879111067":1509788624561,"1024879111068":1509788624561,"1010091989562":1491634246522,"1021968533499":1478686417010,"1012980281270":1465470268252,"1024780282958":1509788624510,"4994800829":1509788667394,"1025018827267":1509788624246,"2029047265":1491634246513,"1021197709791":1495284743407,"1021212127495":1509788624171,"1021928823361":1509788624974,"1021928823360":1509788624974,"1021928823363":1509788624974,"2029047275":1491634246513,"1021928823362":1509788624974,"1021928823365":1509788624974,"1019917681188":1509788624361,"1021928823364":1509788624974,"1021928823366":1509788624974,"1024333105907":1509788625110,"2029047254":1491634246513,"1022996028057":1509788624815,"1021249614589":1478686804033,"1021987276530":1478686417057,"1020067984662":1509788625077,"1022644105098":1480585069133,"1021693416575":1478686804032,"1021693416574":1478686804032,"1000526201262":1444487341712,"1019739691164":1509788624173,"1021623036100":1509788624819,"1021971810302":1478686417010,"1000526201267":1444487341714,"1016601249695":1478686804031,"1021928823359":1509788624974,"1021256561215":1478686417040,"578721541":1478950494912,"1022095674421":1478686417274,"1022241585097":1478686417066,"1021869316421":1478686804032,"1199239920":1491634246508,"1017973225103":1509788624947,"1021713602451":1509788624194,"1199239897":1491634246507,"1014983353597":1478686804052,"1014983353599":1478686804052,"1020985082423":1478686804031,"1021860929271":1509788624992,"1003079612773":1478686804017,"1019882422510":1509788624362,"1021940876602":1478686417260,"1021406635458":1509788624816,"1023735033457":1509788624970,"1012396196521":1478686804028,"1021388946083":1478686417240,"1024451425070":1509788624931,"1021138597270":1478686417096,"1017604102368":1478686804022,"1022668091074":1509788624971,"1023617065303":1509788624969,"1682756003":1491634246518,"1020996619580":1478686417230,"715693919":1478686417020,"1021388946069":1478686417240,"1021692105866":1509788624304,"1021336386187":1478686417041,"1000527905527":1444487341713,"1025513780106":1509788624838,"1022721042441":1509788625058,"1025513780096":1509788624838,"1021336386201":1478686417041,"227457950":1478950494906,"1021336386200":1478686417041,"1021336386199":1478686417041,"1024459681919":1509788625029,"1025561886349":1509788624304,"1024633218596":1509788624991,"1024633218597":1509788624991,"1024633218599":1509788624991,"1025018827068":1509788624247,"1020294084753":1465470268287,"1022491797398":1478943089532,"1019607962505":1509788624317,"1014669543850":1478686804016,"1019882423057":1509788624353,"1024660349987":1509788624531,"1021791064537":1478686416976,"1021707441158":1509788624436,"1002269240700":1478686804023,"1010069707335":1491634246534,"1025513779982":1509788624546,"1025513779976":1509788624539,"1025513779978":1509788624552,"1025521251261":1509788624825,"1024782249908":1509788624456,"1022428756989":1478686417070,"1025513779999":1509788624546,"1021965125543":1509788624271,"1025521251246":1509788624847,"1021946513081":1478686417144,"1025513779994":1509788624546,"1025513779988":1509788624546,"1025513779991":1509788624546,"1021252235562":1478686416981,"1022076407492":1509788624924,"1024332843198":1509788624476,"1025513780002":1509788624545,"1023210195526":1509788624269,"1022468602288":1478686416979,"1023844603846":1509788624940,"1023844603847":1509788624940,"1009715421568":1491634246511,"1025561230859":1509788624523,"1025513780058":1509788624864,"1025513780052":1509788624916,"1020200369823":1509788624363,"1025513780049":1509788624916,"1022201317824":1478686417064,"1020200369827":1509788624363,"1020200369826":1509788624363,"1025018827246":1509788624247,"1020200369825":1509788624363,"1025513780078":1509788624826,"1020200369824":1509788624363,"1021573885058":1509788624814,"1025513780079":1509788624849,"1020200369831":1509788624363,"1025513780072":1509788624864,"1020200369830":1509788624363,"1020200369829":1509788624363,"1020200369828":1509788624363,"1025671854279":1509788624943,"1020200369832":1509788624363,"1025018827256":1509788624247,"1025513780088":1509788624838,"1021252104518":1465470268197,"1025018827258":1509788624247,"1025018827259":1509788624247,"1025018827253":1509788624247,"1021807582825":1478686417255,"1025513780082":1509788624838,"1025018827251":1509788624247,"1020818758243":1478686417226,"578721147":1478950494912,"1021965125181":1509788624269,"1021860928595":1509788624992,"1025874619676":1509788667581,"1025874619677":1509788667581,"1021891336840":1478686417054,"1024365836038":1495284743424,"1021306109272":1478686417041,"1022242239911":1478686417283,"1025344277655":1509788625016,"1020818758239":1478686417226,"1868879967":1444487341749,"1023319536973":1509788624926,"1022996027523":1509788625100,"1022457460888":1480585069112,"1025372457816":1509788624543,"1022457460889":1480585069112,"1025372457817":1509788624537,"1025372457818":1509788624524,"1022397168691":1478686417206,"1022457460891":1480585069112,"1022457460893":1480585069113,"1022457460895":1480585069113,"1022457460880":1480585069112,"1021906147838":1509788624465,"1022457460882":1480585069112,"1022457460883":1480585069112,"1218772968":1480585069060,"1022457460884":1480585069112,"1019882422811":1509788624362,"1022457460885":1480585069112,"1020857423995":1478686417227,"1022457460886":1480585069112,"1025372457815":1509788624541,"1022457460875":1480585069112,"1022457460878":1480585069112,"1022996027622":1509788624193,"1018885475837":1509788624301,"1021910604051":1478686417259,"1025513779948":1509788624613,"1025513779951":1509788624611,"1024058906913":1509788624290,"1022020829883":1478686417162,"1024597702991":1509788624937,"1022454577289":1478686417297,"1025671854413":1509788624942,"1022020829874":1478686417162,"1014720689549":1444487341759,"1024660350235":1509788624531,"1022107340227":1478686417275,"1025513779956":1509788624565,"1025601207564":1509788624178,"1022457460899":1480585069113,"1022457460824":1480585069116,"1021736932136":1478686417124,"1022457460825":1480585069116,"1022457460827":1480585069116,"1025299976130":1509788624292,"1022457460818":1480585069116,"1022457460819":1480585069116,"1022457460822":1480585069116,"1021924235282":1509788667538,"1020918498309":1478686417081,"1020719272166":1478686417028,"1022857089137":1509788625166,"1019623821603":1447944718215,"1022457460848":1480585069117,"1022857089100":1509788625141,"1022457460851":1480585069117,"1022457460840":1480585069117,"1022457460841":1480585069117,"2010431589":1491634246533,"1022457460842":1480585069117,"1022956706724":1509788624439,"1022956706725":1509788624439,"1024660350428":1509788624531,"1022457460832":1480585069117,"1021154981571":1478686417097,"1022457460836":1480585069117,"1022457460837":1480585069117,"1022457460839":1480585069117,"1021693679261":1478686804028,"1021693679259":1478686804028,"1019827504465":1509788624285,"1019827504466":1509788624285,"1021049048167":1478686417093,"1006334966040":1478686804017,"1022996027504":1509788624533,"1023970303555":1509788625037,"1021693679245":1478686804028,"1022457460744":1480585069116,"1012241144191":1478686416985,"1022457460746":1480585069116,"1021981640164":1478686417057,"1021049048186":1478686417093,"1022457460748":1480585069116,"1011906260334":1478686804049,"1025689155823":1509788624351,"1002912494862":1478686417018,"1022457460737":1480585069116,"1022457460738":1480585069116,"1022457460740":1480585069116,"1004344336545":1444487341756,"1022457460743":1480585069116,"1022457460792":1480585069116,"1022457460794":1480585069116,"1022457460796":1480585069116,"1022457460784":1480585069116,"1022457460785":1480585069116,"1022457460787":1480585069116,"1025671854539":1509788624942,"1934279846":1444487341748,"1021965125343":1509788624269,"1022457460789":1480585069116,"1022457460776":1480585069116,"1022457460777":1480585069116,"1022457460778":1480585069116,"1000527905536":1444487341714,"1022457460780":1480585069116,"1022457460781":1480585069116,"1022457460783":1480585069116,"1021693679269":1478686804028,"1022457460774":1480585069116,"1022457460775":1480585069116,"1022511326589":1480585069128,"1022763112832":1509788624379,"1022457460697":1480585069116,"1022763112833":1509788624379,"1025289096979":1509788624286,"1022457460700":1480585069116,"1022457460701":1480585069116,"1022457460702":1480585069116,"1022457460688":1480585069116,"1022457460689":1480585069116,"1022457460691":1480585069116,"1022457460692":1480585069116,"1022457460693":1480585069116,"1023995597319":1491634246532,"1022457460694":1480585069116,"1022457460695":1480585069116,"1023995597317":1491634246529,"1025609069550":1509788624840,"1020437999142":1478686804029,"1025779592647":1509788624349,"1022457460684":1480585069116,"1022457460685":1480585069116,"1022457460686":1480585069116,"1022457460687":1480585069116,"1025609069545":1509788624841,"1022049668633":1509788624474,"1022457460728":1480585069116,"1022953690116":1509788624291,"1025609069534":1509788624841,"1022457460729":1480585069116,"1022457460731":1480585069116,"1025609069528":1509788624826,"772314657":1444487341748,"1021602456708":1478686804046,"1022457460723":1480585069116,"1022457460724":1480585069116,"1025609069522":1509788624848,"1022457460725":1480585069116,"1022457460726":1480585069116,"1022457460727":1480585069116,"1025609069518":1509788624864,"1025609069509":1509788624864,"1019427742221":1478686804021,"1022457460634":1480585069116,"1022457460636":1480585069116,"1022457460637":1480585069116,"1022457460638":1480585069116,"1022457460639":1480585069116,"1021965126009":1509788624269,"1022850145853":1509788624437,"1022457460616":1480585069115,"1020201545855":1478686804053,"1022457460618":1480585069115,"1022457460619":1480585069115,"1021007364209":1478686417089,"1022457460620":1480585069115,"1025902535732":1509788667461,"1025902535733":1509788667457,"1025902535734":1509788667458,"1021680572498":1478686804028,"1025902535735":1509788667466,"1022457460609":1480585069115,"1022457460611":1480585069115,"1022457460613":1480585069115,"1024028628079":1509788624517,"1022457460614":1480585069115,"1716313645":1491634246534,"1020194336989":1509788625076,"1022459426780":1478686417217,"1022071947446":1478686417176,"1022071947448":1478686417176,"1022457460657":1480585069116,"1022457460659":1480585069116,"1021490392336":1478686416990,"1006992805352":1478686804030,"1022457460648":1480585069116,"1022457460651":1480585069116,"1022457460652":1480585069116,"1022457460653":1480585069116,"1022457460654":1480585069116,"1022457460655":1480585069116,"1025609069447":1509788624435,"1022457460642":1480585069116,"1022457460645":1480585069116,"1020236673611":1509788624287,"1022457460568":1480585069115,"1022457460569":1480585069115,"1008304552905":1509788624310,"1987628794":1444487341722,"1022457460570":1480585069115,"1025609069436":1509788624451,"1022457460572":1480585069115,"1022457460574":1480585069115,"1022457460575":1480585069115,"1022457460563":1480585069115,"1025609069429":1509788624451,"1022457460564":1480585069115,"1022457460565":1480585069115,"1022457460567":1480585069115,"1021004349671":1478686417089,"1022457460600":1480585069115,"1022457460601":1480585069115,"1022215764098":1478686417064,"1022457460603":1480585069115,"1022457460604":1480585069115,"1024828515521":1509788624925,"1022457460606":1480585069115,"1019835370151":1509788625076,"1022457460596":1480585069115,"273590499":1444487341723,"1021004349657":1478686417089,"1022457460599":1480585069115,"1023926787733":1491634246530,"1022457460576":1480585069115,"1022457460577":1480585069115,"1022457460578":1480585069115,"1023926787736":1491634246530,"1022457460581":1480585069115,"1022457460582":1480585069115,"578722497":1478950494912,"1024094685411":1509788624521,"1022457460507":1480585069115,"1021965126135":1509788624269,"1021671790666":1478686417050,"1024094685413":1509788624523,"1022457460496":1480585069115,"1022457460497":1480585069115,"1025609069367":1509788624547,"1022457460498":1480585069115,"1025609069365":1509788624547,"1022238177798":1478686417282,"1022457460500":1480585069115,"1022457460502":1480585069115,"1022996027248":1509788624419,"1022457460503":1480585069115,"1021897889248":1478686417010,"1024028628195":1509788624517,"1022474496006":1478943089531,"1024117885458":1509788624325,"1025609069342":1509788624552,"1025609069340":1509788624564,"1022457460529":1480585069115,"1021885437214":1478686417024,"1025609069331":1509788624564,"1022139843669":1478686417277,"1021008412870":1478686804040,"1022457460523":1480585069115,"1009839548216":1491634246520,"1022457460525":1480585069115,"1022457460512":1480585069115,"1022457460516":1480585069115,"1022457460517":1480585069115,"1022457460519":1480585069115,"1021965125687":1509788624269,"1020021491682":1465470268315,"1022511328140":1480585069128,"1021669824934":1478686417009,"1020294215612":1465470268297,"1019000715480":1480585069067,"1024365836549":1495284743424,"4994797717":1509788667394,"1022377374650":1478686804071,"1021885437149":1478686417024,"1020437999365":1478686804066,"1025796894623":1509788624185,"1020942748981":1478686417033,"1025532264403":1509788624338,"1023198397135":1509788624424,"1012342197732":1478686417026,"1022072078736":1509788624945,"1016284456687":1480585069064,"1022511328202":1480585069128,"1023143215542":1509788625045,"1021721860835":1509788624400,"1008155755391":1478686804030,"1021844542239":1478686417257,"1016301623745":1480585069065,"1010024485806":1491634246521,"1021008413009":1478686804026,"1010024485803":1491634246526,"1021995141666":1478686417156,"1022202395035":1480585069084,"1021008413005":1478686804022,"1021653444319":1509788624206,"1020925577861":1478686417082,"1021871281455":1509788624399,"1025902667258":1509788667460,"1025902667255":1509788667466,"1025902667252":1509788667464,"1025902667250":1509788667457,"1025902667251":1509788667461,"1022039707443":1478686417169,"1004668867465":1478686804052,"1004668867464":1478686804052,"1021865775754":1509788624402,"1024880027367":1509788624443,"1022203181432":1478686417280,"1024880027370":1509788624443,"1024880027371":1509788624443,"1024880027369":1509788624443,"1024880027372":1509788624443,"1023995597717":1491634246532,"1021470338350":1478686416973,"4994797587":1509788667394,"4989817038":1509788624159,"1020824392894":1509788624934,"1021613598140":1478686416991,"4989817040":1509788624159,"4989817046":1509788624159,"4989817045":1509788624159,"4989817044":1509788624159,"1004668867527":1478686804052,"1004668867526":1478686804052,"1004668867525":1478686804052,"1021861057165":1509788624465,"1004668867532":1478686804052,"1004668867531":1478686804052,"1004668867530":1478686804052,"1004668867529":1478686804052,"1004668867528":1478686804052,"1010002727395":1491634246524,"1009997091259":1491634246520,"1010002727398":1491634246524,"1019006613682":1509788624315,"1021965125865":1509788624269,"1025855480051":1509788667405,"1024597702648":1509788624937,"1016839436629":1478686804031,"1022189782602":1478686417279,"1022008642922":1478686417158,"1020938816938":1478686417033,"1020437999552":1478686804066,"1022202394902":1480585069085,"1021938780836":1509788624959,"1022306860251":1478686417199,"1022306860249":1478686417199,"1025784704886":1509788624349,"1001813768763":1478686804029,"1022477118105":1478943089531,"1012210210463":1478686417223,"1024433995767":1509788624818,"1021965126417":1509788624271,"1024950540572":1509788625178,"1022074831526":1509788624530,"1021258005873":1465470268198,"1020254499116":1509788625077,"1021652788637":1509788624396,"1000368656451":1478686416993,"1022389563902":1478686417015,"1021195090218":1478686417235,"1022444877017":1478686417214,"1021924890071":1478686416980,"1024433995691":1509788624534,"1024365836892":1495284743424,"1021712423013":1478686417050,"1021712423019":1478686417050,"1022457460112":1480585069113,"1022457460114":1480585069113,"1021712423023":1478686417051,"1022457460116":1480585069113,"1022457460104":1480585069113,"1021712423026":1478686417051,"1022457460105":1480585069113,"1022457460106":1480585069113,"1022292443101":1478686417198,"1022457460108":1480585069113,"1022457460111":1480585069113,"1022457460099":1480585069113,"1022457460100":1480585069113,"1022457460102":1480585069113,"1022457460103":1480585069113,"1024950540638":1509788625178,"1022202395268":1480585069085,"1021156293430":1478686417038,"1001813768796":1478686804029,"1024273334752":1509788624277,"1012138119860":1478686417025,"1024950540608":1509788625178,"1553786595":1444487341755,"1022457460056":1480585069115,"1022457460057":1480585069115,"1022425610044":1478686417070,"1022457460058":1480585069115,"1022457460059":1480585069115,"1022457460062":1480585069115,"1022457460052":1480585069115,"1021713602689":1509788624816,"1022457460053":1480585069115,"1022457460054":1480585069115,"1022371606628":1478686417204,"1021736279621":1478686417251,"1021164157017":1478686417097,"1021736279616":1478686417251,"1022457460047":1480585069115,"1021164157012":1478686417097,"1023354928832":1509788625040,"1021317116238":1478686417102,"1020901853197":1478686417227,"1023933996406":1491634246531,"793286121":1491634246506,"1023933996400":1491634246531,"1023933996401":1491634246529,"1021990816034":1509788624978,"1020824393632":1509788624945,"1022511327281":1480585069128,"1021995141619":1478686417156,"1021995141618":1478686417156,"1022457460065":1480585069115,"1023933996399":1491634246531,"1022457460066":1480585069115,"1022457460067":1480585069115,"1022457460068":1480585069115,"1022457459999":1480585069114,"1020976696529":1478686417087,"1022457459976":1480585069114,"1022457459979":1480585069114,"1021965126631":1509788624188,"1022457459970":1480585069114,"1017808175146":1478686804016,"1022457459974":1480585069114,"1022457459975":1480585069114,"1022850145455":1509788625074,"1020626212891":1478686804028,"1021018506103":1478686417090,"1022457460016":1480585069115,"1021736279614":1478686417251,"1022457460009":1480585069114,"1022457460010":1480585069114,"1022457460011":1480585069114,"1022457460012":1480585069114,"1022233197506":1509788624181,"1022457460013":1480585069115,"1022233197507":1509788624181,"1022457460014":1480585069115,"1022457460000":1480585069114,"1022457460001":1480585069114,"1022457460002":1480585069114,"1022233197514":1509788624181,"1022233197515":1509788624181,"1022457460006":1480585069114,"1022233197512":1509788624181,"1022457460007":1480585069114,"1022233197513":1509788624181,"1022457459928":1480585069114,"1022457459929":1480585069114,"1022457459930":1480585069114,"1022457459922":1480585069114,"1022457459926":1480585069114,"1022298865187":1478686417287,"1022457459927":1480585069114,"1020999369650":1478686416990,"1022457459916":1480585069114,"1025100355396":1509788624273,"1022457459917":1480585069114,"1022457459918":1480585069114,"1024727854463":1509788624170,"1022457459909":1480585069114,"1022457459962":1480585069114,"1022457459953":1480585069114,"1022457459954":1480585069114,"1022457459955":1480585069114,"1022457459956":1480585069114,"1022457459957":1480585069114,"1024433995461":1509788624195,"1022457459947":1480585069114,"1021685422827":1509788624396,"1021670087568":1478686417120,"1022457459949":1480585069114,"1022057401587":1478686417270,"1020626213309":1478686804028,"1021810856704":1478686417131,"601659545":1444487341743,"1022457459856":1480585069114,"1023110319495":1509788624299,"1022151247696":1478686417185,"1022457459859":1480585069114,"1022457459860":1480585069114,"1023821536039":1491634246523,"1022457459848":1480585069114,"1022457459850":1480585069114,"1022185587899":1478686417187,"1022457459853":1480585069114,"1619057622":1478950494926,"1021351065342":1478686417104,"1022457459840":1480585069114,"1022457459841":1480585069114,"1024947525654":1509788625069,"1022060153918":1478686804050,"1022457459843":1480585069114,"1022457459844":1480585069114,"1022202395569":1480585069085,"1022457459847":1480585069114,"1020824393298":1509788624945,"1022457459896":1480585069114,"1022457459902":1480585069114,"572168562":1478950494911,"1021959621135":1509788624466,"1022073258964":1478686417176,"1022457459893":1480585069114,"1022426396357":1478686417211,"1020977745042":1478686417087,"1864291429":1478950494927,"1020712459430":1509788624392,"1025278872588":1509788624461,"1022457459801":1480585069114,"1025278872590":1509788624461,"1025278872591":1509788624461,"1022202395496":1480585069085,"1022457459805":1480585069114,"1025278872587":1509788624461,"1022457459794":1480585069114,"1024098880104":1509788624534,"1022457459797":1480585069114,"1553786642":1444487341755,"1021985966176":1478686417153,"1022457459786":1480585069114,"1022457459787":1480585069114,"1025278872600":1509788624461,"1022457459789":1480585069114,"1021985966182":1478686417153,"1020918892792":1478686804031,"1021985966185":1478686417153,"1022457459776":1480585069114,"1025278872597":1509788624461,"1022457459782":1480585069114,"1025278872594":1509788624461,"1025278872595":1509788624461,"1025530428718":1509788624543,"1025530428719":1509788624537,"1022457459835":1480585069114,"1025530428717":1509788624541,"1019872726638":1478686804021,"1024637676129":1509788667503,"1024950540440":1509788625178,"1022457459839":1480585069114,"1021985966175":1478686417153,"1024365837228":1495284743424,"1021965126279":1509788624269,"1025530428729":1509788624524,"1023210194753":1509788624915,"1020526339917":1465470268323,"1024950540419":1509788625178,"1024727854500":1509788624170,"1020073097777":1509788624386,"1008286857659":1478686804030,"1024727854497":1509788624170,"1021327339761":1478686417005,"1024727854498":1509788624170,"1006617814075":1509788624386,"1022457459730":1480585069113,"1010069706745":1491634246534,"1022457459732":1480585069113,"1016664690385":1478686804042,"1022457459733":1480585069113,"1024727854505":1509788624170,"1024950540529":1509788625178,"1022457459720":1480585069113,"1022457459723":1480585069113,"1024077255935":1509788624518,"1024880026790":1509788624557,"1020990328060":1478686417088,"1022457459725":1480585069113,"1025100355461":1509788624173,"1024880026791":1509788624557,"1025756260589":1509788624969,"1017808175395":1478686804016,"1022457459727":1480585069113,"1022457459712":1480585069113,"1024880026795":1509788624557,"1022457459714":1480585069113,"1024880026792":1509788624557,"1024880026793":1509788624557,"1022457459718":1480585069113,"1022202395405":1480585069085,"1022457459770":1480585069113,"1024727854470":1509788624170,"1024727854471":1509788624170,"1024727854465":1509788624170,"1022079812542":1478686417272,"1024727854467":1509788624170,"1022071292725":1478686417012,"1020526339866":1465470268322,"1022071292723":1478686417012,"1022457459764":1480585069113,"1022457459765":1480585069113,"1022457459767":1480585069113,"1024727854475":1509788624170,"1024727854485":1509788624170,"1024727854486":1509788624169,"1024727854480":1509788624170,"1024950540491":1509788625178,"1022502677232":1509788625007,"857245935":1478686417020,"1022260066411":1478686417301,"1022060154013":1478686804050,"857245922":1478686417020,"1024885531876":1509788625023,"1024727854495":1509788624170,"1024727854490":1509788624169,"1022457459672":1480585069113,"1022457459673":1480585069113,"1022457459674":1480585069113,"1022457459676":1480585069113,"1022457459678":1480585069113,"1022457459664":1480585069113,"1022457459665":1480585069113,"1021713604100":1509788624220,"1022457459667":1480585069113,"1022457459668":1480585069113,"1022457459656":1480585069113,"1023996909062":1509788624430,"1021462998796":1478686417108,"1022457459663":1480585069113,"1022457459648":1480585069113,"1024727853688":1509788624168,"1021482133988":1478686417007,"1022457459654":1480585069113,"1024779494736":1509788624477,"1022457459708":1480585069113,"1022457459709":1480585069113,"1022457459711":1480585069113,"1023730837466":1509788624969,"1024779494723":1509788624477,"1022457459680":1480585069113,"1021468371095":1509788624405,"1022457459681":1480585069113,"1024779494730":1509788624477,"1025609070532":1509788624840,"1025609070533":1509788624840,"1024779494732":1509788624477,"1023884712166":1509788624258,"1025609070524":1509788624863,"1021957262798":1478686417147,"1022291261925":1478686804044,"1022060153632":1478686804050,"1022291261926":1478686804044,"1023884712160":1509788624258,"1022291261927":1478686804044,"1024779494711":1509788624477,"1022291261928":1478686804044,"1022291261929":1478686804044,"1024779494713":1509788624477,"1024576467235":1509788624507,"1022291261930":1478686804044,"1023884712172":1509788624258,"1022291261931":1478686804044,"1022291261932":1478686804044,"1022291261933":1478686804044,"1022291261934":1478686804044,"1023884712168":1509788624258,"1024779494718":1509788624477,"1022291261935":1478686804044,"1022291261936":1478686804044,"1022291261937":1478686804044,"1022291261938":1478686804044,"1023884712180":1509788624258,"1021226023278":1478686417099,"1022291261940":1478686804044,"1023884712178":1509788624258,"1022291261941":1478686804044,"1021957262813":1478686417147,"1022291261942":1478686804045,"1023884712176":1509788624258,"1022291261943":1478686804045,"1022291261944":1478686804045,"1022291261945":1478686804045,"1022291261946":1478686804045,"1022291261947":1478686804045,"1021617660313":1478686417117,"1022291261948":1478686804045,"1022291261949":1478686804045,"1023884712184":1509788624258,"1022457459641":1480585069113,"1022457459642":1480585069113,"1022457459644":1480585069113,"1022457459645":1480585069113,"695768351":1478686804024,"1022457459647":1480585069113,"1023884712142":1509788624258,"1021957262821":1478686417147,"1218770132":1480585069060,"1023884712150":1509788624258,"1023884712148":1509788624258,"1023884712149":1509788624258,"1021523815176":1478686417047,"1023884712145":1509788624258,"1021934980232":1509788624815,"1012140741848":1478686417073,"1023884712159":1509788624258,"1023884712156":1509788624258,"1023884712157":1509788624258,"1023884712153":1509788624258,"1025609070461":1509788624866,"1022184800913":1478686417013,"1664933809":1491634246534,"1020496979489":1478686804054,"1000237719209":1444487341761,"1025609070447":1509788624840,"1021049440053":1478686417232,"1024779494885":1509788624478,"741511339":1478686417020,"1910558075":1444487341730,"1025609070437":1509788624826,"1013878666130":1478686804015,"1021684899174":1509788624396,"1022288771428":1478686417067,"1025609070428":1509788624864,"1023111105124":1509788625045,"1025609070422":1509788624864,"1020526338138":1465470268322,"1021687782676":1509788624396,"1022470304676":1478686417073,"1019000716665":1480585069063,"1021713604277":1509788624857,"1022347097334":1478686417202,"1021713604273":1509788624857,"1021713604275":1509788624857,"1021713604274":1509788624857,"1022173397601":1478686417278,"1012138120206":1478686417025,"1218770019":1480585069060,"1025620735972":1509788624932,"1025620735973":1509788624946,"1020654133149":1478686804057,"1022030662113":1509788624463,"1025620735974":1509788624931,"1025620735975":1509788624941,"1021755545920":1509788624403,"1025609070384":1509788624840,"1025620735970":1509788624941,"1025620735971":1509788624930,"1022879634521":1509788625111,"1019846119330":1509788624282,"1021500746301":1478686804031,"1025609070360":1509788624826,"2387620537":1509976385181,"1021327865854":1465470268218,"1021327865853":1465470268218,"1021327865852":1465470268218,"1023020403934":1509788625049,"1021327865850":1465470268218,"1021327865848":1465470268218,"336374004":1444487341740,"1024365837536":1495284743424,"1021327865846":1465470268217,"1022173397596":1478686417278,"1021327865845":1465470268217,"1024798107310":1509788625176,"1021327865844":1465470268217,"1025609070341":1509788624864,"1021327865842":1465470268217,"1022502677510":1509788625007,"1026226541105":1514456869772,"1018469194902":1509788624428,"1022697185387":1509788625015,"1022697185381":1509788625015,"1022697185378":1509788625015,"1022697185379":1509788625015,"1019369417413":1509788624369,"1023578927088":1491634246536,"1023578927089":1491634246536,"1023578927090":1491634246536,"1024028627232":1509788624517,"1023578927096":1491634246536,"4994798738":1509788667394,"1026226541079":1514456869772,"1025609070290":1509788624866,"1021676117351":1478686417249,"1022697185374":1509788625015,"1025609070284":1509788624840,"1022697185372":1509788625015,"1022697185370":1509788625016,"1025609070281":1509788624840,"1025609070278":1509788624840,"1019384227294":1509788624933,"1024098880732":1509788624195,"1025609070272":1509788624826,"1026226541070":1514456869772,"1025609070268":1509788624826,"1009844265671":1509788624353,"1025609070261":1509788624848,"1021934980529":1509788624533,"1025609070255":1509788624864,"1025609070250":1509788624864,"1022697185339":1509788625016,"1025609070249":1509788624864,"1021005792514":1478686417231,"1024919870579":1509788624218,"1021455789581":1509788624977,"1024919870577":1509788624218,"1024919870581":1509788624218,"1024919870584":1509788624218,"1026226541146":1514456869772,"1012138120615":1478686417025,"1023862824804":1491634246520,"1020842087282":1509788625021,"1026226541122":1514456869772,"1021934849418":1478686417143,"1021588825831":1509788624437,"1024919870574":1509788624218,"1025609070204":1509788624229,"1025609070194":1509788624209,"1025792174235":1509788624349,"1024954472819":1509788625021,"1025609070189":1509788624199,"1767691464":1478950494926,"749244720":1444487341751,"1012524778072":1478686416991,"1026226541200":1514456869772,"1024024039899":1509788624277,"1020082535648":1465470268310,"1000789556984":1478686804059,"1021092692122":1478686417094,"1024028627355":1509788624517,"1022086366303":1478686417179,"1021287494695":1465470268201,"1024919870626":1509788625151,"1024919870627":1509788625151,"1021287494692":1465470268201,"1024919870625":1509788625151,"1022359417860":1478686417289,"1024919870630":1509788625151,"1002035671205":1478686417019,"1024919870628":1509788625151,"1009865104887":1478686804025,"1009275388113":1478686804024,"1024723528474":1509788667888,"1024888151368":1509788624342,"1020988361355":1478686416992,"1020551897230":1478686804047,"1025609070131":1509788624229,"1021558678662":1509788624401,"1025609070124":1509788624209,"158381219":1444487341704,"1025609070121":1509788624209,"1022060153533":1478686804050,"1025609070118":1509788624199,"1025609070119":1509788624199,"1024098880568":1509788624819,"1022021355534":1509788624420,"1025609070110":1509788624227,"1021748730356":1509788624615,"1021748730353":1509788624615,"1022060153485":1478686804050,"1021748730367":1509788624614,"1021748730361":1509788624615,"1022424428576":1509788624352,"1021934980365":1509788624194,"1021748730349":1509788624615,"1012160009312":1478686417025,"1021748730350":1509788624615,"1021748730347":1509788624614,"1021172022388":1478686417098,"1021172022384":1478686417098,"1021748730387":1509788624615,"1021748730386":1509788624615,"1022346704507":1478686417202,"1025609070068":1509788624209,"1023288868389":1509788625007,"1021748730373":1509788624615,"1022701118274":1509788624972,"1018829375498":1509788624929,"1016284455352":1480585069064,"1021848867855":1509788624993,"1022611072674":1509788625063,"1021861057876":1509788624467,"1021748730374":1509788624615,"1022701118273":1509788624972,"1021748730369":1509788624615,"1021748730368":1509788624615,"1021748730370":1509788624615,"1021821867937":1478686417132,"1025902404218":1509788667460,"1012151227931":1478686417223,"1021748730383":1509788624615,"1025902404216":1509788667461,"1516299387":1478950494924,"1021748730382":1509788624615,"1025902404217":1509788667459,"1022127916386":1478686417276,"1021748730376":1509788624615,"1021329961712":1465470268219,"1021748730378":1509788624615,"1022060153156":1478686804050,"1025609070044":1509788624199,"1016444229127":1480585069061,"1025609070037":1509788624214,"1025609070034":1509788624227,"1025609070035":1509788624227,"1021716225480":1509788624817,"1020764230805":1478686416996,"1021962506083":1478686417148,"1022092003263":1478686417180,"1021962506086":1478686417148,"1024134139272":1509788667503,"1021470337739":1478686416973,"1021459459345":1509788624398,"1025569617425":1509788624348,"1025609069992":1509788624229,"1025609069990":1509788624209,"1022072080010":1509788624921,"1025609069988":1509788624209,"1025609069989":1509788624209,"1021296276621":1478686417102,"1022342903528":1478686417069,"1025609069978":1509788624227,"1022701118263":1509788624972,"1022701118267":1509788624973,"1025833985789":1509788667452,"1018829375604":1509788624929,"1000237718600":1444487341761,"1010024486073":1491634246521,"1025890215241":1509788667442,"1010024486068":1491634246526,"1024056283372":1509788624328,"1004522331225":1478686804040,"1010024485966":1491634246516,"1010024485961":1491634246521,"4994799411":1509788667394,"1026226540980":1514456869772,"1010024485963":1491634246521,"1328607679":1491634246518,"1583538413":1491634246518,"1026226540967":1514456869772,"1010024485974":1491634246526,"1021546358425":1478686417300,"1010002728620":1491634246525,"1025910793026":1509788667579,"1025910793024":1509788667579,"1025609069915":1509788625134,"1025910793031":1509788667579,"1025609069909":1509788625111,"1017446292166":1478686804066,"1025910793038":1509788667579,"1017446292167":1478686804066,"1017446292165":1478686804066,"1024680406504":1509788624442,"1024680406506":1509788624442,"1024680406507":1509788624442,"1021716225361":1509788624194,"1024680406508":1509788624442,"1024680406511":1509788624442,"1023330155885":1509788625040,"1025796892693":1509788625114,"1025796892695":1509788625105,"1025736600825":1508316495865,"1025609069886":1509788625164,"1024187222137":1509788624236,"1021392613786":1478686417105,"1021428002813":1478686804026,"1026226541055":1514456869772,"1021308859643":1478686417005,"1025910793022":1509788667579,"1026226541008":1514456869772,"1021934980637":1509788625100,"632462166":1478686417024,"1018187394747":1509788624928,"1026226541015":1514456869772,"1021960671132":1509788624464,"1022060153239":1478686804050,"1025609069835":1509788625167,"1023920494716":1509788624972,"1025609069831":1509788625134,"1022879635063":1509788625245,"1022147052192":1478686417013,"1026226541003":1514456869772,"1025609069822":1509788625112,"1025609069818":1509788625143,"1022291262118":1478686804046,"1022291262119":1478686804046,"1022291262120":1478686804046,"1022291262121":1478686804046,"1022202396645":1480585069084,"4994799294":1509788667394,"1022291262122":1478686804046,"1025609069812":1509788625164,"1021344248637":1478686417041,"1025609069810":1509788625164,"1022978068958":1509788625136,"1018690310481":1509788624378,"1021716225269":1509788624533,"1516299634":1478950494924,"925403198":1478686417020,"1021435342271":1478686417241,"1021474007916":1478686417109,"1022209605506":1509788624938,"1022221008622":1478686417064,"1022209605504":1509788624938,"1020834484661":1478686804050,"1020235887878":1465470268181,"1015513140874":1509788624369,"1020834484665":1478686804050,"1012304580043":1509788624369,"1021293917726":1478686417004,"1016159414289":1478686804040,"1025609069777":1509788625005,"1025609069774":1509788625134,"1024028627715":1509788624517,"1023748006909":1509788667836,"1022149018382":1509788624949,"1016670980484":1478686804063,"1025569486690":1509788624351,"1021967879644":1509788624467,"1025609069765":1509788625112,"1025609069763":1509788625143,"1016574381917":1480585069080,"1024028627825":1509788624517,"1021713603913":1509788624560,"1021713603912":1509788624560,"1022502678094":1509788625007,"1021713603911":1509788624560,"1021713603910":1509788624560,"1025627550622":1509788624999,"1022420366005":1478686417209,"1025627550619":1509788625084,"1534256144":1444487341719,"1023959422768":1509788624825,"1021323801642":1478686417103,"1021721730269":1509788624403,"920422835":1491634246517,"1023855353110":1491634246520,"1023855353106":1491634246537,"1025609069704":1509788625134,"1025609069702":1509788625134,"1019052751829":1509788624315,"1022204362572":1478686417280,"1021927641291":1478686417142,"1025609069691":1509788625164,"1021927641287":1478686417142,"1021168483612":1478686417098,"1007198813892":1478686804017,"1021488687630":1478686417046,"1021739555614":1478686417051,"1022263999717":1478686417014,"1022112450030":1478686417182,"1025609069651":1509788624435,"1025048975085":1509788625017,"1021047604333":1478686417092,"1025609069646":1509788624427,"1025609069640":1509788624440,"1022399657107":1478686417292,"1024153275167":1509788667495,"1025609069619":1509788624451,"1021491702423":1478686416992,"1022209605502":1509788624938,"1021489212044":1478686417110,"1021114449957":1478686417037,"1022209605500":1509788624938,"1021489212046":1478686417110,"1021489212042":1478686417110,"1021489212039":1478686417110,"1024187222357":1509788624236,"1024187222354":1509788624236,"1024187222355":1509788624236,"1024187222352":1509788624236,"1024187222353":1509788624236,"1021713604093":1509788624220,"1024187222350":1509788624236,"1021713604092":1509788624220,"1021713604094":1509788624220,"1024187222349":1509788624236,"168998378":1444487341703,"1709758994":1478686417018,"1023920494974":1509788624972,"1019615566531":1509788624304,"1021783189483":1509788624395,"1019388926140":1480585069073,"1025601047161":1509788624520,"1025601047162":1509788624520,"1025601047163":1509788624520,"1021564033310":1478686417114,"1000527901938":1444487341713,"1022278419554":1478686417014,"1019388926139":1480585069073,"1025601047155":1509788624520,"1025601047156":1509788624520,"1025601047157":1509788624520,"1025601047158":1509788624520,"1024687232255":1509788624223,"1025601047159":1509788624520,"1024687232224":1509788624223,"1022202396925":1480585069085,"1024687232227":1509788624223,"1024687232228":1509788624224,"1024687232229":1509788624223,"1022481977432":1478943089531,"1016952129503":1444487341760,"1021816351172":1509788625014,"1024637686260":1509788667502,"1021564033315":1478686417114,"1008040964927":1478686804052,"1021564033312":1478686417114,"1021564033318":1478686417114,"1021564033316":1478686417114,"1008058135647":1480585069065,"1020294221539":1465470268298,"4984203611":1509788624159,"1010092404374":1491634246516,"1019211976057":1509788624316,"1011625773346":1478686804032,"1021604666581":1478686416974,"1019211976053":1509788624316,"1022816085028":1509788625110,"1024687232144":1509788624562,"795668239":1478950494916,"1024489572572":1509788625029,"1021484078516":1478686804038,"1021484078515":1478686804038,"1021484078514":1478686804038,"1021484078513":1478686804038,"1021484078512":1478686804038,"1021484078511":1478686804038,"1025628310696":1509788624204,"1021484078510":1478686804038,"1025628310697":1509788624197,"1021616594311":1478686417008,"1021484078509":1478686804038,"1021484078508":1478686804038,"1021484078507":1478686804038,"1025628310702":1509788624186,"1024687232138":1509788624562,"1019727621142":1509788624317,"1024687232139":1509788624562,"1024687232140":1509788624562,"1024687232141":1509788624562,"1025628310695":1509788624200,"1024496519343":1509788624441,"1021740852448":1478686417125,"1026507718877":1515854751198,"294048021":1478686417019,"1021816351096":1509788625013,"1021895257551":1509788624465,"1022202396791":1480585069084,"1025797789215":1509788624406,"1024780294631":1509788624511,"1024780294624":1509788624426,"1025797789208":1509788624431,"1025797789209":1509788624425,"1025797789207":1509788624428,"1024780294637":1509788624434,"1024780294638":1509788624426,"1022281172209":1478686417197,"1021113040712":1478686417037,"1024780294645":1509788624427,"1024780294640":1509788624456,"1016737856022":1478686804063,"1025756107660":1509788624970,"1024780294652":1509788624451,"1024780294649":1509788624454,"1021693534595":1509788624851,"1021693534594":1509788624851,"1025879972633":1509788667403,"1021941657681":1478686417143,"1022023447921":1478686417267,"1022202396712":1480585069085,"1021693534596":1509788624851,"1025593313801":1509788624929,"1021693534600":1509788624851,"1014848326031":1509788625017,"1024687232034":1509788625157,"1019882419639":1509788624361,"1021933268983":1478686417260,"1024780294561":1509788624441,"1024687232028":1509788625157,"1024687232029":1509788625157,"1024687232030":1509788625157,"1016952129297":1444487341760,"1024687232031":1509788625157,"1023232900473":1509788624277,"1011599034856":1478686804033,"1025797789614":1509788625087,"1211795756":1444487341716,"1025797789608":1509788625122,"1025797789606":1509788625114,"1025797789607":1509788625105,"1021484078275":1478686804038,"1021484078274":1478686804038,"1021484078273":1478686804038,"1021484078272":1478686804038,"1022263214701":1509788625019,"1022263214699":1509788625016,"1021347368136":1478686417005,"1021606239675":1509788624420,"1022093441113":1478686417180,"1022264918625":1478686417067,"1021770082203":1478686417127,"1022941916580":1509788624935,"1020581142224":1480585069077,"1024678056482":1509788624199,"1021484078271":1478686804038,"1021484078270":1478686804038,"1021484078269":1478686804038,"1021484078268":1478686804038,"1021484078267":1478686804038,"1020744853675":1509788624959,"1021484078266":1478686804038,"1021484078265":1478686804038,"1021484078264":1478686804038,"1021484078263":1478686804038,"1021484078262":1478686804038,"1021484078261":1478686804038,"1021933268602":1478686417143,"1021286811882":1478686417101,"1022755135842":1509788624393,"1021286811879":1478686417101,"1022202397078":1480585069084,"1021391539768":1478686417006,"1024727865112":1509788624279,"1016952129140":1444487341760,"1025530922763":1509788624345,"1020374176374":1478686804047,"1021606239491":1509788624817,"1022021088335":1478686417162,"1025524893565":1509788625008,"1022111136715":1478686417182,"1019615552648":1509788624315,"1022737833658":1509788625056,"1012371060566":1478686417026,"1010001308051":1491634246520,"1024529681297":1509788625027,"1010755998948":1509788625017,"1024687232288":1509788624859,"1024098873394":1509788625149,"1024098873395":1509788625149,"1022018597937":1478686417301,"1024098873392":1509788625148,"1024098873393":1509788624445,"1024098873398":1509788624445,"1024098873399":1509788624445,"1024098873396":1509788625149,"1024098873397":1509788624445,"1025791104220":1509788624418,"1024098873402":1509788625149,"1025791104221":1509788624418,"1021747144151":1478686417126,"1024509102260":1509788624935,"1025791104223":1509788624418,"1024098873406":1509788624445,"1025791104218":1509788624418,"1025791104219":1509788624418,"1024687232272":1509788624859,"1025791104225":1509788624418,"1025791104226":1509788624418,"1025791104227":1509788624418,"1024687232286":1509788624859,"1021937332523":1478686417055,"1021937332522":1478686417055,"1021937332521":1478686417055,"1021602176290":1478686417048,"1021037935503":1478686417001,"1026225090266":1514456869772,"1024687232270":1509788624859,"1024687232271":1509788624859,"1024098874336":1509788624218,"1009999080015":1491634246516,"1021632322786":1478686417119,"1016952129009":1444487341760,"1019159152739":1509788624312,"1018884192453":1509788624301,"1019159152737":1509788624315,"1009848474960":1491634246512,"1020781947297":1478686416997,"1019159152741":1509788624314,"1024930373733":1509788625021,"1021727744379":1509788624395,"1012114154600":1478686804024,"1022202397396":1480585069084,"1024098874331":1509788624218,"1295552258":1478950494922,"1024098874334":1509788624218,"1024098874335":1509788624218,"1019299926482":1509788624282,"1016731040566":1478686804056,"1022112577659":1509788624944,"1024098874333":1509788624218,"1024637686663":1509788667502,"4984204114":1509788624159,"1389924498":1444487341715,"1024299810743":1509788624293,"1002050063453":1444487341702,"1023154780738":1509788625044,"1022034327394":1478686417167,"1019882420013":1509788624368,"1020626231416":1478686804028,"1210223287":1444487341727,"1022207377974":1478686417013,"1020792433026":1478686417225,"1019811115791":1509788625080,"1023927166119":1491634246517,"1020768446717":1478686417029,"1021259285949":1465470268198,"1022093441997":1478686417180,"1016952128847":1444487341760,"1021543324389":1478686417047,"1024678056399":1509788624199,"1021262169519":1478686804047,"1023627269797":1509788624932,"1021536901756":1478686417245,"1024096514760":1509788624325,"1021536901754":1478686417245,"1210223351":1444487341731,"1020576423200":1478686416995,"1210223354":1444487341720,"1016737855557":1478686804063,"1024678056321":1509788624199,"1021900368913":1478686417054,"1023377049071":1509788624974,"1025522009607":1509788624342,"1023377049057":1509788624974,"1023377049058":1509788624973,"1025522009605":1509788624340,"1023377049062":1509788624973,"1025522009601":1509788624335,"1021971804606":1478686417010,"1023377049073":1509788624973,"1022594700433":1480585069076,"1025675889858":1509788624393,"1023691234060":1509788624392,"1020922458225":1478686417081,"1019347768856":1509788625079,"1022443834790":1478686417295,"1022478046129":1478943089315,"1021693534835":1509788624555,"1023377049048":1509788624973,"1021693534838":1509788624555,"1021357198969":1478686417006,"1021693534837":1509788624555,"1021357198968":1478686417006,"1024687232970":1509788624448,"1021693534841":1509788624555,"1024687232971":1509788624448,"1023377049043":1509788624973,"1024687232972":1509788624448,"1024687232973":1509788624448,"1023377049046":1509788624974,"1024687232975":1509788624448,"1024780294660":1509788624509,"1016731040329":1478686804063,"1021988319468":1509788624463,"1024880696330":1509788625023,"1021693534727":1509788624217,"1016952128699":1444487341760,"1021693534726":1509788624217,"1021693534725":1509788624217,"1022323246239":1478686417288,"1024780294669":1509788624438,"1021693534728":1509788624217,"1011625773630":1478686804032,"1021680558934":1478686804028,"1021142106985":1478686417002,"1025459093915":1509788624351,"1022321542308":1478686417015,"1021445935447":1478686417107,"1022697201208":1509788625016,"1020985636040":1478686804039,"1021700874670":1509788624303,"1024780294690":1509788624424,"1024780294691":1509788624438,"1019360482569":1509788624317,"1016777572152":1478686804016,"1024727864603":1509788624303,"1021594572967":1478686417114,"1021741246435":1478686417125,"1021646085566":1478686417008,"1023561601633":1509788624531,"1021279079321":1480585069097,"1022396778725":1478686417291,"1022246699496":1478686417195,"1021405828035":1478686417240,"1025880365172":1509788667450,"1022022923797":1509788624466,"1025627656040":1509788624509,"1020790859965":1478686417077,"1020818124508":1478686804022,"1020818124505":1478686804022,"1020818124504":1478686804022,"1020818124503":1478686804022,"1022827619951":1509788624990,"1025593313543":1509788624929,"1007891540003":1478686804023,"1020997040919":1478686417300,"1022579103051":1480585069125,"1022470837048":1478686417299,"1021270297420":1478686804034,"1016731040477":1478686804051,"1021497448137":1478686417007,"1022827619957":1509788624990,"1016952128545":1444487341760,"1019427199383":1478686804067,"1009270013478":1509788624386,"1019427199382":1478686804067,"1019286819122":1509788625076,"1019427199384":1478686804067,"1011970366779":1478686417299,"1022233199301":1509788624181,"1011970366781":1478686416993,"1025412856904":1509788624543,"1022038652247":1478686417168,"1023095404073":1509788624978,"1025911692809":1509788667818,"1022038652243":1478686417168,"1022233199304":1509788624181,"1025407220760":1509788624298,"626581851":1478686417020,"1003634977196":1478950494936,"1021723420552":1478686417123,"1021245129229":1478686417100,"1021493121394":1478686417111,"1021673088183":1478686417120,"1009275386201":1478686804024,"1023947615448":1491634246532,"1023947615449":1491634246532,"335597633":1444487341732,"1013062048668":1478686804064,"1021900499616":1478686417054,"1021742424124":1509788624395,"1025508508076":1509788624345,"1025508508077":1509788624338,"1025508508072":1509788624344,"1025508508074":1509788624336,"1025508508071":1509788624340,"582149840":1444487341747,"1022238836390":1509788624947,"1022238836391":1509788624941,"1022238836392":1509788624931,"1019964079643":1465470268315,"1016952128396":1444487341760,"1022092000767":1478686417180,"1019489721027":1509788624302,"1024273334044":1509788624277,"1856416295":1478686417020,"1024273334046":1509788624277,"1024273334040":1509788624277,"1856416291":1478686417020,"1025034054818":1509788667497,"1020294220325":1465470268298,"1021308833442":1509788625017,"4984204677":1509788624159,"1022697200124":1509788625015,"1022441081409":1478686417295,"1049164315":1491634246518,"1025797657145":1509788624865,"1012995071870":1478686804062,"1023880634439":1509788624939,"1019263227034":1509788624315,"1012995071866":1478686804062,"1024638080366":1509788667462,"1022032228738":1478686417166,"1018994263186":1509788624282,"1022209082417":1478686417191,"1021055631357":1478686417232,"1024273334052":1509788624277,"1024273334053":1509788624277,"1024273334054":1509788624277,"1024273334048":1509788624277,"1009748336102":1491634246511,"1021501379176":1509788624401,"1021936415748":1509788624465,"1021259416550":1465470268199,"1021259416549":1465470268199,"1020090664449":1509788624361,"1019929214140":1509788624322,"1024435306796":1509788624462,"1025797788251":1509788624616,"261278585":1444487341722,"1025797788234":1509788624831,"1025797788235":1509788624822,"1024375014809":1509788625031,"1025797788233":1509788624827,"1021096000000":1478686417094,"1022169463788":1509788624924,"1020985635468":1478686804039,"1016952128224":1444487341760,"1021509899124":1478686417244,"1018279941117":1465470268271,"1022331765360":1478686417068,"1021509899128":1478686417244,"1024433995992":1509788624420,"1024985555001":1509788624169,"1021120772693":1478686417002,"1024985555003":1509788624169,"1013076338129":1478686804033,"1024985555004":1509788624169,"1021120772690":1478686417002,"1024985555007":1509788624169,"1009749646359":1491634246514,"1024673076884":1509788624815,"1020609586369":1478686417075,"1021109893943":1478686417232,"1024673076887":1509788624533,"1021071620400":1478686417002,"1020955226112":1478686417033,"1025811026614":1509788667791,"1022029082630":1509788624466,"1024615402097":1509788624188,"1021425226775":1509788624977,"1020875273545":1478686417031,"1023774726170":1491634246535,"1021308833657":1509788625017,"1021250765567":1478686416984,"1025412856534":1509788624829,"1025412856535":1509788624834,"1017868073007":1478686804056,"1017808175007":1478686804016,"1017868073012":1478686804056,"1025629358556":1509788624565,"1017868073011":1478686804056,"1017868073008":1478686804056,"1017868073009":1478686804056,"1022028820539":1509788624433,"1017868073156":1478686804056,"1017868073154":1478686804056,"1017868073155":1478686804056,"1017868073152":1478686804056,"1017868073153":1478686804056,"1022262953721":1509788624957,"1020435780558":1480585069065,"1021504131862":1478686417007,"1024673076752":1509788625100,"1022246569866":1478686417195,"1016952128060":1444487341760,"1021308833769":1509788625018,"1017770554099":1478686804022,"1022002475324":1509788624466,"1009712419501":1491634246511,"1022246569862":1478686417195,"1003284618568":1478686804054,"1025412856420":1509788624429,"1024433995836":1509788625101,"1025412856423":1509788624408,"1025278898772":1509788624454,"1022246569872":1478686417195,"1017165125362":1478686804020,"1017923552752":1478686804021,"1011850302452":1478686804022,"1024673076802":1509788624419,"1013618099890":1480585069065,"1022030918444":1478686417267,"1024673076666":1509788624194,"1024132298226":1509788624328,"1012283766316":1478686417073,"1022202398449":1480585069085,"1024303741839":1509788624948,"1025610485229":1509788624520,"1022065651995":1478686417174,"1023444290764":1509788624960,"1026225088781":1514456869772,"1025620708608":1509788624970,"1025620708609":1509788624970,"1022331633948":1478686417068,"1004071551473":1478686804061,"1024313178992":1509788624926,"1021274754584":1478686417101,"1004071551472":1478686804061,"1004071551469":1478686804061,"1012335146329":1478686417223,"1004071551470":1478686804061,"1004071551465":1478686804061,"1017517977207":1478686804045,"1004071551466":1478686804061,"1017517977208":1478686804045,"1017517977209":1478686804045,"1004071551460":1478686804060,"1017517977210":1478686804045,"1004071551463":1478686804061,"1017517977211":1478686804045,"1004071551462":1478686804060,"1017517977212":1478686804045,"1004071551457":1478686804060,"1024778723104":1509788625024,"1022268589383":1478686417067,"1017517977213":1478686804045,"1004071551456":1478686804060,"1017517977214":1478686804045,"1004071551459":1478686804060,"1017517977215":1478686804045,"1021238312960":1478686416987,"1021308832847":1509788625017,"1020970168345":1478686417034,"1012353626747":1478686416972,"1012284552783":1478686417026,"1021940872955":1478686417143,"1017974407830":1509788624372,"1025797787710":1509788624540,"1025797787711":1509788624542,"1022886080174":1509788624996,"1019908763945":1509788624354,"1021693405133":1478686804031,"1022579101717":1480585069124,"1019908763954":1509788625076,"1018974108143":1509788624317,"1016952127849":1444487341760,"1018974108140":1509788624314,"1025500906218":1509788624269,"1023394480485":1509788625039,"1022551315133":1509788624504,"1023877490066":1491634246512,"1022202398277":1480585069085,"294704931":1444487341736,"1021476868840":1478686417109,"1024540560715":1509788667549,"1023947222570":1491634246532,"1024540560712":1509788667549,"1023947222567":1491634246529,"1022551315185":1509788624504,"1024540560735":1509788667549,"1021429159891":1478686417044,"1024540560732":1509788667549,"1024540560728":1509788667549,"1024540560729":1509788667549,"1526111277":1444487341741,"1025372879564":1509788625135,"1024540560721":1509788667549,"1020626232348":1478686804028,"1019448434130":1478686804020,"1025508508436":1509788624336,"1024540560742":1509788667549,"1021549223696":1478686417047,"1024540560741":1509788667549,"1024540560738":1509788667549,"1025508508433":1509788624339,"1024540560739":1509788667549,"1025508508434":1509788624341,"1021994874279":1509788624463,"1025797787717":1509788624523,"1025797787712":1509788624536,"1021089577539":1478686417094,"1022086495989":1478686417179,"1022053462215":1509788625066,"1021578714423":1468845634471,"1016847927073":1478686804018,"1022389308637":1478686417205,"1020391871459":1478686804027,"1024283294706":1509788624326,"1020912104686":1478686417080,"1022430071392":1478686804071,"1022430071393":1478686804071,"1021308833072":1509788625017,"1022246831458":1478686417195,"1021933266993":1478686417260,"1022430071391":1478686804071,"1019427331408":1478686804021,"1016952127702":1444487341760,"1019489720727":1509788624302,"1022202398662":1480585069085,"1010482447028":1509788625017,"1019759995327":1509788624283,"1020076639901":1509788624383,"1019759995329":1509788624283,"1021763134077":1509788624467,"1025472726360":1509788624201,"1025472726358":1509788624205,"1025472726359":1509788624198,"1020782865600":1478686416997,"1025278898398":1509788624438,"1024094680952":1509788624519,"1022097112624":1478686417275,"1021038722351":1478686417092,"1022202398600":1480585069084,"1021733905309":1509788624918,"1009710846199":1480585069062,"1023031834358":1509788625079,"1025278898407":1509788624438,"1025278898402":1509788624438,"1021353265913":1478686417104,"1024587090365":1509788625026,"1021841911069":1509788624394,"1025843011223":1509788667443,"1021038722359":1478686417092,"1023305090606":1509788624368,"1021038722357":1478686417092,"1021933926247":1509788624465,"1022063685825":1478686417060,"1022063685824":1478686417060,"1024273333263":1509788624277,"4984204938":1509788624161,"1024094680961":1509788624518,"1022698379992":1509788625059,"1022120967267":1478686417276,"1022202398535":1480585069085,"1024094680974":1509788624518,"1024094680975":1509788624521,"1024094680972":1509788624521,"1024094680976":1509788624517,"1021960402632":1478686417148,"1018335518430":1478686804064,"1021040950685":1478686417092,"1022077190104":1478686417271,"1025472726434":1509788624543,"1022229661427":1478686417282,"1025472726433":1509788624541,"1021021028021":1478686417035,"1021308833254":1509788625018,"1017165124857":1478686804020,"1022276715343":1509788624958,"1025620708607":1509788624970,"1025078619211":1509788624292,"1012361228893":1478686417026,"1023995063786":1491634246532,"1023995063785":1491634246532,"1023094616578":1509788624815,"1020971479467":1478686417086,"1021316566058":1478686417005,"1016952127498":1444487341760,"1017040864433":1478686804016,"1023561341435":1509788624191,"1211793442":1444487341738,"1024680287043":1509788624996,"1021528252194":1478686417244,"1021327180565":1465470268217,"1025485310846":1509788625109,"1021327180564":1465470268216,"1025485310845":1509788625125,"1021327180561":1465470268216,"1006013182912":1478686804046,"1021327180563":1465470268216,"1021553152400":1478686417047,"1021937465574":1478686417143,"1022276586676":1478686417285,"1022430070082":1478686804047,"1022517107216":1480585069099,"1021327180558":1465470268216,"1021815955497":1509788624394,"1007172208783":1478686804025,"1024316454575":1509788624368,"1025722554722":1509788624306,"1020294219505":1465470268297,"1024316454576":1509788624368,"1021424965916":1509788624978,"1021680560219":1478686804028,"4984201547":1509788624160,"1024017343676":1509788624610,"1021739543778":1478686417252,"1021262172022":1478686804039,"1025486359370":1509788624437,"1022370824839":1478686417204,"1024017343673":1509788624610,"1022370824842":1478686417204,"1024017343665":1509788624610,"1021426014503":1478686417043,"1024017343656":1509788624610,"1024017343657":1509788624610,"1024017343655":1509788624610,"1024017343651":1509788624610,"1022537161575":1479755120603,"1024017343583":1509788625237,"1024017343581":1509788625237,"1024017343577":1509788625237,"1024017343572":1509788625237,"1021694978489":1480585069067,"1024017343564":1509788625237,"1024017343559":1509788625237,"1024017343552":1509788625236,"1022258498326":1478686417196,"1021955553539":1509788624454,"1019882421748":1509788624355,"1021955553541":1509788624456,"1021484080506":1478686804066,"1024017343607":1509788625237,"1014765227262":1478686804024,"1024017343604":1509788625237,"1024017343605":1509788625237,"1024017343602":1509788625237,"1024017343600":1509788625237,"1024017343598":1509788625237,"1021644248807":1478686417008,"1021295067574":1478686417041,"1021212101799":1478686417038,"1016399687294":1480585069069,"1024017343593":1509788625237,"1024017343590":1509788625237,"1022517107350":1480585069099,"1024017343586":1509788625237,"1024244625901":1509788624949,"1025521356281":1509788624201,"1025521356282":1509788624205,"1019241858985":1509788624301,"1025521356275":1509788624829,"464180090":1480585069060,"1016701415448":1478686804049,"1025485310855":1509788625089,"1208778989":1444487341741,"1021287334263":1478686417040,"1024017343549":1509788625237,"1024017343546":1509788625237,"1022189123379":1478686417188,"1023463555878":1509788624419,"1024017343542":1509788625237,"1019300190976":1478686804018,"1024017343541":1509788625237,"1024017343537":1509788625237,"1024017343533":1509788625236,"1010632656506":1478686804064,"1022480013463":1478943089315,"1022470571539":1478686417219,"1845404922":1444487341754,"1025513753756":1509788625110,"1025569325382":1509788624341,"1020469334341":1509788625076,"1024633624867":1509788625026,"1020455575083":1509788624362,"1024781209716":1509788624423,"1020455575082":1509788624362,"1025513753775":1509788625133,"1020455575085":1509788624362,"1025513753768":1509788625133,"1020455575084":1509788624362,"1020455575086":1509788624362,"1025513753771":1509788625133,"1023926906634":1491634246530,"1022235823047":1478686417065,"61000329":1480585069059,"1025513753761":1509788625133,"1025513753762":1509788625133,"1025902646607":1509788667457,"1022758545541":1509788625057,"1020923509359":1478686417082,"1021006606618":1509788624921,"1019874426109":1509788624285,"1021955553524":1509788624441,"1022121357973":1478686416975,"1019874426107":1509788624285,"1019874426106":1509788624285,"1023561341115":1509788624812,"1023463555739":1509788624533,"1021792628250":1478881022015,"1000526200195":1444487341712,"1025565000180":1509788624337,"1021673875741":1478686804026,"1018907259395":1509788624282,"1019380407893":1509788625079,"1020700422118":1509788624454,"1020295661512":1509788625078,"1020295661515":1509788625076,"1020295661514":1509788625077,"1020295661517":1509788625077,"1019710579438":1478686804022,"1021461011133":1478686417242,"1025513753628":1509788624271,"1025513753629":1509788624271,"1025513753627":1509788624269,"1000526200179":1444487341740,"1025513753644":1509788624215,"1022039441157":1478686417169,"1025513753640":1509788624197,"1022370038598":1509788624300,"1022039441162":1478686417169,"1025513753632":1509788624227,"1023453987804":1509788624533,"1025513753635":1509788624227,"1025513753660":1509788624209,"1025779571808":1509788624341,"1025513753658":1509788624209,"1025647051789":1509788624337,"1010812489806":1509788624299,"1025513753650":1509788624197,"1022537161383":1479755120603,"1019882421397":1509788624368,"1021632321313":1509788624404,"1021073454480":1478686417093,"1025513753666":1509788624209,"1025756109546":1509788624970,"1025513753694":1509788625246,"1025513753689":1509788625244,"1022966293692":1509788624996,"1022349722105":1478686417069,"1025513753709":1509788625165,"1023010994494":1509788624389,"1022040358738":1478686417268,"1025513753701":1509788625246,"1023251380104":1509788625083,"1025561198890":1509788624523,"1023463555635":1509788624816,"1023453987719":1509788625101,"1025513753719":1509788625165,"1025513753715":1509788625165,"1021089576769":1478686417094,"1019947037555":1478686804021,"1023463555543":1509788624194,"4576959188":1478686416965,"1023219005008":1509788625042,"1025607860280":1509788624209,"1022518155280":1509788625065,"1024462965762":1509788624998,"1024462965760":1509788625001,"1024261926917":1509788624907,"1026232171253":1514456869769,"1022537161002":1479755120602,"1009456300695":1480585069064,"1025607860264":1509788624199,"1019882422123":1509788624353,"1022072074898":1509788624921,"1025565786833":1509788624304,"1021938776805":1478686417143,"1022153078713":1478686417185,"1022153078712":1478686417185,"1021685279633":1478686417050,"1021684100029":1478686417249,"1025507856311":1509788624341,"1024462965883":1509788625002,"1016683986339":1478686804063,"1024462965876":1509788625084,"1025507856314":1509788624338,"1021931824466":1478686417142,"1025607860301":1509788624229,"1025507856313":1509788624339,"1021992385012":1478686417156,"1020975545447":1478686417086,"1024184073407":1509788625035,"1025508511624":1509788624336,"184074382":1444487341731,"1024462965840":1509788625001,"1023463555518":1509788625101,"1025516244961":1509788624344,"1025607860375":1509788625164,"1024462965927":1509788624998,"1021758156782":1478686417009,"1025078616336":1509788624292,"1025721375648":1509788624437,"115002453":1444487341723,"1025721375651":1509788624437,"1010024505437":1491634246526,"1025078616333":1509788624292,"1025078616334":1509788624292,"1010024505438":1491634246526,"1010024505433":1491634246521,"1020455574943":1509788624361,"1022537161145":1479755120602,"1022031576986":1509788624463,"1022131974554":1478686417184,"1020455574945":1509788624361,"1010024505444":1491634246521,"1020455574944":1509788624361,"1020455574946":1509788624362,"1025721375645":1509788624437,"1023299849011":1509788624449,"1022995260699":1509788625050,"1025607860386":1509788625164,"1025721375647":1509788624437,"1025721375640":1509788624437,"1023299849014":1509788624449,"1025721375641":1509788624437,"1023299849015":1509788624449,"1023299849012":1509788624449,"1023299849013":1509788624449,"1024283293276":1509788624326,"1025607860393":1509788625143,"1025721375639":1509788624437,"1016531674154":1480585069067,"1021395600846":1478686417105,"1023109430306":1509788625072,"1022430857131":1478686417071,"1022430857129":1478686417071,"1022430857126":1478686417071,"1020455575009":1509788624362,"1023561341700":1509788624417,"1022430857124":1478686417071,"1020455575011":1509788624362,"1025607860474":1509788624451,"1020455575010":1509788624362,"1025607860475":1509788624451,"1020455575013":1509788624362,"1022430857123":1478686417071,"1020455575012":1509788624362,"1020455575015":1509788624362,"61000013":1480585069064,"1020455575014":1509788624362,"1021694979024":1480585069077,"1018884190679":1509788624281,"1021961321033":1509788624898,"1021961321032":1509788624898,"1021961321035":1509788624898,"1021961321034":1509788624898,"1019696030071":1478686804064,"1019696030070":1478686804064,"1021961321036":1509788624898,"1019696030069":1478686804064,"1025607860502":1509788624435,"1021961321038":1509788624898,"1021961321024":1509788624899,"1021961321027":1509788624898,"1019696030072":1478686804064,"1021961321026":1509788624898,"1021961321028":1509788624899,"1021961321031":1509788624898,"1018884190680":1509788624301,"1021961321030":1509788624898,"1008040966166":1478686804052,"1021961321049":1509788624899,"1008040966167":1478686804052,"1025607860481":1509788624440,"1021961321048":1509788624899,"1025628047311":1509788624523,"1021961321050":1509788624899,"1025607860486":1509788624427,"1013442166304":1478686804030,"1021961321041":1509788624898,"1021961321043":1509788624898,"1021961321045":1509788624899,"1008040966168":1478686804052,"1021961321047":1509788624898,"1017311139762":1509788624915,"1010000782205":1491634246535,"1004244179548":1480585069072,"1022029872760":1509788625019,"1000528429052":1444487341710,"1021600733178":1478686417048,"1025521356300":1509788624407,"1022194365523":1478686417189,"1025521356289":1509788624800,"1021302276490":1478686417102,"1019241989155":1480585069108,"1021112251558":1478686417037,"1024435441335":1509788624264,"1021950573227":1478686417056,"1021507673392":1478686417047,"1024132298924":1509788624328,"1022437017178":1478686417213,"1022234380874":1478686417282,"1022202399676":1480585069084,"1012822448979":1478686417224,"1022234380880":1478686417282,"1021120508990":1478686416980,"1021120508988":1478686416980,"1022131581040":1478686416986,"1025749686464":1509788624350,"1021994612752":1478686417156,"1017119120012":1465470268241,"1025721375300":1509788624453,"1025514278637":1509788624339,"1009120853972":1478686804030,"1019766154580":1509788624369,"1021961321023":1509788624899,"1021961321022":1509788624898,"1008287222025":1478686804025,"1023561341590":1509788625097,"1335395559":1444487341730,"1010847092805":1478686804022,"937229407":1478950494919,"1004360045547":1478686804061,"115395941":1444487341750,"1004360045546":1478686804061,"1004360045544":1478686804061,"1004360045542":1478686804061,"1004360045540":1478686804061,"1004360045539":1478686804061,"1004360045538":1478686804061,"1004360045536":1478686804061,"1023143768959":1509788625072,"1021600864085":1478686417115,"1022061984985":1478686417174,"1022238706007":1509788624947,"1022238706010":1509788624931,"1022479752190":1478943089531,"1022238706009":1509788624932,"1022238706012":1509788624931,"1024501760604":1509788625028,"1022131581058":1478686416986,"1008693678491":1478686804030,"1021152463402":1478686417097,"1004360045535":1478686804061,"1004360045534":1478686804061,"1004360045531":1478686804061,"1022202399576":1480585069084,"1004360045529":1478686804061,"1004360045521":1478686804061,"1021540307873":1478686417047,"1022430070462":1478686804071,"1022430070463":1478686804071,"1022430070461":1478686804071,"1022085444137":1478686417062,"1845405229":1444487341715,"1025879969804":1509788667405,"1022537160896":1479755120602,"1022246701457":1478686417195,"1020293956979":1465470268278,"1022202399501":1480585069084,"1022039702873":1478686417169,"4984201957":1509788624160,"1020760449289":1478686416996,"1024012230902":1509788667830,"1021426670894":1509788624399,"1024685791456":1509788624440,"1020871736405":1478686417031,"1024002795440":1491634246532,"1022346314860":1478686417069,"1021688556955":1509788624815,"1142327299":1491634246519,"1020998350021":1478686417034,"1024540559279":1509788667548,"1022206463108":1478686417064,"1017497004882":1478686804015,"1024540559290":1509788667549,"1024540559288":1509788667549,"1021606105250":1509788624401,"1024540559287":1509788667549,"1019000819192":1480585069063,"1025750998868":1509788624293,"1024540559310":1509788667549,"1024540559307":1509788667549,"1021507803703":1478686417112,"1024540559299":1509788667549,"1025626079403":1509788624393,"1021668633739":1509788624861,"1024540559322":1509788667548,"1021311059545":1465470268205,"1025626079405":1509788624393,"1021668633736":1509788624861,"1021668633735":1509788624861,"1021668633734":1509788624861,"1024540559312":1509788667549,"1024685791362":1509788624430,"1021332160675":1478686417103,"1007920767042":1478686804023,"1024613827388":1509788624923,"1025505626215":1509788624972,"1024597443162":1509788624937,"1026232171688":1514456869769,"1021668633686":1509788624226,"1019882420702":1509788624353,"1021668633685":1509788624226,"1023316495880":1509788624334,"1021688556802":1509788624194,"1021484079441":1478686804067,"1021668633679":1509788624226,"1021680561297":1478686804028,"1021320103714":1465470268209,"1021320103719":1465470268209,"1021320103718":1465470268209,"1021320103721":1465470268209,"1022949253312":1509788624291,"1017092244265":1478686804019,"1020963224161":1478686417229,"1022430069206":1478686804065,"1022949253317":1509788624291,"1021668633696":1509788624226,"1022949253335":1509788624291,"172934790":1509788625018,"1016566283315":1478686804024,"1019041058731":1509788624374,"1019041058730":1509788624374,"1019041058733":1509788624374,"1019041058732":1509788624374,"1022034328015":1478686417167,"1023927167711":1491634246530,"1023927167709":1491634246530,"1022070764579":1478686417060,"1020988259246":1478686417088,"1020988259232":1478686417088,"1098157471":1491634246513,"1024096517357":1509788624325,"1021688556900":1509788624533,"1025053582838":1509788624367,"1022235823619":1478686417282,"1022165529037":1478686417186,"1024132300565":1509788624328,"1024134135612":1509788667504,"1022445142625":1478686417295,"1025056859709":1509788625007,"1021463240219":1478686416985,"1021476084055":1478686417242,"1023881554420":1509788624259,"1012905154617":1478950494940,"1023881554430":1509788624259,"1009787000344":1491634246536,"1023881554427":1509788624259,"1023881554425":1509788624259,"1023881554406":1509788624259,"1020848530092":1478686417031,"1023881554404":1509788624259,"1023881554402":1509788624259,"1023425807636":1509788625079,"1015831087547":1509788625081,"1023881554415":1509788624259,"1023881554412":1509788624259,"1023881554411":1509788624259,"1022082430225":1480585069086,"1023881554388":1509788624259,"1025908543782":1509788667456,"1023881554389":1509788624259,"1023881554386":1509788624259,"1025607599920":1509788624548,"1025607599921":1509788624548,"1025607599922":1509788624548,"1023881554385":1509788624259,"1020294087554":1465470268288,"1023881554397":1509788624259,"1023881554394":1509788624259,"1021948607803":1509788624506,"1021908624216":1478686417259,"1019882420334":1509788624368,"1023881554381":1509788624259,"1023881554379":1509788624259,"1023881554376":1509788624259,"1211794813":1444487341742,"1021630746709":1478686417049,"1021330719147":1478686417239,"1022451434360":1478686417215,"1020916825823":1478686417080,"321314430":1478686804046,"1019504267905":1465470268274,"1019504267906":1465470268274,"1022949253384":1509788624291,"1022949253376":1509788624291,"1023881554334":1509788624424,"1022949253379":1509788624291,"1024920285057":1509788624259,"1022949253381":1509788624291,"1021684755626":1478686417121,"1022630089758":1509788624218,"1023995586427":1491634246532,"1022630089759":1509788625150,"1023995586428":1491634246532,"1022630089752":1509788625150,"1025716788453":1509788625004,"1022630089753":1509788625150,"1022630089750":1509788624218,"1022202400149":1480585069084,"1022630089751":1509788625150,"1022630089748":1509788624218,"1020744852661":1509788624318,"1022630089749":1509788624218,"1022630089746":1509788624218,"1022630089747":1509788625150,"1024156809711":1509788667856,"4984202391":1509788624160,"1023561604203":1509788625097,"1019710580226":1478686804022,"227459101":1478950494907,"1024394809280":1509788624973,"1025756110490":1509788624970,"1017092244001":1478686804019,"1024141475536":1509788624959,"1021484079222":1478686804050,"1021039245289":1478686417035,"1021484079221":1478686804050,"1021062967629":1478686417036,"1025911296070":1509788667464,"1010024507147":1491634246521,"1022049270723":1478686417172,"1022598765187":1509788624462,"1025797266295":1509788624831,"1025083860735":1509788624294,"1021809796514":1509788624394,"1025585448082":1509788624351,"1025585448080":1509788624352,"1021929464463":1478686417259,"1025797266297":1509788624616,"1024804410900":1509788625136,"1011574786947":1478686804033,"387111675":1491634246524,"356178125":1444487341718,"1021890535542":1478686417138,"1022202400018":1480585069084,"1024334934543":1509788625031,"1025513753484":1509788624546,"1025513753485":1509788624546,"1025513753486":1509788624550,"1022209609364":1480585069113,"1023453987964":1509788624816,"1025756110133":1509788624970,"1021231892693":1478686417039,"1020745377747":1478686417028,"1760732880":1444487341708,"1147832904":1478950494920,"1021211445820":1478686804033,"1024727865411":1509788624279,"1016101100188":1509788624941,"1023000371543":1509788624462,"1025513753524":1509788624917,"1021092197122":1478686417094,"1671867804":1478686417020,"1025513753520":1509788624916,"1022183354445":1478686417278,"1025513753548":1509788624864,"1025513753550":1509788624821,"1009275384622":1478686804024,"1025513753544":1509788624865,"1025513753547":1509788624865,"1022485519941":1478943089489,"1023561342886":1509788625098,"1025513753543":1509788624865,"1309442112":1491634246534,"1025513753536":1509788624917,"1023881554598":1509788624259,"1021763529573":1509788624403,"1023881554595":1509788624259,"1025513753561":1509788624839,"1023453987876":1509788624194,"1025513753562":1509788624839,"1023881554593":1509788624259,"1025513753558":1509788624821,"1025513753559":1509788624825,"1025513753552":1509788624849,"1022291397598":1478686417068,"1018156859501":1478686804056,"1018156859500":1478686804056,"1018156859503":1478686804056,"1018156859502":1478686804056,"1025513753577":1509788624840,"1018156859499":1478686804056,"1023881554576":1509788624259,"1025513753578":1509788624846,"1016661703492":1478686804042,"1021613576813":1509788624397,"1023881554589":1509788624259,"1016661703490":1478686804063,"1025513753568":1509788624839,"1023881554585":1509788624259,"1021995793712":1509788624932,"1018156859517":1478686804056,"1018156859516":1478686804056,"1018156859519":1478686804056,"1023881554564":1509788624259,"1018156859518":1478686804056,"1020819956484":1478686416998,"1018156859512":1478686804056,"699197402":1478686804054,"1018156859515":1478686804056,"1018156859514":1478686804056,"1023881554561":1509788624259,"1018156859509":1478686804056,"1018156859508":1478686804056,"1018156859511":1478686804056,"1018156859510":1478686804056,"1023881554573":1509788624259,"1018156859505":1478686804056,"1018156859504":1478686804056,"1023881554571":1509788624259,"1000088409980":1478686804046,"1018156859507":1478686804056,"1023881554568":1509788624259,"1018156859506":1478686804056,"1023881554550":1509788624259,"1023881554551":1509788624259,"1018156859528":1478686804056,"1018156859530":1478686804056,"1018156859525":1478686804056,"1023881554558":1509788624259,"1018156859524":1478686804056,"1023881554559":1509788624259,"1023881554556":1509788624259,"1018156859526":1478686804056,"1018156859521":1478686804056,"1023881554554":1509788624259,"137938613":1444487341701,"1018156859520":1478686804056,"1018156859523":1478686804056,"1023881554552":1509788624259,"1018156859522":1478686804056,"1023881554553":1509788624259,"1020496073784":1465470268322,"1025078617405":1509788624292,"1025078617406":1509788624292,"1025078617400":1509788624292,"1022966293440":1509788624996,"1021475953406":1478686417109,"1025078617402":1509788624292,"1025078617398":1509788624292,"1025078617395":1509788624292,"1025270511804":1509788624532,"1021742164681":1509788625001,"1025270511805":1509788624532,"1025270511806":1509788624532,"1025270511797":1509788624532,"1025270511799":1509788624532,"1025270511794":1509788624532,"1025270511822":1509788624532,"1022966293414":1509788624996,"1025270511823":1509788624532,"1025270511817":1509788624532,"1024300593972":1509788624298,"1025270511812":1509788624532,"1021894861704":1509788624465,"1022966293423":1509788624996,"1021694980068":1480585069067,"1025270511809":1509788624532,"1024772953861":1509788624853,"1022966293429":1509788624996,"1022966293430":1509788624996,"1022966293431":1509788624996,"1024772953856":1509788624853,"1024772953857":1509788624853,"1020934388310":1509788624971,"1024772953858":1509788624853,"1019041058209":1509788624391,"1019041058208":1509788624391,"1022966293437":1509788624996,"1019041058211":1509788624391,"1019041058210":1509788624391,"1022966293439":1509788624996,"1019882421131":1509788624353,"1019041058213":1509788624391,"1022966293432":1509788624996,"1019041058212":1509788624391,"1022966293434":1509788624996,"1025513753448":1509788624613,"1025513753449":1509788624613,"1025513753451":1509788624565,"1021967089657":1509788624215,"1023561342726":1509788624191,"1025513753447":1509788624611,"1023143638553":1509788625045,"4984203257":1509788624159,"1021967089661":1509788624215,"1022357063481":1478686417203,"1021967089660":1509788624215,"1021972855880":1478686417150,"1022138004019":1478686417276,"1025513753459":1509788624536,"1021987929310":1478686417154,"1019013795336":1478686804033,"1024017343434":1509788624268,"1024017343433":1509788624268,"1024017343431":1509788624268,"1024017343429":1509788624268,"1024017343426":1509788624268,"1024017343427":1509788624268,"1019710579891":1478686804022,"1022474379258":1478943089486,"1024772953851":1509788624853,"1025762008057":1509788667888,"1024794056147":1509788624989,"1024017343388":1509788624268,"1023453988152":1509788624419,"1024017343379":1509788624268,"1024017343376":1509788624268,"1023881554854":1509788624825,"1021885817497":1509788624859,"1021885817496":1509788624224,"1021885817498":1509788624859,"1024017343370":1509788624268,"1024017343366":1509788624267,"1021600732049":1478686417048,"1021885817494":1509788624859,"1021604402131":1478686417115,"1024017343422":1509788624268,"1021885817513":1509788624859,"1021181299882":1478686417098,"1024017343423":1509788624268,"1021885817512":1509788624562,"1024017343420":1509788624268,"1024017343418":1509788624268,"1021885817517":1509788624562,"1021885817516":1509788624562,"1021885817519":1509788624449,"1021885817518":1509788624224,"1024017343414":1509788624268,"1024017343415":1509788624268,"1021885817504":1509788624449,"1021885817507":1509788624225,"1024017343412":1509788624268,"1021885817506":1509788624225,"1024017343408":1509788624268,"1021885817511":1509788624449,"1021885817510":1509788624449,"1016952129679":1444487341760,"1024017343407":1509788624268,"1024017343403":1509788624267,"1019300191377":1478686804018,"1024017343396":1509788624267,"1021885817522":1509788624562,"1025797790010":1509788624185,"1024017343322":1509788624912,"1024017343320":1509788624912,"1024017343319":1509788624912,"1024017343316":1509788624912,"1024017343317":1509788624912,"1024017343312":1509788624912,"4984202906":1509788624159,"1025797789998":1509788624203,"1025797789999":1509788624197,"1025797789997":1509788624200,"1021243951513":1478686417100,"1024017343305":1509788624912,"1024017343302":1509788624912,"1024017343303":1509788624912,"1024017343300":1509788624912,"1008116725510":1478686804034,"725804267":1444487341720,"1023561342529":1509788624812,"1023881554779":1509788624825,"1023918385418":1509788624957,"1022205677418":1478686417280,"1013061914729":1478686804064,"1023521751544":1509788625071,"1021385113621":1478686417006,"1024017343338":1509788624912,"1024017343339":1509788624912,"1024017343336":1509788624912,"1024017343332":1509788624912,"1023878540479":1491634246506,"1024017343330":1509788624912,"1024017343331":1509788624912,"1020394232597":1509788624392,"1021815039941":1509788624394,"1024132299816":1509788624328,"1012209181563":1478686417073,"61000812":1480585069067,"1024205699157":1509788625033,"1526109472":1444487341721,"1022021351949":1478686417266,"1021311059439":1465470268205,"1021165047074":1478686417003,"1024017343293":1509788624912,"1024017343285":1509788624912,"1024017343277":1509788624912,"1025607730657":1509788625084,"1024017343270":1509788624912,"1024017343268":1509788624912,"1024017343266":1509788624912,"1020786664624":1478686417029,"1024273593445":1509788667496,"1022447902286":1480585069108,"1022447902284":1480585069108,"1021565471462":1478686417114,"1022447902274":1480585069108,"1022021084624":1478686417162,"1022447902275":1480585069108,"1022447902273":1480585069108,"1025880755104":1509788667811,"1016694335319":1478686804063,"1022447902277":1480585069108,"1023989561961":1509788624345,"1020264340609":1509788624959,"1019325613183":1478686804058,"1012418766894":1478686417026,"1020858892058":1478686417031,"1021267024054":1478686417101,"1019325613181":1478686804058,"1019325613180":1478686804058,"1022447902289":1480585069108,"1019325613179":1478686804058,"1016673494663":1478686804056,"1019325613178":1478686804058,"1019325613177":1478686804058,"1022447902292":1480585069108,"1019325613176":1478686804058,"1021969572588":1478686417149,"1024578182483":1509788624925,"1025429213331":1509788624432,"1017558350832":1509788624367,"1025486099322":1509788625108,"1025486099323":1509788625117,"1025486099321":1509788625125,"1022447902330":1480585069108,"1022810715291":1509788624420,"1022447902328":1480585069108,"1022511334068":1480585069131,"1025715470782":1509788624414,"1020862685437":1509788625084,"1025715470783":1509788624414,"1025715470780":1509788624414,"1022447902326":1480585069108,"1025429213322":1509788624432,"1022447902327":1480585069108,"1025715470776":1509788624414,"1021892246826":1478686417138,"1022447902219":1480585069108,"1013290515579":1509788624353,"1025715470788":1509788624414,"1022447902220":1480585069108,"1021668896915":1509788624396,"1025715470799":1509788624414,"1021939687677":1478686417143,"1025715470796":1509788624414,"1025715470797":1509788624414,"1022447902212":1480585069108,"1025715470793":1509788624414,"1025715470805":1509788624414,"1025715470802":1509788624414,"1024779503908":1509788624580,"1022188859276":1478686417187,"1019932485633":1509788624922,"1025715470808":1509788624414,"1022447902250":1480585069108,"1022447902251":1480585069108,"1023097759212":1509788624600,"1022447902249":1480585069108,"1022447902255":1480585069108,"1022447902252":1480585069108,"1022447902253":1480585069108,"1025715470831":1509788624415,"1023097759207":1509788624600,"1025715470828":1509788624414,"1023097759204":1509788624600,"1023097759205":1509788624599,"1021990151133":1478686417265,"1023097759202":1509788624600,"1023097759201":1509788624599,"1022447902266":1480585069108,"1025715470838":1509788624414,"1025715470839":1509788624414,"1023097759231":1509788624599,"1022447902265":1480585069108,"1020014931256":1509788624311,"1025715470835":1509788624415,"1023097759227":1509788624599,"1022447902268":1480585069108,"1025715470832":1509788624415,"1025715470833":1509788624415,"1023097759225":1509788624599,"1022447902258":1480585069108,"1023097759222":1509788624599,"1022447902259":1480585069108,"1025715470844":1509788624414,"1023097759220":1509788624599,"1022447902257":1480585069108,"1025597250254":1509788624359,"1023097759218":1509788624599,"1025715470843":1509788624414,"1022447902260":1480585069108,"1025715470841":1509788624414,"1025429213238":1509788625136,"1025429213236":1509788625171,"1016673494559":1478686804063,"1021101633036":1478686417232,"1022067484573":1509788624863,"1021148270928":1478686417002,"1021217477942":1478686417038,"1022241329711":1478686417194,"1021918986084":1509788624433,"1020202342588":1465470268243,"1025429213224":1509788625127,"1021353663774":1465469681398,"1025429213225":1509788625127,"1020659397702":1478686417075,"1025429213207":1509788625104,"1024780290534":1509788624440,"1009433892543":1478686804034,"1025429213214":1509788625127,"1025879182189":1509788667404,"1025429213213":1509788625127,"1021281179974":1478686417237,"1025429213189":1509788625245,"1025429213184":1509788625244,"1024769935701":1509788624289,"1025429213199":1509788625128,"1021948862640":1478686417145,"1025429213195":1509788625128,"1022447902346":1480585069108,"1022447902347":1480585069108,"1009966315140":1491634246524,"1022330984320":1478686417288,"1022447902344":1480585069108,"1025429213300":1509788624433,"1009966315142":1491634246524,"1025429213301":1509788624433,"1022447902351":1480585069108,"1316789945":1491634246505,"1022447902348":1480585069108,"1022447902336":1480585069108,"1025429213308":1509788624427,"1025429213309":1509788624432,"1019160205967":1509788624314,"1025429213306":1509788624434,"1022447902343":1480585069108,"1025429213305":1509788624424,"1012184021733":1478686417073,"1022447902362":1480585069108,"1023145469958":1509788624881,"1022447902363":1480585069108,"1019504135954":1509788624313,"1022447902360":1480585069108,"1019160205969":1509788624314,"1025429213284":1509788624510,"1020123960345":1465470268247,"1025429213283":1509788624510,"1022447902364":1480585069108,"1022447902365":1480585069108,"1025486099333":1509788625089,"1022447902355":1480585069108,"1022447902352":1480585069108,"1012836991482":1478686416981,"1022447902353":1480585069108,"1024779504045":1509788625194,"1022447902356":1480585069108,"1021736137783":1478686417124,"1020202342594":1465470268243,"1020202342597":1465470268243,"1024145925072":1509788625035,"1019325613185":1478686804058,"1019325613184":1478686804058,"1022165003727":1478686417186,"1022069057553":1478686417301,"1022069057555":1478686417301,"1022511333996":1480585069131,"1022069057554":1478686417301,"1021415915831":1478686417240,"1021415915830":1478686417240,"1020202342618":1465470268243,"1021415915827":1478686417240,"1020005887227":1509788625076,"1020969248622":1478686417001,"1025067219755":1509788624374,"1025067219758":1509788624374,"1025067219759":1509788624373,"1025067219756":1509788624374,"1025067219757":1509788624374,"1025067219760":1509788624373,"1025067219761":1509788624374,"1025797261189":1509788624197,"1021156921467":1478686417097,"1022021084413":1509788624179,"1022238708710":1509788624947,"1021833264074":1478686417053,"1022398093927":1478686417207,"1022238708711":1509788624931,"1013328658143":1465470268239,"4572496315":1478686416965,"1021668635039":1509788624564,"1022608984464":1509788624914,"1021668635038":1509788624564,"1022608984465":1509788624914,"1022608984468":1509788624914,"1023403398707":1509788625072,"1022608984470":1509788624914,"1024966948207":1509788624363,"1022608984475":1509788624914,"1022608984477":1509788624914,"1020868190659":1509788625017,"1022608984451":1509788624914,"1022608984453":1509788624914,"1022608984456":1509788624914,"1022608984458":1509788624914,"1022608984460":1509788624914,"1022407007623":1478686417208,"1022608984461":1509788624914,"1022608984462":1509788624914,"1021469263317":1478686417109,"4919456843":1509788624161,"1021668635041":1509788624564,"1021668635040":1509788624564,"1023097758730":1509788624908,"1021327186608":1465470268217,"1018849716552":1509788624309,"1025703936476":1509788625001,"1023097758723":1509788624908,"1023097758720":1509788624908,"1021540829677":1478686417113,"1020375876189":1509788625020,"1023097758740":1509788624908,"1012476701984":1444487341760,"1021484860493":1478686417007,"1022608984433":1509788624914,"1022608984435":1509788624914,"1023097758762":1509788624908,"1022608984436":1509788624914,"1025879181920":1509788667404,"1023097758763":1509788624908,"1022827623437":1509788624990,"1023097758760":1509788624908,"1023097758761":1509788624908,"1022608984439":1509788624914,"1023097758758":1509788624908,"1022407007607":1478686417208,"1023097758753":1509788624908,"1022608984447":1509788624914,"1023097758780":1509788624908,"1023097758781":1509788624908,"1023097758779":1509788624908,"1021656174126":1509788624404,"1004167371809":1444487341703,"1025383885960":1509788624869,"1020294094702":1465470268288,"1322688285":1444487341717,"1022143376709":1478686417184,"1022827623537":1509788624990,"1022158580821":1478686417185,"1009388672329":1478686804055,"1022143376757":1478686417184,"1006873263952":1478686804017,"1016694335152":1478686804069,"1018667793492":1478686804033,"1021654208073":1478686417120,"1008105318107":1509788624374,"1024920285983":1509788624488,"1024509106325":1509788624935,"1022455504393":1478686417298,"1025715471238":1509788625094,"1025715471239":1509788625094,"1025715471236":1509788625093,"1025715471237":1509788625094,"1022014924348":1509788624814,"1010484680567":1478686804061,"1025715471246":1509788625094,"1025715471247":1509788625094,"1025715471244":1509788625094,"1025715471242":1509788625093,"1025715471243":1509788625093,"1025715471240":1509788625094,"725809488":1444487341734,"1024363090486":1509788624278,"1025715471248":1509788625094,"1020817997700":1478686417226,"1025715471249":1509788625094,"1023561335798":1509788625098,"1020817997709":1478686417226,"1023561335757":1509788624531,"1023561335754":1509788624530,"1023561335755":1509788624531,"1023561335748":1509788624531,"1023561335749":1509788624530,"1023561335750":1509788624530,"1023561335751":1509788624530,"1023930053694":1509788624178,"1023561335745":1509788624531,"1021211448881":1478686804033,"1025715471283":1509788625164,"1025098284614":1509788624293,"1025715471281":1509788625164,"1021603352219":1478686804031,"1022112573564":1509788624944,"1025715471295":1509788625111,"1023561335760":1509788624531,"1023561335761":1509788624530,"1025715471291":1509788625111,"1025715471288":1509788625142,"1021492856597":1478686417111,"1023561335726":1509788624530,"158260010":1444487341723,"1023561335723":1509788624531,"158260007":1444487341727,"1023561335719":1509788624531,"1023561335714":1509788624530,"1645523035":1478686804024,"1023561335715":1509788624531,"1023561335740":1509788624530,"1023561335743":1509788624531,"228646909":1444487341754,"1023561335731":1509788624530,"1025715471334":1509788625095,"1025715471335":1509788625095,"1025715471330":1509788625094,"1025636572732":1509788624335,"1025715471328":1509788625094,"1025715471342":1509788625094,"1025715471340":1509788625094,"1020933859040":1478686416984,"1023561335680":1509788624417,"1025715471338":1509788625094,"1023880640138":1509788624969,"1025715471336":1509788625094,"1025715471351":1509788625094,"1025715471347":1509788625094,"1025715471345":1509788625094,"1025270244430":1509788624915,"1025715471352":1509788625095,"1022882282008":1509788625111,"1023561335660":1509788624417,"1025514280709":1509788624338,"1023561335661":1509788624417,"1008797365098":1444487341757,"1022608984658":1509788624265,"1025270244530":1509788624915,"1008797365099":1444487341757,"1023561335656":1509788624417,"1023561335657":1509788624417,"1023561335658":1509788624417,"1008797365103":1444487341757,"1023561335659":1509788624417,"1022608984664":1509788624265,"1023561335652":1509788624417,"1025715471117":1509788625092,"1022897355533":1509788624928,"1023561335650":1509788624417,"1008797365112":1444487341757,"1023561335676":1509788624417,"1023561335677":1509788624417,"1008797365114":1444487341757,"1023561335678":1509788624417,"1022608984645":1509788624265,"1023561335673":1509788624417,"1025715471123":1509788625092,"1023561335674":1509788624417,"1025715471120":1509788625092,"1008797365104":1444487341757,"1021485516605":1478686417046,"1023561335668":1509788624417,"1025715471134":1509788625092,"1025715471135":1509788625092,"1008797365106":1444487341757,"1022608984650":1509788624265,"1023561335670":1509788624417,"1025715471133":1509788625092,"1008797365108":1444487341757,"1008797365110":1444487341757,"1023561335666":1509788624417,"1025715471128":1509788625092,"1012179302626":1478686417073,"1025715471140":1509788625092,"1022608984691":1509788624265,"1025715471141":1509788625092,"1025715471138":1509788625092,"1022608984694":1509788624265,"1025715471136":1509788625092,"1022608984695":1509788624265,"1025715471137":1509788625092,"1016694334961":1478686804063,"1023561335621":1509788624812,"1016694334962":1478686804063,"1021396786617":1509788624394,"1023561335622":1509788624812,"1023946569146":1491634246531,"1016694334965":1478686804042,"1023561335617":1509788624812,"1016694334966":1478686804042,"1022711483418":1509788625058,"1019391019565":1509788624281,"1025715471158":1509788625093,"1022608984673":1509788624265,"1022608984674":1509788624265,"1025715471156":1509788625092,"1025715471157":1509788625093,"1021899456428":1478686417010,"1022608984677":1509788624265,"1022608984678":1509788624265,"1019388922373":1480585069072,"1022608984680":1509788624265,"1021934838341":1509788624869,"1022482236132":1478943089315,"1025715471164":1509788625092,"1019388922374":1480585069072,"1025715471165":1509788625092,"1022608984684":1509788624265,"1025715471163":1509788625093,"1019388922371":1480585069072,"1025715471160":1509788625093,"1019388922370":1480585069072,"1025715471174":1509788625092,"1008906155349":1509788624389,"1023561335597":1509788624812,"1025715471172":1509788625092,"1023561335594":1509788624812,"1025715471168":1509788625092,"1023561335595":1509788624812,"1025715471180":1509788625093,"1023561335591":1509788624812,"1025715471181":1509788625093,"1021934838321":1509788624849,"1021191000473":1478686417038,"1023561335613":1509788624812,"1023561335614":1509788624812,"1023561335608":1509788624812,"1022188858639":1478686417187,"1021853972740":1509788624394,"1020809084611":1478686416992,"1021946503927":1478686417144,"1025288988107":1509788624286,"1023561335606":1509788624812,"1006734717990":1478686804054,"1023561335601":1509788624812,"1023561335602":1509788624812,"1023561335603":1509788624812,"1025715471206":1509788625093,"1022065649107":1478686417060,"1025715471204":1509788625093,"1022608984627":1509788624266,"1025879968059":1509788667405,"1021485516609":1478686417046,"1022608984631":1509788624265,"1025715471201":1509788625093,"1025715471214":1509788625093,"1025715471215":1509788625093,"1025715471213":1509788625093,"1025715471211":1509788625093,"1022608984638":1509788624266,"1025715471208":1509788625093,"1025715471209":1509788625093,"1023561335580":1509788624812,"1021051955564":1478686804059,"1023561335583":1509788624812,"1025715471218":1509788625093,"1025001288909":1509788624462,"1019797349043":1465470268275,"1025715471216":1509788625093,"1022608984615":1509788624265,"1023561335579":1509788624812,"1025715471217":1509788625093,"1024920285211":1509788625218,"1022608984617":1509788624266,"1021704810569":1478686417050,"1025715470983":1509788624415,"1025715470981":1509788624415,"1023561335528":1509788624191,"1025715470978":1509788624415,"1022608985044":1509788625241,"1025715470976":1509788624415,"1022998412434":1509788624195,"1022608985049":1509788625241,"1025715470988":1509788624415,"1023561335527":1509788624191,"1025715470989":1509788624415,"1025715470986":1509788624415,"1022608985052":1509788625241,"1023561335521":1509788624191,"1025715470987":1509788624415,"1025715470984":1509788624415,"1025422421009":1509788624307,"1025715470985":1509788624415,"1023844987412":1491634246520,"1022608985024":1509788625241,"1022608985025":1509788625241,"1022393637013":1478686417291,"1025270244643":1509788624915,"1022608985028":1509788625241,"1025627922374":1509788624746,"1022608985032":1509788625241,"1023946437636":1491634246531,"1025627922370":1509788624823,"1022608985036":1509788625241,"1503562371":1444487341746,"1023946437637":1491634246531,"1023946437638":1491634246531,"1025627922368":1509788624828,"1022447639889":1480585069105,"1025627922369":1509788624832,"1022608985072":1509788625241,"1016301777795":1480585069066,"1023561335502":1509788624191,"1022608985075":1509788625241,"4990368342":1509788624161,"1023561335497":1509788624191,"1016301777796":1480585069066,"1022608985078":1509788625241,"1023561335499":1509788624191,"1025715471022":1509788624413,"1020773169430":1478686417029,"1023561335493":1509788624191,"1025715471023":1509788624413,"1025715471021":1509788624413,"1025715471019":1509788624412,"1023561335490":1509788624191,"1023561335517":1509788624191,"1025715471031":1509788624413,"1025715471028":1509788624412,"1018515617693":1509788624426,"1022608985058":1509788625241,"1021887004399":1478686804027,"1025715471026":1509788624412,"1022447902079":1480585069107,"1022608985061":1509788625241,"1023561335514":1509788624190,"1025715471024":1509788624413,"1021064409076":1478686417093,"1025715471025":1509788624412,"1022608985066":1509788625241,"1023561335511":1509788624190,"1023561335504":1509788624190,"1025715471034":1509788624413,"1025715471035":1509788624413,"1022608985069":1509788625241,"1022608985070":1509788625241,"1025715471033":1509788624413,"1022056211680":1478686417011,"1023561335469":1509788624190,"1022608984977":1509788624505,"1022608984978":1509788624505,"1022608984980":1509788624505,"1022733765645":1509788624544,"1021690917413":1478686417249,"1025715471063":1509788624413,"1022608984962":1509788624505,"1025715471061":1509788624413,"1023561335480":1509788624191,"1022608984965":1509788624505,"1023097759448":1509788624538,"1023561335483":1509788624190,"1022608984968":1509788624505,"1023561335477":1509788624191,"1025715471069":1509788624413,"1023561335472":1509788624191,"1022608984972":1509788624505,"1025715471067":1509788624413,"1025715471079":1509788624413,"1025593579951":1509788624201,"1025715471075":1509788624413,"1016728414774":1480585069087,"1019029393769":1509788624315,"1025715471073":1509788624413,"1025715471086":1509788624413,"1022659184824":1509788625059,"1025715471085":1509788624413,"1025715471083":1509788624413,"1022608985021":1509788625241,"1022608985022":1509788625241,"1025715471094":1509788624413,"1025715471093":1509788624413,"1022046119207":1478686417059,"1025593579952":1509788624204,"1025538135362":1509788624337,"1022056211674":1478686417011,"1022965120744":1509788625018,"1025715470854":1509788624415,"1023097759246":1509788624600,"1025522013839":1509788624295,"1022447902158":1480585069107,"1019834966415":1509788624301,"1025715470850":1509788624414,"1022447902159":1480585069107,"1022447902156":1480585069107,"1022447902157":1480585069107,"1023097759241":1509788624599,"1024681459872":1509788625213,"1023097759239":1509788624599,"1021149581861":1478686417097,"1023097759235":1509788624599,"1023097759232":1509788624599,"1022447902168":1480585069107,"1016673494281":1478686804051,"1022447902173":1480585069107,"1022447902162":1480585069107,"1021459824820":1509788624405,"1019932486594":1509788624922,"1021051955207":1478686804065,"1023097759248":1509788624599,"1023097759249":1509788624600,"1022452358566":1478686417296,"1022447902186":1480585069107,"1022608984945":1509788624505,"1025270244754":1509788624915,"1022447902191":1480585069107,"1022447902188":1480585069107,"1020294094080":1465470268288,"1022608984953":1509788624505,"1022346845146":1478686417202,"1022447902176":1480585069107,"1022346845148":1478686417202,"1022447902183":1480585069107,"1022608984957":1509788624505,"1022447902180":1480585069107,"1022447902181":1480585069107,"1025715470889":1509788624451,"1022608984959":1509788624505,"1024681459866":1509788624452,"1022608984930":1509788624505,"1025715470901":1509788624435,"1022608984931":1509788624505,"1022447902207":1480585069108,"1022608984934":1509788624505,"1022447902205":1480585069108,"1022608984935":1509788624505,"327467068":1444487341730,"1022608984937":1509788624505,"1022346845131":1478686417202,"1022608984939":1509788624505,"1022608984940":1509788624505,"1022447902199":1480585069108,"1022447902196":1480585069107,"1022998412378":1509788624419,"1022447902091":1480585069107,"1022447902088":1480585069107,"1022447902089":1480585069107,"1025715470917":1509788624435,"1022447902094":1480585069107,"1022447902095":1480585069107,"1025270244853":1509788624915,"1022447902092":1480585069107,"1025715470912":1509788624435,"1022048609778":1478686417171,"1022447902082":1480585069107,"1022212625337":1478686417191,"1022447902080":1480585069107,"1022998412368":1509788624817,"1022447902081":1480585069107,"1022447902086":1480585069107,"1021442785695":1478686417241,"1022447902085":1480585069107,"1025715470921":1509788624453,"1022447902106":1480585069107,"1023946568902":1491634246531,"1022447902107":1480585069107,"1022447902104":1480585069107,"1022447902105":1480585069107,"1012186773559":1478686416994,"1022447902110":1480585069107,"1022447902108":1480585069107,"1022447902099":1480585069107,"1022882282369":1509788624544,"1012291232320":1478686804019,"1022447902112":1480585069107,"1025593579834":1509788624800,"1025715470967":1509788624415,"1021153776285":1478686417097,"1025593579833":1509788624823,"1024681459920":1509788624335,"1025715470975":1509788624415,"1025593579830":1509788624829,"1025593579831":1509788624833,"1025715471750":1509788624803,"1024727859813":1509788624279,"1022064206639":1478686416975,"1025715471746":1509788624803,"1024727859809":1509788624279,"1025715471747":1509788624803,"1024727859811":1509788624279,"1025715471759":1509788624804,"1025715471757":1509788624803,"1024727859816":1509788624279,"1025715471755":1509788624803,"1013077390563":1478686804064,"1025715471760":1509788624805,"1022195542895":1509788624930,"1022827622833":1509788624990,"1022432041336":1478686417212,"1025715471790":1509788624808,"1025715471791":1509788624805,"1025715471788":1509788624809,"1025715471786":1509788624809,"1025715471787":1509788624809,"1025715471785":1509788624805,"1025715471798":1509788624805,"1025715471796":1509788624805,"1025385982232":1509788624915,"1025715471795":1509788624805,"1025715471806":1509788624805,"1025715471803":1509788624805,"1020815505907":1478686416998,"1025715471808":1509788624809,"1025615994846":1509788624929,"1024212247410":1509788625033,"1012418767970":1478686417026,"1025715471838":1509788624810,"1024294168580":1509788625032,"1025715471837":1509788624810,"1021831953759":1478686417053,"1025715471834":1509788624809,"1025715471846":1509788624809,"1025715471847":1509788624809,"1020807379027":1478686417030,"1025715471844":1509788624809,"1025715471845":1509788624809,"1021690918159":1478686417249,"1025715471842":1509788624809,"1025715471840":1509788624810,"1022089637312":1478686417273,"1020792045430":1478686804057,"1025715471850":1509788624810,"1025715471848":1509788624809,"1025715471849":1509788624809,"1025715471619":1509788624188,"1025715471616":1509788624188,"1022044021494":1478686417269,"4998364516":1509788667397,"1025710884163":1509788624305,"1025715471638":1509788624864,"1025715471636":1509788624864,"1022444624395":1478686417071,"1025715471646":1509788624826,"1025715471647":1509788624826,"1025715471649":1509788624840,"1025715471671":1509788624801,"1833351668":1491634246515,"1024663111410":1509788625025,"1025715471678":1509788624801,"1025715471679":1509788624801,"1025715471676":1509788624802,"1025715471677":1509788624802,"1022440561254":1478686417214,"1025715471673":1509788624802,"1021892376997":1478686417010,"1025627789313":1509788624281,"1025715471685":1509788624801,"1025715471683":1509788624801,"1025715471680":1509788624801,"1025715471681":1509788624801,"1023716658786":1491634246535,"1024518413867":1509788625008,"1025715471688":1509788624801,"1025715471689":1509788624802,"1016943350457":1478686804071,"1022377909836":1478686417069,"1008678473190":1478686804030,"1025715471727":1509788624803,"417385485":1444487341746,"1008938532203":1509788624371,"1019330986179":1509788624374,"1025715471732":1509788624805,"1019330986181":1509788624374,"1025715471730":1509788624804,"1019330986180":1509788624374,"1025715471728":1509788624804,"1024727859859":1509788624278,"1021794333607":1509788624394,"1025715471738":1509788624804,"1025521357253":1509788625125,"1021427975625":1478686804026,"1025521357254":1509788625108,"1025715471494":1509788624187,"1024773606570":1509788624876,"1025715471495":1509788624187,"1025715471492":1509788624187,"598144673":1478686804054,"1025715471489":1509788624187,"1016612939582":1465470268266,"1025715471503":1509788624187,"1025715471499":1509788624187,"1025715471496":1509788624187,"1025715471497":1509788624187,"1025715471506":1509788624187,"1025715471507":1509788624188,"1016335726510":1478686804016,"1025715471504":1509788624187,"1024773606542":1509788624876,"1022816088401":1509788624439,"1010847092463":1478686804022,"1024773606554":1509788624876,"1006984798502":1480585069067,"1025521356806":1509788624524,"1022375419896":1478686417290,"1024461787908":1509788624988,"1016677425947":1465470268261,"1024461787909":1509788624988,"1009932628239":1478686804025,"1025715471567":1509788624188,"1025715471564":1509788624188,"1011113705138":1480585069073,"1025715471565":1509788624188,"1024773606625":1509788624876,"1025715471562":1509788624188,"1022816088372":1509788624439,"1025082031620":1509788625007,"1025715471563":1509788624188,"1025715471575":1509788624188,"1023097757919":1509788625224,"1023097757916":1509788625224,"1021288520755":1465469681397,"1012836992117":1478686416981,"1025715471570":1509788624188,"1023097757914":1509788625224,"1025715471571":1509788624188,"1025715471568":1509788624188,"1023097757912":1509788625224,"1025715471569":1509788624188,"1023097757913":1509788625224,"1025715471578":1509788624188,"1025715471577":1509788624188,"1023097757934":1509788625224,"1024773606603":1509788624876,"1023097757935":1509788625224,"1023097757932":1509788625224,"1023097757933":1509788625224,"1023097757928":1509788625224,"1023097757929":1509788625224,"1021484859579":1478686417007,"1021321682433":1478686804034,"1025715471598":1509788624188,"1024773606594":1509788624876,"1025715471599":1509788624188,"1008583049660":1509788624383,"1023097757924":1509788625224,"1025715471597":1509788624188,"1021321682437":1478686804026,"1023097757922":1509788625224,"1022435711092":1478686417213,"1025715471607":1509788624188,"1026507592960":1515854751199,"1025715471603":1509788624188,"1025715471600":1509788624188,"1025715471601":1509788624188,"1023097757945":1509788625224,"1025715471614":1509788624188,"1023097757942":1509788625224,"1017168266850":1478686804040,"1025715471613":1509788624188,"1023097757941":1509788625224,"1023097757938":1509788625224,"1025715471611":1509788624188,"1023097757939":1509788625224,"1023097757936":1509788625224,"1017168266907":1478686804040,"1018744726659":1444487341701,"1022061716170":1478686417174,"1017168266911":1478686804057,"1025715471374":1509788624187,"1022293233675":1478686417198,"1025715471375":1509788624187,"1020862686543":1509788625084,"1021120506598":1478686416980,"1019932487125":1509788624922,"1025715471383":1509788624187,"1025715471380":1509788624187,"1025715471378":1509788624187,"1025715471391":1509788624187,"1025715471386":1509788624187,"1021089573086":1478686417094,"1017168266886":1478686804040,"1025715471407":1509788624187,"1025715471405":1509788624187,"1025715471402":1509788624187,"1025715471400":1509788624187,"1025485313776":1509788624425,"1025715471401":1509788624187,"1025485313775":1509788624431,"1020850633257":1478686804071,"1020850633256":1478686804071,"1022501504143":1509788625170,"1020850633253":1478686804071,"1025715471422":1509788624187,"1020850633252":1478686804071,"1025715471423":1509788624187,"1020850633255":1478686804071,"1020850633254":1478686804071,"1025715471421":1509788624187,"1025715471430":1509788624187,"1025715471431":1509788624187,"1025715471429":1509788624187,"1025715471426":1509788624187,"1025715471427":1509788624187,"1025715471424":1509788624187,"1025715471434":1509788624187,"1025715471432":1509788624187,"1025715471433":1509788624187,"1020937396640":1478686417229,"1022002340143":1478686804039,"1022517102582":1480585069099,"1008592749029":1478686804030,"1023561335820":1509788625097,"1023561335823":1509788625097,"1025715471458":1509788624199,"1025715471459":1509788624209,"1025270244311":1509788624915,"1023097757801":1509788625110,"1022092127351":1509788625020,"1025715471466":1509788624229,"1023561335832":1509788625097,"1116116862":1444487341756,"1018279936801":1465470268270,"1023561335831":1509788625097,"1022897355900":1509788624928,"1025715471483":1509788624187,"1021680563716":1478686804028,"1025732641925":1509788624922,"115396842":1444487341703,"1025732641931":1509788624922,"1025459098818":1509788624350,"1025732641933":1509788624922,"1024283421378":1509788624330,"1018907258198":1509788624282,"715586691":1509788625020,"1022084919234":1509788624416,"1022078889594":1478686417272,"2078846426":1478686804029,"1022511334581":1480585069131,"1022238840055":1509788624946,"1022238840057":1509788624932,"1022238840058":1509788624971,"1022238840059":1509788624971,"1025811022263":1509788667791,"1008732474247":1478686804019,"1013425119868":1465470268239,"1024943879632":1509788624408,"1018200508364":1465470268239,"1023097758702":1509788624908,"1023097758703":1509788624908,"1025879182757":1509788667404,"4998365067":1509788667393,"149741189":1509788625019,"1022511334638":1480585069131,"1023097758719":1509788624908,"1597016387":1491634246520,"1023097758712":1509788624908,"4913951388":1509788624160,"1023097758708":1509788624908,"1022188464568":1478686417013,"1020976062588":1478686417087,"1012405268123":1478686416994,"1023097758705":1509788624908,"1021803118169":1478686417130,"1021845191889":1480585069082,"1023097758474":1509788624264,"1021803118163":1478686417130,"1023097758471":1509788624264,"1023097758469":1509788624264,"1023097758466":1509788624264,"1025486099935":1509788624428,"1021845191877":1480585069082,"1021321682427":1478686804048,"1009275382777":1478686804024,"1021845191878":1480585069082,"1021845191873":1480585069082,"1021321682428":1478686804048,"1021845191875":1480585069082,"1023087665840":1509788624185,"1023097758486":1509788624264,"1025715472158":1509788624528,"1021845191884":1480585069082,"1025715472159":1509788624528,"1021845191887":1480585069082,"1023097758484":1509788624264,"1025715472156":1509788624528,"1021845191886":1480585069082,"1023097758485":1509788624264,"1025715472154":1509788624528,"1021845191880":1480585069082,"1021845191882":1480585069082,"1021845191925":1480585069082,"1006011477183":1478686804046,"1021845191924":1480585069082,"1025715472167":1509788624528,"1024773607179":1509788624877,"1000037679278":1478686417021,"1021845191927":1480585069082,"1025715472164":1509788624528,"1025715472165":1509788624528,"551220863":1478686417019,"1021845191920":1480585069082,"1025715472160":1509788624528,"1021845191922":1480585069082,"1025715472161":1509788624528,"1021845191932":1480585069082,"1021845191929":1480585069082,"1021845191928":1480585069082,"1021845191930":1480585069082,"1025715472183":1509788624528,"1021845191911":1480585069082,"1025486099936":1509788624425,"551220847":1478686417019,"1021803118190":1478686417130,"1025593580671":1509788624407,"1021845191907":1480585069082,"1025486099940":1509788624431,"1021845191916":1480585069082,"1012418768525":1478686417026,"1021845191918":1480585069082,"1025486099945":1509788624407,"1023087665813":1509788624185,"1025715472184":1509788624528,"1021981893772":1478686417057,"1021845191914":1480585069082,"1025715472185":1509788624528,"1022126730669":1478686417184,"1025756104186":1509788624970,"1024453136389":1509788624335,"1010767396940":1478950494939,"1023845119944":1491634246537,"1023087665914":1509788624185,"1022074170982":1478686417176,"1025715472222":1509788624528,"1024435442472":1509788624908,"1025715472230":1509788624528,"1025715472231":1509788624528,"1025715472228":1509788624528,"1025715472229":1509788624528,"1025715472226":1509788624528,"1025715472227":1509788624528,"1025715472224":1509788624528,"1021845191869":1480585069082,"1025715472238":1509788624528,"1021845191868":1480585069082,"1025715472236":1509788624528,"1021845191870":1480585069082,"1021810982575":1478686417256,"1025715472234":1509788624528,"1021845191867":1480585069081,"1025715472232":1509788624528,"1021693409201":1478686804034,"1021693409203":1478686804033,"1021693409204":1478686804031,"1012172487731":1478686804024,"1023087665887":1509788624185,"1020963741757":1478686417001,"1021289176967":1478686417040,"1019948740541":1509788624320,"1019948740540":1509788624320,"1021918198016":1509788624869,"1018454931277":1478686804040,"1023087665954":1509788624185,"1018994136873":1509788624282,"1025715472023":1509788624527,"1006710338401":1478686804028,"1020294093233":1465470268288,"1025715472029":1509788624527,"1025715472024":1509788624527,"1025715472025":1509788624527,"1019300185291":1478686804018,"1025715472038":1509788624527,"1025715472039":1509788624527,"1025715472036":1509788624527,"1025715472037":1509788624527,"1021952403157":1478686417146,"1023097758379":1509788624198,"1023087665935":1509788624185,"1025715472042":1509788624527,"1025715472043":1509788624527,"1021865245737":1478686417009,"1025715472040":1509788624527,"1025715472041":1509788624527,"1022897356465":1509788624928,"1025715472062":1509788624527,"1025715472063":1509788624527,"1025715472060":1509788624527,"1025715472061":1509788624528,"1009715429485":1491634246512,"1025715472059":1509788624527,"1022259549380":1478686417196,"1025715472070":1509788624527,"1022259549381":1478686417196,"1022036156851":1478686417267,"1025715472066":1509788624527,"1025715472067":1509788624527,"1025715472064":1509788624527,"1025715472074":1509788624527,"1025715472075":1509788624528,"1022965250777":1509788625051,"1025715472072":1509788624527,"1023097758430":1509788624264,"1833351700":1491634246515,"1023097758428":1509788624264,"923852867":1478950494918,"1023097758429":1509788624264,"1018513257376":1509788624837,"1024667829570":1509788624206,"1025715472092":1509788624564,"1022231107124":1509788624938,"1023097758445":1509788624264,"1025715472101":1509788624547,"1022014923615":1509788624532,"1025715472098":1509788624538,"1025715472099":1509788624546,"1022231107120":1509788624938,"1021613312876":1509788624397,"1023097758439":1509788624264,"1833351723":1491634246515,"1023097758432":1509788624264,"1022021477029":1509788624181,"1025796342182":1509788624274,"1023097758461":1509788624264,"1023097758457":1509788624264,"1023097758454":1509788624264,"1019948740154":1509788624323,"1023097758453":1509788624264,"1023097758450":1509788624264,"1023097758451":1509788624264,"1000037679474":1478686417021,"1020819176190":1478686416998,"1019325613026":1478686804058,"1020800563986":1509788624454,"725810384":1444487341732,"1022085443189":1478686417062,"1025879182422":1509788667404,"1024453792077":1509788624836,"239786449":1444487341707,"1021661677753":1509788625082,"1022014923674":1509788624193,"1025715471911":1509788624840,"1025715471909":1509788624840,"1221762938":1491634246508,"1024773606912":1509788624876,"1021148272239":1478686417002,"1025715471913":1509788624866,"1021568224616":1478686804065,"1022035894606":1478686417011,"1020771466728":1478686416996,"1025715471950":1509788624527,"1023377051937":1509788624974,"1025715471947":1509788624527,"1025715471944":1509788624526,"1023561598503":1509788624812,"1025161324380":1509788624179,"1023377051962":1509788624974,"1022985173407":1509788625049,"1025715471960":1509788624527,"1021181301780":1478686417098,"1022188726331":1478686417187,"1025522012904":1509788624296,"1025715471983":1509788624526,"1025715471980":1509788624527,"1016531024612":1478686804018,"1025715471990":1509788624526,"1025715471991":1509788624527,"1025715471988":1509788624526,"1025715471989":1509788624526,"1016942825885":1465470268261,"1025715471987":1509788624526,"1023377051934":1509788624974,"1025715471992":1509788624527,"1021021675850":1478686417090,"1025627657415":1509788624202,"1021021675849":1478686417090,"1021021675848":1478686417090,"1025627657413":1509788624202,"1021654206387":1478686417120,"1025627657418":1509788624202,"1025585451343":1509788624352,"1021021675843":1478686417090,"1025627657421":1509788624230,"1025627657426":1509788624214,"1025627657424":1509788624199,"1025585451348":1509788624351,"851503827":1444487341747,"1025627657425":1509788624229,"1025585451349":1509788624350,"1025627657430":1509788624212,"1025585451346":1509788624351,"1025627657431":1509788624198,"1025585451347":1509788624350,"1025627657428":1509788624211,"1025627657429":1509788624197,"1025585451345":1509788624350,"1020743021043":1478686417075,"1023145468111":1509788625182,"1025627657432":1509788624206,"1023145468108":1509788625182,"1023145468109":1509788625182,"1025522015506":1509788624295,"1023145468106":1509788625182,"1023145468107":1509788625182,"1022221801946":1478686417281,"1023145468104":1509788625182,"1023145468105":1509788625182,"1025714817425":1509788624540,"1021217611167":1478686417099,"1025714817426":1509788624542,"1016870214392":1478686804068,"1016870214393":1478686804068,"1016870214394":1478686804068,"1020726767830":1509788624389,"1023561599453":1509788624417,"1021223247229":1478686417003,"1002762707342":1480585069061,"1008292993629":1480585069074,"1015292542093":1478686804067,"1024695094326":1509788624291,"1025627657362":1509788624270,"1020971478552":1478686417086,"1021958433223":1478686417010,"1008130351609":1478686804034,"1023821264957":1491634246535,"1025627657367":1509788624269,"1025627657369":1509788624214,"1021958433225":1478686417010,"1021958433224":1478686417010,"1021958433226":1478686417010,"1025627657376":1509788624213,"1025627657386":1509788624214,"1022425748945":1478686417210,"1025627657391":1509788624199,"1025714817475":1509788624204,"1025714817477":1509788624185,"1021174225441":1478686417098,"1025627657397":1509788624203,"1020965711579":1478686417001,"1006788850140":1478686804046,"1025627657405":1509788624203,"1016870214236":1478686804068,"1016870214237":1478686804068,"1025627657283":1509788625121,"1019932745940":1480585069095,"1016870214234":1478686804068,"1016870214235":1478686804068,"1025627657293":1509788625121,"1025627657298":1509788625168,"1024779502049":1509788624244,"1024779502050":1509788624244,"1024779502052":1509788624244,"1024779502053":1509788624244,"1024961313807":1509788624970,"1023145467982":1509788624574,"1025627657306":1509788625167,"1021716347774":1478686417250,"1023145467983":1509788624574,"1025627657307":1509788625143,"1024779502058":1509788624244,"1023145467980":1509788624574,"1024779502059":1509788624244,"1023145467981":1509788624574,"1025627657305":1509788625111,"1023145467978":1509788624574,"1024695094501":1509788624291,"1023145467979":1509788624574,"1016456966652":1478686804040,"1024779502062":1509788624244,"1025627657308":1509788625105,"1023145467977":1509788624574,"1025627657309":1509788625138,"1022318927546":1478686417200,"1025627657315":1509788625129,"1025627657312":1509788625110,"1022185186999":1478686417063,"1665842171":1444487341741,"1010013630937":1491634246521,"1025907098761":1509788667459,"1665842172":1444487341750,"1022024101176":1478686417163,"1024225878216":1509788624990,"1019819633069":1509788624932,"1025907098757":1509788667463,"1021140408477":1478686417037,"1025797262952":1509788625086,"1020243497855":1465470268312,"1023076658211":1509788624378,"1023076658212":1509788624378,"1021743873173":1478686417009,"1023145467904":1509788624242,"1019105812291":1478686804020,"1025627657248":1509788625246,"1025627657252":1509788625243,"1025627657259":1509788625141,"1025627657257":1509788625141,"1025627657263":1509788625143,"1025627657266":1509788625111,"1021681744100":1509788624400,"1019932483752":1509788624922,"1025627657270":1509788625121,"1025797262942":1509788625123,"1025797262943":1509788625105,"1021413689617":1509788624816,"1022249196253":1509788624301,"1024294561117":1509788625032,"1020900567948":1509788625221,"1024494031224":1509788624228,"1020900567957":1509788625221,"1008576629287":1478686804030,"1020900567965":1509788625221,"1019300186868":1478686804018,"1020900567975":1509788625220,"1024095332633":1509788667459,"1020900567996":1509788625221,"1015292542453":1478686804067,"1022202272175":1480585069086,"1009181273672":1478686804030,"1021632448439":1509788624396,"1022218787142":1478686417281,"1021345928515":1478686416989,"1020900568024":1509788625221,"1021117884122":1465470268312,"1024547246657":1509788667496,"1020900568040":1509788625221,"1022473587120":1478943089531,"1025528831966":1509788624337,"1025528831967":1509788624339,"1021292580958":1478686417040,"1025528831962":1509788624341,"1024460873672":1509788625029,"1025710884939":1509788624306,"1019891855136":1509788624311,"1020221214860":1509788624374,"1012395830811":1478686804055,"1020741185928":1478686417028,"1022184269714":1478686417063,"1022184269719":1478686417063,"1019908501042":1509788624375,"1022403334795":1478686417207,"1501855790":1491634246534,"1022929203722":1509788625073,"1025147303636":1509788625171,"1021816352857":1509788625013,"1022123057680":1478686417183,"1020954045633":1478686416988,"1025202482051":1509788624515,"1020918917845":1478686804031,"1019704422962":1509788624354,"1025627657473":1509788624916,"1020900567875":1509788625221,"1022301756616":1478686417068,"1020900567884":1509788625221,"1025627657487":1509788624831,"1025627657484":1509788624848,"1025627657485":1509788624826,"1021958301771":1478686417147,"1025402365824":1509788625083,"1020900567895":1509788625221,"1020726767927":1478686416982,"1025627657494":1509788624831,"1025627657495":1509788624831,"1020900567889":1509788625221,"1020900567903":1509788625221,"1021007520254":1478686417089,"1025627657502":1509788624830,"1025627657506":1509788624868,"1025627657505":1509788624830,"1025627657510":1509788624844,"1025627657511":1509788624822,"1025627657508":1509788624866,"1025627657509":1509788624848,"1025627657515":1509788624824,"1025627657513":1509788624845,"1025627657516":1509788624836,"1020900567913":1509788625221,"1009203290156":1478686804054,"1009203290153":1478686804054,"1020900567935":1509788625221,"1008603106425":1478686804061,"1022402286332":1478686417070,"1022402286333":1478686417070,"1020850632093":1478686804050,"1011890144177":1478686804062,"1020850632092":1478686804050,"1024281059588":1509788624931,"1011890144178":1478686804062,"1024281059586":1509788624931,"1007587967491":1478686804030,"1011890144180":1478686804062,"1025714817975":1509788625106,"1025714817977":1509788625087,"1024281059592":1509788624931,"1023561599994":1509788624191,"1873589690":1444487341702,"1011890144168":1478686804062,"1011890144171":1478686804062,"1011890144173":1478686804062,"1011890144175":1478686804062,"1024116566250":1509788625035,"1011890144145":1478686804062,"1021880710682":1478686804069,"1011890144146":1478686804062,"1022199473439":1478686417280,"1011890144149":1478686804062,"1011890144148":1478686804062,"1011890144151":1478686804062,"1011890144150":1478686804062,"1011890144152":1478686804062,"1021952142278":1478686417146,"1021663905076":1478686417248,"1011890144139":1478686804062,"1011890144143":1478686804062,"1011890144142":1478686804062,"1016399428744":1480585069069,"1021880710769":1478686804069,"115530929":1444487341711,"4828612010":1509788624161,"1025561203376":1509788624523,"1025561203377":1509788624523,"1021170030844":1478686417098,"1021729061210":1478686417123,"1023172993865":1509788625044,"1004684194213":1509788624972,"1020849321258":1478686417078,"1024554587770":1509788624927,"1021897881498":1478686416979,"1008873258959":1444487341757,"1008873258962":1444487341757,"1019601141419":1478686804050,"1019601141418":1478686804050,"1019601141417":1478686804050,"1208783551":1444487341749,"1019601141416":1478686804050,"1008873258966":1444487341757,"1019601141421":1478686804050,"1001052490046":1478686417022,"1019601141420":1478686804050,"1019601141415":1478686804050,"1019601141414":1478686804050,"1019601141413":1478686804050,"1011890144113":1478686804062,"1021390362032":1478686417006,"1011890144115":1478686804062,"1011890144114":1478686804062,"1021930780155":1478686417142,"1011890144117":1478686804062,"1009352759346":1478686804055,"1019227182217":1509788625079,"1025876164830":1509788667402,"1021880710902":1478686804069,"1025876164831":1509788667402,"1025896089104":1509788667465,"1011890144098":1478686804062,"1022409365090":1478686417208,"1019811375943":1509788625017,"1011890144100":1478686804062,"1011890144103":1478686804062,"1009352759342":1478686804055,"1011890144104":1478686804062,"1021880710881":1478686804069,"1011890144106":1478686804062,"1019811375944":1509788625017,"1011890144109":1478686804062,"1011890144108":1478686804062,"1011890144111":1478686804062,"1024779502510":1509788624244,"1011890144110":1478686804062,"1011890144080":1478686804062,"1011890144083":1478686804062,"1011890144084":1478686804062,"1011890144087":1478686804062,"1025876164853":1509788667403,"1011890144089":1478686804062,"1025876164859":1509788667405,"1025876164856":1509788667402,"1873589568":1444487341754,"1020294222939":1465470268298,"1010013631385":1491634246521,"1021303984238":1478686417004,"1010013631390":1491634246521,"1021452224854":1509788624399,"1025876164837":1509788667406,"1025876164842":1509788667406,"1021217873730":1478686417099,"1022076396176":1478686417177,"1010013631382":1491634246526,"1025876164847":1509788667405,"1025876164844":1509788667403,"1003709033041":1478686804060,"1003709033042":1478686804060,"1003709033045":1478686804060,"1021880710975":1478686804069,"1003709033047":1478686804060,"1003709033048":1478686804060,"1003709033051":1478686804060,"1003709033050":1478686804060,"1012599232633":1478686417074,"1003709033055":1478686804060,"1016810333564":1509788625020,"1025797262774":1509788624424,"1025797262772":1509788624428,"1003709033026":1478686804060,"1021880710947":1478686804069,"1025627789273":1509788624999,"1022254831825":1478686417196,"1870181468":1478950494927,"4563195094":1465469681387,"1022620123954":1509788625075,"1022160414298":1478686417186,"1003709033062":1478686804060,"1021880710924":1478686804069,"1003709033068":1478686804060,"1025627789311":1509788624997,"1021951879865":1478686417146,"1022094484024":1478686417181,"1020047696944":1509788625078,"1004035382926":1478686804051,"1020047696946":1509788625077,"1365412396":1444487341741,"1015292542852":1478686804067,"1024210938884":1509788624608,"1024210938885":1509788624608,"1024210938886":1509788624608,"1004035382929":1478686804051,"1024210938880":1509788624608,"240702733":1478686804024,"1004035382930":1478686804051,"1021906531792":1509788624466,"1020294092235":1465470268288,"1025627789222":1509788625001,"1024797720883":1509788625069,"1022360081130":1478686417203,"415548329":1444487341743,"1022022790871":1478686417163,"1021240548660":1478686417003,"1022412511004":1478686417208,"1025880752336":1509788667811,"1021866948460":1509788624394,"1021880711089":1478686804069,"1021832475285":1478686804026,"1021170030852":1478686417098,"1024398875027":1509788624383,"1024398875028":1509788624383,"1024398875029":1509788624383,"1024398875030":1509788624383,"1024398875031":1509788624383,"1024398875032":1509788624383,"1022631396065":1509788624424,"1024637684320":1509788667503,"1022202272582":1480585069085,"1016399428976":1480585069069,"499041911":1444487341740,"1022191477862":1478686416989,"1025662522703":1509788625086,"1021493776071":1509788624398,"1023440884426":1509788625081,"1020781948993":1478686416997,"1024281059571":1509788624931,"1024281059569":1509788624946,"1016531809553":1480585069063,"415548223":1444487341743,"1026223387456":1514456869766,"1016400083653":1480585069069,"1024210938694":1509788625242,"1025245342111":1509788624937,"1022208695449":1480585069113,"1024210938690":1509788625242,"1024210938691":1509788625242,"1024210938700":1509788625241,"1024210938702":1509788625241,"1021812814906":1478686417132,"1024210938697":1509788625242,"1022460089262":1478686417217,"1022648567402":1509788624462,"1024210938698":1509788625242,"1024210938740":1509788624914,"1024210938741":1509788624915,"1024210938743":1509788624915,"1024210938736":1509788624915,"1024210938739":1509788624915,"1024210938751":1509788624914,"1024210938746":1509788624915,"1020744594884":1509788624389,"1024210938734":1509788624914,"1024411459454":1509788625070,"1021812814946":1478686417132,"1021812814944":1478686417132,"1024210938643":1509788625241,"1024210938653":1509788625242,"1021121815355":1478686417095,"719910565":1478950494915,"1021475031051":1478686417109,"1024210938650":1509788625242,"1024210938630":1509788625242,"1024210938625":1509788625242,"1024210938626":1509788625242,"1025628704907":1509788624507,"1024210938639":1509788625242,"1024210938677":1509788625241,"1021812814927":1478686417132,"1024210938685":1509788625242,"1024210938687":1509788625242,"1022208695520":1480585069115,"1022067485561":1509788624226,"1024210938662":1509788625242,"1021735745708":1509788624850,"1021812814930":1478686417132,"1024210938657":1509788625242,"1025797262032":1509788624537,"1021735745705":1509788624850,"1021735745704":1509788624850,"1024210938668":1509788625241,"1021735745700":1509788624850,"1021812814938":1478686417132,"1024210938836":1509788624608,"776794830":1491634246510,"1024886865000":1509788624460,"1024210938846":1509788624608,"1024886864993":1509788624461,"1021887000918":1478686804027,"1024886864999":1509788624461,"1024210938843":1509788624608,"1024886865018":1509788624460,"1013010792538":1465470268318,"1024210938819":1509788624608,"1024210938828":1509788624608,"1024886865008":1509788624460,"1024210938830":1509788624608,"1024886865009":1509788624460,"1024210938831":1509788624608,"1008155780787":1478686804030,"1024210938825":1509788624608,"1024886865012":1509788624461,"1024210938827":1509788624608,"719910474":1478950494915,"1024210938870":1509788624608,"1024210938864":1509788624608,"1022072071286":1509788624921,"1024210938876":1509788624608,"1024886864963":1509788624460,"1025322411454":1509788624306,"1024886864960":1509788624461,"719910467":1478950494915,"1024886864961":1509788624461,"1024210938873":1509788624608,"1021990022937":1478686417155,"1022443835942":1478686417295,"1021340553465":1465470268223,"1022178108108":1478686417278,"719910489":1478950494915,"1024210938853":1509788624608,"1021340553467":1465470268223,"1024210938854":1509788624608,"1021340553466":1465470268223,"719910491":1478950494915,"1024210938848":1509788624608,"1021340553468":1465470268223,"1023939230675":1509788624519,"1025860044381":1509788667462,"1024210938860":1509788624608,"1024210938861":1509788624608,"1024210938857":1509788624608,"1024210938774":1509788624915,"1024210938768":1509788624914,"1024210938769":1509788624914,"1024210938770":1509788624915,"1024210938771":1509788624915,"1024210938780":1509788624914,"1009716218852":1478686804032,"1024210938781":1509788624914,"1025507858733":1509788624340,"1024210938776":1509788624915,"1024210938778":1509788624915,"1024210938779":1509788624915,"1017260934470":1465470268269,"1004910159211":1478686804040,"1024210938758":1509788624914,"1024210938754":1509788624914,"1021909938848":1478686417140,"1022370043447":1509788624300,"1024210938765":1509788624914,"1022239628814":1478686417283,"1025628704782":1509788624507,"1024210938760":1509788624914,"1024210938762":1509788624914,"1018478657024":1509788624372,"719910413":1478950494914,"1020650618752":1478686416996,"1020650618757":1478686416996,"1022208695394":1480585069114,"1025147827087":1509788624929,"1022030129575":1509788624463,"1003709033552":1478686804060,"1016317115605":1509788624284,"1003709033556":1478686804060,"1012791120608":1478686804062,"1022736646706":1509788624301,"1022208695691":1480585069114,"1022736646707":1509788624301,"1003709033563":1478686804060,"1020444166871":1478686804033,"1021501639621":1509788624451,"1022208695700":1480585069113,"1021899714612":1509788625240,"1208784174":1444487341728,"1024210938486":1509788624266,"1022114015095":1478686417183,"1003709033588":1478686804060,"1024210938481":1509788624266,"1003709033591":1478686804060,"1024210938483":1509788624266,"1003709033595":1478686804060,"1021885952231":1478686417137,"1024210938488":1509788624266,"1024210938489":1509788624266,"1298305100":1478686804068,"1024210938490":1509788624266,"1003709033598":1478686804060,"1021705207737":1478686417050,"1003709033572":1478686804060,"1022208695737":1480585069113,"1003709033577":1478686804060,"1024210938476":1509788624266,"1012791120607":1478686804062,"1024210938478":1509788624266,"1003709033580":1478686804060,"1021705207731":1478686417050,"1025669731198":1509788667457,"1021790403293":1509788624399,"1021705207744":1478686417050,"1298305079":1478686804068,"1014942700278":1478686804028,"1014617007702":1465470268319,"1023242724273":1509788625102,"1017168268921":1478686804040,"1021920817843":1509788624466,"1017770551888":1478686804022,"1021914919781":1478686417054,"1024773604551":1509788624438,"1021089570876":1478686417094,"1015334484942":1478686804062,"1021734173040":1509788624395,"1022208695558":1480585069114,"158389501":1444487341754,"1024210938560":1509788624266,"1024210938572":1509788624266,"1025880753716":1509788667811,"1024210938573":1509788624266,"1024210938574":1509788624266,"1191352991":1444487341735,"1022674780506":1480585069068,"1024210938571":1509788624266,"1024210938613":1509788625241,"1024210938614":1509788625242,"1015334484974":1478686804062,"1012822445474":1478686417224,"1001052491299":1478686417022,"1007646949680":1478686804032,"1020971477991":1478686417086,"1024210938619":1509788625242,"1022325086733":1478686417288,"1019676505133":1509788624315,"1020787455738":1478686417029,"1015334484977":1478686804063,"1022208695602":1480585069113,"1015334484874":1478686804062,"1021757765807":1509788624993,"1015334484875":1478686804062,"1015334484873":1478686804062,"512279372":1491634246518,"1024210938513":1509788624266,"1021786602000":1509788624997,"1012587306959":1478686417074,"1024210938522":1509788624266,"1003709033601":1478686804060,"1024210938500":1509788624266,"1003709033603":1478686804060,"268227119":1478950494908,"1024210938497":1509788624266,"1020812619801":1478686417030,"1022207384957":1478686417013,"1024210938505":1509788624266,"1010863341843":1478686804049,"1024210938550":1509788624266,"337693131":1491634246518,"1024210938559":1509788624266,"1024210938553":1509788624266,"1022208695651":1480585069114,"1024210938529":1509788624266,"1024210938537":1509788624266,"1021845189717":1480585069080,"1021845189718":1480585069080,"1021845189713":1480585069080,"1021984648675":1478686417264,"1021845189715":1480585069080,"1022628644739":1509788624915,"1021845189723":1480585069080,"1021742561895":1478686804038,"1021845189701":1480585069080,"1021742561894":1478686804038,"1021742561893":1478686804038,"1021845189703":1480585069080,"1021742561892":1478686804038,"1021742561891":1478686804038,"1023145469634":1509788625183,"1021742561890":1478686804038,"115398902":1444487341756,"1021742561889":1478686804038,"1021845189699":1480585069080,"1023242723580":1509788624196,"1021742561888":1478686804038,"1021845189709":1480585069080,"1021845189708":1480585069080,"1021845189711":1480585069080,"1021845189710":1480585069080,"1021845189704":1480585069080,"1021742561897":1478686804038,"1021845189707":1480585069080,"1021742561896":1478686804038,"1021845189706":1480585069080,"1021845189749":1480585069081,"1016399821035":1480585069069,"1021845189748":1480585069081,"1021845189750":1480585069081,"1021845189745":1480585069081,"1022713053368":1509788624569,"1021845189744":1480585069080,"1021845189747":1480585069081,"1021845189746":1480585069081,"1021845189756":1480585069081,"1021845189753":1480585069081,"1021845189752":1480585069081,"1021845189755":1480585069081,"1005797175541":1480585069070,"1022404514514":1478686417207,"1021937856228":1478686804072,"1021845189743":1480585069080,"1021288650533":1465469681397,"1021168590028":1478686416977,"1021742561831":1478686804038,"1021168590033":1478686416977,"1021742561835":1478686804038,"1023784812774":1509788624960,"1021742561834":1478686804038,"1021742561833":1478686804038,"1024695093798":1509788624291,"1021742561832":1478686804038,"1022966297348":1509788624996,"1022966297346":1509788624996,"1022211710480":1478686417281,"1016870214829":1478686804018,"1021865375091":1509788624394,"1022170243202":1509788624924,"1021996969299":1478686417057,"1021010536084":1478686416991,"1021036750049":1478686417035,"1021845189841":1480585069081,"1021845189840":1480585069081,"1024185772113":1509788625071,"1020900568065":1509788625221,"1022152811372":1478686417277,"1021036750070":1478686417035,"1021845189830":1480585069081,"1024481188267":1509788667836,"1021036750065":1478686417035,"1021845189825":1480585069081,"1021845189824":1480585069081,"935651665":1509788624310,"1021036750067":1478686417035,"1021908627707":1478686417259,"1023953647132":1509788624437,"1021845189826":1480585069081,"1021845189836":1480585069081,"1021036750079":1478686417035,"1021845189839":1480585069081,"935651678":1509788624310,"1021845189832":1480585069081,"1021845189834":1480585069081,"1018288457973":1478686804053,"1018288457975":1478686804053,"1018288457974":1478686804053,"1879748270":1444487341709,"1018288457969":1478686804053,"1018288457968":1478686804053,"1018288457971":1478686804053,"1018288457970":1478686804053,"935651694":1509788624310,"935651695":1509788624311,"1006011475122":1478686804046,"1018288457977":1478686804053,"1018288457976":1478686804053,"1018288457978":1478686804053,"1024780158953":1509788624452,"1022441082976":1478686417295,"1879748284":1444487341709,"1022185185449":1478686417063,"1023945128372":1509788667535,"1021036750044":1478686417035,"935651588":1509788624310,"1025891108303":1509788667406,"1012668307860":1478686417224,"1021135298118":1480585069070,"1019815833576":1509788625081,"1021845189761":1480585069081,"1021845189760":1480585069081,"1023161460503":1509788625044,"1024763774613":1509788625069,"1022284585680":1478686417014,"1021742561953":1478686804039,"1021845189763":1480585069081,"1021742561952":1478686804039,"115005442":1444487341734,"1022477520473":1478943089487,"1021845189821":1480585069081,"1021742561950":1478686804039,"1021845189820":1480585069081,"1021742561949":1478686804039,"1021845189823":1480585069081,"1021742561948":1478686804039,"1021742561947":1478686804038,"1024098873102":1509788624555,"1021845189816":1480585069081,"1024098873103":1509788624556,"1021845189819":1480585069081,"1024098873107":1509788624556,"1024098873104":1509788624556,"1024098873105":1509788624556,"1021483944750":1509788624977,"1007384023771":1478686804032,"935651645":1509788624310,"1007384023760":1478686804032,"1025627657154":1509788624551,"1025627657153":1509788624551,"1023393962208":1509788624847,"1025627657162":1509788624541,"1021540829042":1478686417113,"1025627657161":1509788624538,"1025627657164":1509788624541,"1024779503201":1509788624580,"1025627657168":1509788624541,"1024779503202":1509788624580,"1025627657169":1509788624541,"1024779503203":1509788624580,"1020626107895":1478686417075,"1024779503204":1509788624580,"1024779503209":1509788624580,"1024779503210":1509788624580,"1024779503211":1509788624580,"719910390":1478950494914,"1023957055318":1509788624520,"1019053251459":1509788625019,"1024454711690":1509788625030,"1022068008903":1478686417175,"1025627657192":1509788624566,"719910339":1478950494914,"1025627657199":1509788624866,"1016694335607":1478686804068,"1025627657197":1509788624538,"1025627657202":1509788624536,"1025627657203":1509788624845,"1025627657200":1509788624848,"1025627657201":1509788624844,"1023330000098":1509788625072,"1879748415":1444487341751,"1025627657204":1509788624824,"1025627657205":1509788624544,"1025784023720":1509788624351,"1021460745241":1478686417045,"1025784023726":1509788624351,"1879748419":1444487341753,"935651476":1509788624310,"1021742431014":1478686417253,"1879748444":1444487341751,"1016677427464":1465470268261,"1022811110387":1509788624363,"1021742431022":1478686417253,"1020997822341":1478686417230,"1023145469832":1509788624242,"1021604135912":1478686804046,"1021845189941":1480585069081,"1021845189940":1480585069081,"719910282":1478950494914,"1021845189943":1480585069081,"1021845189942":1480585069081,"1024244622903":1509788624949,"1021845189939":1480585069081,"1002497191":1444487341744,"719910273":1478950494914,"1021845189948":1480585069081,"1022415262519":1478686417292,"1021845189950":1480585069081,"1021845189945":1480585069081,"1021845189944":1480585069081,"1021845189946":1480585069081,"1022579100151":1480585069124,"1001052491001":1478686417022,"1021845189933":1480585069081,"1024098872986":1509788624852,"1021845189932":1480585069081,"1024098872987":1509788624852,"1019932485410":1509788624922,"1021845189935":1480585069081,"1021845189929":1480585069081,"1025627657150":1509788624612,"1024098872990":1509788624852,"1021845189928":1480585069081,"1025627657151":1509788624611,"1879748468":1444487341753,"1024098872988":1509788624852,"1024098872989":1509788624852,"1879748480":1444487341751,"1024779503328":1509788625193,"1024779503329":1509788625194,"1024779503331":1509788625194,"1022966297331":1509788624996,"1024779503335":1509788625193,"1024779503336":1509788625193,"1024779503337":1509788625193,"1021557212926":1478686417048,"1023152154606":1509788625045,"1879748526":1444487341754,"1879748527":1444487341752,"1023076658006":1509788624358,"1023076658008":1509788624358,"1023076658009":1509788624358,"935651433":1509788624310,"1024779503325":1509788625193,"1013077393219":1478686804064,"1007838722179":1509788624386,"1022007061256":1478686417057,"1021304509736":1478686417238,"1021625107148":1509788624815,"935651448":1509788624310,"1021018662487":1478686417231,"1025593840904":1509788625022,"1879748549":1444487341752,"1025525160238":1509788624523,"1022067484867":1509788625083,"1008058133442":1480585069065,"935651354":1509788624310,"1022446195076":1478686417214,"1022713053561":1509788625171,"1025711541797":1509788624307,"1018767928394":1509788624366,"935651381":1509788624310,"1023141799706":1509788624453,"1012111669661":1478686416993,"1021721066567":1509788625084,"1023145469743":1509788624574,"1022128039042":1478686417184,"1021985166331":1478686417057,"1020597518525":1478686804026,"1021990802328":1478686417155,"1022282359870":1478686417286,"1022473597148":1478943089531,"1020810644931":1509788624359,"1021674782797":1478686416984,"1023752191164":1509788624926,"1022244872790":1478686417284,"1017112178756":1509788624300,"1025068911109":1509788624307,"1023442987308":1509788625081,"1009708496780":1491634246511,"1021976121939":1478686417056,"1013247249132":1465470268319,"1021885550066":1509788624465,"1021490246961":1509788624977,"1021819226520":1478686417053,"1021983724150":1509788624417,"1021983724144":1509788624417,"1025607608932":1509788624542,"1025607608933":1509788624537,"1025607608934":1509788624524,"1021971927775":1478686417150,"1013100970264":1478686804066,"1025607608931":1509788624540,"1021744907482":1478686416972,"1022008759323":1509788624424,"1020807367825":1478686417030,"1021854223119":1478686417135,"1020943684775":1478686417000,"1022111652544":1478686417182,"1018245739641":1509788625079,"1021925527510":1478686417055,"1021831416247":1478686417053,"1022421429566":1478686417209,"1023242722859":1509788624819,"1024442787235":1509788624925,"1024442787232":1509788624925,"1024442787237":1509788624925,"1021424972172":1509788624978,"1025532896896":1509788624341,"1012641703457":1478686417074,"1024086544466":1509788667495,"1022236090896":1478686417193,"1025176654168":1509788625079,"1024690517438":1509788624486,"1024690517439":1509788624487,"1024690517436":1509788624487,"1024690517434":1509788624487,"1024690517433":1509788624487,"1024690517431":1509788624486,"1022712545166":1509788625058,"1016634168806":1478686804058,"1016634168807":1478686804058,"1016634168804":1478686804058,"1016634168805":1478686804058,"1016634168810":1478686804058,"1016634168811":1478686804058,"1016634168808":1478686804058,"1016634168809":1478686804058,"1020781808287":1478686417076,"1011856733855":1478686804024,"1021500995573":1478686804040,"1025902525773":1509788667461,"1025902525774":1509788667462,"1021747791159":1478686804066,"1022442925953":1478686416984,"1019716733440":1509788624316,"1024690517378":1509788624486,"1021683302593":1478686417249,"1024690517376":1509788624486,"1022426147977":1478686417294,"4818402931":1509788624156,"1021955674342":1478686417056,"1021955674348":1478686417056,"1016399677336":1480585069069,"1020960592966":1478686417000,"1024690517478":1509788624487,"1021606510024":1478686417048,"1013100970038":1478686804066,"1021693788163":1480585069064,"1024536242860":1509788625026,"1024690517472":1509788624486,"1021750805652":1509788624395,"1020960593009":1478686417000,"1024690517468":1509788624486,"1024690517469":1509788624486,"1022700878901":1509788624973,"1016847933782":1478686804018,"1024690517465":1509788624486,"1022169325455":1478686417013,"1024690517458":1509788624486,"1020960593022":1478686417000,"1016098354611":1478686804026,"1024690517452":1509788624486,"1016098354609":1478686804019,"1024690517453":1509788624486,"1022371490701":1480585069097,"1024690517449":1509788624486,"1024690517447":1509788624486,"1024966411606":1509788625100,"1024690517445":1509788624486,"1020960593006":1478686417000,"1024690517440":1509788624486,"1025237210505":1509788624268,"1020886667512":1509788624177,"1021659594435":1509788624199,"1016779136419":1478686804017,"1023836454921":1491634246536,"1020960593030":1478686417000,"1021682122822":1478686417121,"1022280001010":1478686417067,"1024690517372":1509788624486,"1024690517371":1509788624486,"1022269252310":1478686417285,"1022269252311":1478686417285,"1023048209221":1509788625079,"1022269252312":1478686417285,"1024690517367":1509788624486,"1024690517362":1509788624486,"1024690517356":1509788624486,"1024690517352":1509788624486,"1016254200899":1480585069062,"1020900823897":1480585069064,"1024690517346":1509788624486,"1023932007977":1491634246530,"1024690517343":1509788624486,"1024690517340":1509788624486,"1024690517341":1509788624486,"1016092455647":1509788624941,"1021396004599":1478686416986,"1021396004598":1478686416986,"1024690517332":1509788624486,"1024690517331":1509788624486,"1024690517329":1509788624486,"1024690517326":1509788624486,"1000984079956":1478686417022,"1024690517327":1509788624486,"1024690517325":1509788624486,"1573698617":1491634246509,"1021680550393":1478686804028,"1025364745616":1509788624294,"1309453324":1491634246534,"1022882269812":1509788624553,"1019022712962":1509788625019,"1021243565092":1480585069071,"1024596274240":1509788624299,"1023612335870":1509788624952,"1021659594084":1509788624919,"1021659594087":1509788624920,"1021545036314":1478686417245,"171239441":1444487341725,"1392554279":1480585069072,"1021659594095":1509788624920,"1023721650261":1509788625110,"1021659594089":1509788624920,"1021659594101":1509788624920,"1021659594102":1509788624919,"1021659594096":1509788624920,"1021659594099":1509788624919,"1566621527":1444487341702,"1021659594098":1509788624920,"1021659594111":1509788624919,"1021886992352":1478686804027,"1021659594110":1509788624919,"1021659594105":1509788624919,"1025667116118":1508010983409,"1025101942394":1509788624308,"1023612335782":1509788624952,"1022458523118":1478686417217,"1025101942387":1509788624307,"1021680550472":1478686804028,"1023612335788":1509788624952,"1024383148895":1509788624330,"1025101942377":1509788624308,"1021885812632":1509788624818,"1023612335793":1509788624952,"1024690517738":1509788625201,"1023612335799":1509788624952,"1022264271114":1478686417067,"1024690517737":1509788625200,"1025101942368":1509788624308,"1023612335802":1509788624952,"1024690517734":1509788625200,"1024690517732":1509788625200,"1024690517730":1509788625200,"1024690517731":1509788625200,"1024030838350":1509788624521,"1407627705":1444487341729,"1021962228480":1478686417148,"1024690517729":1509788625200,"1024690517727":1509788625200,"1024690517724":1509788625200,"1024690517725":1509788625200,"1024690517722":1509788625200,"1024690517723":1509788625200,"1023612335748":1509788624952,"1024690517721":1509788625201,"1022263484704":1478686417285,"1021292456770":1478686417238,"1024690517719":1509788625201,"1023612335753":1509788624952,"1024690517717":1509788625201,"1024690517714":1509788625201,"1023612335759":1509788624952,"1023612335757":1509788624952,"1024690517713":1509788625201,"1022037464243":1509788625066,"1024690517711":1509788625200,"1025322408807":1509788624305,"1023612335761":1509788624952,"1021703618769":1478686417250,"1025874606206":1509788667581,"1023612335767":1509788624952,"1023612335771":1509788624952,"1023612335773":1509788624952,"1020943685265":1478686417000,"1000984079649":1478686417022,"1021885812556":1509788624195,"1021600611904":1478686416984,"1025874606208":1509788667580,"1022444366873":1478686417214,"1021796156856":1509788624399,"1020927956603":1478686417082,"1021693658054":1478686417121,"1021257328095":1478686417100,"1020927956606":1478686417082,"1023612335683":1509788624955,"1023612335680":1509788624955,"1023612335686":1509788624955,"1023612335690":1509788624955,"1023612335688":1509788624955,"1022165000072":1478686417186,"1021680550570":1478686804028,"1023612335698":1509788624955,"1023612335699":1509788624955,"1023612335696":1509788624955,"1023612335700":1509788624955,"1022238842999":1509788624947,"1023612335701":1509788624955,"1021885812593":1509788624420,"1022238843002":1509788624932,"1025101942403":1509788624308,"1022238843004":1509788624941,"1022238843006":1509788624941,"1023612335650":1509788624954,"1021659594118":1509788624919,"1021659594113":1509788624920,"1023612335654":1509788624955,"1020605252347":1478686417075,"1021659594115":1509788624919,"1356902951":1491634246513,"1021659594114":1509788624920,"1021659594121":1509788624920,"1021659594122":1509788624920,"1023612335674":1509788624955,"1022158053206":1478686417185,"1025569467058":1509788624350,"1021786588479":1509788624997,"1022882269837":1509788624567,"1024054430819":1509788624941,"1025672228055":1509788624921,"1024237935433":1509788667493,"1003909963689":1478686804046,"1025569467055":1509788624350,"1024237935439":1509788667493,"1021098482724":1478686417095,"1021680550650":1478686804028,"1004352977907":1444487341712,"1016549887219":1509788624944,"1020574596383":1509788624353,"4985899581":1509788624162,"1022053979346":1478686417059,"1022355630815":1478686417289,"1013079868341":1478686416995,"1021980709183":1478686417151,"1023612336067":1509788624952,"1016914257688":1478686804053,"1021269912486":1478686804033,"1016914257689":1478686804053,"1013100970568":1478686804066,"1023612336069":1509788624952,"1023612336074":1509788624952,"1023612336077":1509788624952,"1020817723064":1509788625021,"1020937918332":1478686417084,"1021733767116":1478686417124,"1024690517897":1509788624252,"1021455249582":1509788624399,"1023730694349":1509788624961,"1024690517893":1509788624252,"1012180994406":1478686417223,"1024690517889":1509788624252,"1023612336038":1509788624952,"1021714760026":1478686417123,"1023612336042":1509788624952,"1023612336040":1509788624952,"1023612336051":1509788624952,"1023612336048":1509788624952,"1020808941386":1478686417030,"1573699231":1491634246534,"1023612336049":1509788624952,"1023612336054":1509788624952,"1023612336053":1509788624952,"1021680550748":1478686804028,"1023612336062":1509788624952,"1025721643595":1509788624492,"1025629630414":1509788624428,"1025629630415":1509788624431,"1025221873785":1509788624999,"1573699235":1491634246509,"1025629630416":1509788624425,"1025629630418":1509788624406,"1014992777692":1509788624300,"1025767127018":1509788625137,"1025767127017":1509788625137,"1025767127020":1509788625137,"1025767127021":1509788625137,"1011253809158":1478686804066,"1021531405160":1509788624397,"1023995054513":1491634246529,"1021609918427":1478686417246,"1021802842963":1478686804065,"1019596539853":1509788624934,"1025010451485":1509788624461,"1021094157956":1478686417094,"1023612335939":1509788624952,"1012126598203":1478686417299,"1023612335946":1509788624952,"1022241595674":1509788624920,"1023612335951":1509788624952,"1021885812342":1509788624534,"1024690517886":1509788624252,"1023612335904":1509788624952,"1023612335911":1509788624952,"1024690517881":1509788624252,"1023612335909":1509788624952,"1024690517878":1509788624252,"1024690517876":1509788624252,"1023612335918":1509788624952,"1022030517990":1478686417058,"1024690517873":1509788624252,"1024690517870":1509788624252,"1373811251":1491634246518,"1024690517868":1509788624252,"1024690517869":1509788624252,"1023612335921":1509788624952,"1024690517866":1509788624252,"1016092455148":1509788624941,"1023612335926":1509788624952,"1021693788806":1480585069064,"1024690517863":1509788624252,"1022026454704":1478686417058,"1024690517861":1509788624252,"1024690517858":1509788624252,"1024588672269":1509788624169,"1024690517855":1509788624252,"1023612335875":1509788624952,"1004244185749":1480585069072,"1307880982":1491634246505,"1024690517853":1509788624252,"1024690517850":1509788624252,"1008105313486":1509788624389,"1021739272052":1478686417252,"1023612335891":1509788624952,"1021680550897":1478686804034,"1000984079443":1478686417021,"1023612335898":1509788624952,"1024055872878":1509788624328,"1463464762":1491634246509,"1022009544815":1509788624463,"1023242722018":1509788624535,"1024783449403":1509788625021,"1024588671693":1509788624279,"1021749625333":1509788624395,"1020985365426":1478686804039,"1022419462203":1509788624972,"1021747789869":1478686804029,"1022419462198":1509788624940,"1022419462199":1509788624972,"1021544119301":1478686417113,"1025679174545":1509788624352,"1024157323303":1509788667884,"1025679174548":1509788624352,"1018980129622":1509788624317,"1023129867240":1490882721866,"1021921725416":1478686417010,"1018559775313":1478686804071,"1020264343755":1509788624945,"1022444366558":1478686417214,"1025147816730":1509788624929,"1018513637550":1509788625229,"1022235043177":1478686417014,"1021262177134":1478686804039,"1021992507368":1478686416978,"1025514283277":1509788624337,"1022963927301":1509788625051,"1009211809231":1480585069074,"1021685925195":1478686417249,"1021659593688":1509788624826,"1021526684656":1478686417113,"1021526684659":1478686417113,"1021138314439":1478686417096,"1021138314436":1478686417096,"1020907902711":1478686804041,"1020907902710":1478686804041,"1020907902719":1478686804041,"1020907902718":1478686804041,"1022827610465":1509788624990,"1020907902717":1478686804041,"1020907902716":1478686804041,"1020907902715":1478686804041,"1020907902713":1478686804041,"1008601936249":1478686804030,"1020907902712":1478686804041,"1024370304262":1509788624927,"1014669564682":1478686804016,"1022201043945":1478686417280,"1014669564679":1478686804016,"1014669564698":1478686804016,"1014669564700":1478686804016,"1020580756290":1478686417027,"1021791175572":1478686417129,"1020134056109":1509788625076,"1022967859639":1509788625051,"1020134056106":1509788625078,"1023145467351":1509788624881,"1016681091845":1478686804018,"1023145467349":1509788624881,"1022149007677":1478686417185,"1022460095156":1478686417217,"1024920274920":1509788625217,"1023145467344":1509788624881,"1023145467358":1509788624881,"1024920274917":1509788625217,"1024920274918":1509788625218,"1024920274919":1509788625217,"1023145467354":1509788624881,"1024920274912":1509788625218,"1023145467355":1509788624881,"1022921461565":1509788624937,"1024920274913":1509788625218,"1024920274942":1509788625212,"1024920274929":1509788625211,"1024920274930":1509788625212,"1022235305015":1478686417193,"1024920274891":1509788625217,"1024920274884":1509788625217,"1024920274885":1509788625217,"1021979268983":1478686417151,"1024920274880":1509788625218,"1024920274881":1509788625218,"1024920274882":1509788625217,"1022015443202":1478686417160,"1020907902726":1478686804041,"1024920274909":1509788625217,"1020907902725":1478686804041,"1020907902724":1478686804041,"1020907902723":1478686804041,"1019347775493":1509788625080,"1020907902722":1478686804041,"1020907902721":1478686804041,"1020907902720":1478686804041,"1023145467361":1509788624881,"1024920274900":1509788625217,"1019001742568":1480585069068,"1022131445279":1478686417276,"1020927562197":1478686417228,"1020927562196":1478686417228,"1023129866980":1490882721866,"1025023036813":1509788625021,"1021659593222":1509788624515,"1021914254200":1509788625009,"1021914254206":1509788625008,"1021659593219":1509788624515,"1021914254204":1509788625008,"1021659593229":1509788624515,"1021914254195":1509788625008,"1024920274853":1509788625210,"1024920274854":1509788625210,"1021914254192":1509788625008,"1025036012874":1509788624233,"1021914254199":1509788625009,"1024920274848":1509788625211,"1021914254197":1509788625009,"1024920274850":1509788625210,"1024920274851":1509788625211,"1024920274876":1509788625218,"1021914254186":1509788625009,"1024920274878":1509788625218,"1021914254184":1509788625009,"1021914254191":1509788625008,"1024920274873":1509788625218,"1021914254189":1509788625009,"1024920274874":1509788625218,"1021914254188":1509788625009,"1024920274875":1509788625218,"1021659593245":1509788624515,"1021914254179":1509788625008,"1024920274868":1509788625217,"1024920274869":1509788625218,"1024920274870":1509788625218,"1021914254183":1509788625009,"318830173":1444487341731,"1021914254182":1509788625009,"1021914254181":1509788625009,"1019065311369":1509788624933,"1024920274830":1509788625210,"1025796354999":1509788624274,"1024920274825":1509788625211,"1021659593251":1509788624515,"1020821653564":1478686417078,"1022452755303":1478686417215,"1021659593250":1509788624515,"1021659593261":1509788624515,"1024920274820":1509788625211,"1021659593260":1509788624515,"1024920274821":1509788625211,"1021659593263":1509788624515,"1021659593262":1509788624515,"1024920274823":1509788625211,"1024920274819":1509788625209,"1021659593269":1509788624515,"1024920274844":1509788625210,"1021659593265":1509788624515,"1024920274840":1509788625210,"1024383149157":1509788624330,"1021659593264":1509788624515,"1024920274841":1509788625210,"1021659593267":1509788624515,"1024920274842":1509788625210,"1021659593266":1509788624515,"1024920274843":1509788625210,"1021659593277":1509788624515,"1024920274836":1509788625210,"1024920274838":1509788625210,"1024920274832":1509788625210,"1024920274833":1509788625210,"1024920274834":1509788625210,"1024920274835":1509788625210,"1018972264980":1509788624945,"1024920274792":1509788624487,"1024920274793":1509788624488,"1024920274794":1509788624487,"1024920274795":1509788624487,"1022009414119":1509788625075,"1024920274789":1509788624488,"1024920274791":1509788624488,"1024920274784":1509788624487,"1024920274786":1509788624487,"1018509444742":1509788624426,"1024920274787":1509788624487,"1022967204078":1509788625051,"818730321":1444487341744,"1020862682456":1509788625002,"1021678716351":1478686417120,"1024920274764":1509788624488,"1024920274766":1509788624488,"1025508515928":1509788624346,"1024920274760":1509788624488,"1025508515929":1509788624341,"1024920274761":1509788624488,"1022095793379":1478686417274,"1025508515931":1509788624343,"1024920274763":1509788624488,"1024920274755":1509788624487,"1021914254218":1509788625009,"1024920274782":1509788624487,"1024920274783":1509788624487,"1024920274777":1509788624488,"1024920274779":1509788624488,"1024920274774":1509788624488,"1021914254208":1509788625009,"1024920274768":1509788624488,"1024920274771":1509788624488,"1024920274732":1509788624255,"1024920274734":1509788624255,"1024540569165":1509788667549,"1024920274728":1509788624256,"1024920274729":1509788624255,"1024920274731":1509788624255,"1024920274726":1509788624255,"1024920274720":1509788624255,"1009003137150":1478686804023,"1017091730011":1465470268246,"1025715614812":1509788624832,"1013100971188":1478686804066,"1025715614813":1509788624822,"1019042637466":1509788625079,"1025715614811":1509788624828,"1021967603465":1478686417262,"1024920274703":1509788624255,"1024920274696":1509788624256,"1025715614816":1509788624616,"1024920274697":1509788624255,"1024920274698":1509788624255,"1024481190622":1509788667836,"1024920274694":1509788624255,"1024920274695":1509788624256,"1024451437329":1509788624328,"1024920274717":1509788624255,"1024920274718":1509788624255,"1024920274712":1509788624255,"1021967603487":1478686417149,"1024920274714":1509788624255,"1022082555332":1478686416981,"1024920274715":1509788624255,"1024920274708":1509788624255,"1021551197222":1478686417047,"1024920274709":1509788624255,"1022408452447":1478686417208,"1024920274711":1509788624255,"1024920274706":1509788624255,"1463464645":1491634246509,"1021615291374":1478686417116,"1025192645850":1509788667497,"1025192645851":1509788667497,"1018706970955":1509788624321,"1025192645852":1509788667497,"1025192645853":1509788667497,"1025192645854":1509788667497,"1025192645855":1509788667497,"1023502887800":1509788624943,"1021936539345":1509788624464,"1022009414263":1509788625075,"1025270239279":1509788624532,"1008054850063":1480585069062,"1021832466227":1478686416978,"1022337150670":1478686417015,"1023995186202":1491634246532,"1025192645856":1509788667497,"1025192645857":1509788667497,"1008054850072":1480585069062,"1020985627052":1478686804039,"1008054850071":1480585069062,"1021823422401":1478686417133,"1022276592323":1478686417197,"1012260686303":1478686417025,"1356641940":1491634246508,"1023129866733":1490882721866,"1022551323245":1509788624610,"1022337150642":1478686417015,"1008877699952":1478686804025,"1019489728744":1509788624301,"1008877699964":1478686804025,"1008877699963":1478686804025,"1025879457184":1509788667517,"1022551323205":1509788624610,"1009965908011":1491634246523,"715705538":1478686417020,"1022484739667":1478943089488,"1022224558027":1478686417013,"1022321025416":1478686417200,"1021269913332":1478686804033,"1024245407581":1509788624948,"1020805270231":1478686417225,"1022323253599":1478686417200,"1025796354116":1509788624274,"1000476120956":1478686417017,"1025270239405":1509788624532,"1020998475314":1478686417088,"1017403017147":1478686804020,"1008877699980":1478686804025,"1024575433526":1509788667903,"1024966410905":1509788624194,"1008877699995":1478686804025,"1022202406482":1478686417280,"1008877699993":1478686804025,"1022472156743":1478943089486,"1000476120876":1478686417017,"1529003498":1444487341699,"1021786587423":1509788624997,"1012311675992":1478686804062,"1012311675995":1478686804062,"1012311675997":1478686804062,"1025023954450":1509788624973,"1021294817224":1478686416985,"1012311675998":1478686804062,"1024780304273":1509788624511,"1018468812623":1478686804031,"1529003513":1444487341707,"1021914253520":1509788624427,"1021354322806":1465470268230,"1012311676001":1478686804062,"1012311676000":1478686804062,"1012311676002":1478686804062,"1012311676005":1478686804062,"1024901662460":1509788625016,"1012311676004":1478686804062,"1021561814988":1509788624821,"1018938186597":1509788624317,"1025270239538":1509788624532,"1020857829410":1478686416999,"1020857829409":1478686416999,"1020857829415":1478686416999,"1020943684357":1478686417000,"1020857829412":1478686416999,"1019932483395":1509788624922,"1021341870922":1478686417103,"1561508402":1478686417024,"1021322472540":1478686417102,"1023145467892":1509788624242,"1022073642904":1478686416988,"1023145467888":1509788624242,"1023145467900":1509788624242,"1023145467898":1509788624242,"1022359563936":1478686417203,"1020167741793":1509788625077,"1010331999141":1478686804052,"1023145467886":1509788624242,"1023145467883":1509788624242,"1021522096347":1478686417047,"1000527893431":1444487341713,"1022202275757":1480585069084,"1020886668856":1509788624177,"1022148483941":1478686417185,"1024763526914":1509788625219,"1014249734747":1478686804048,"1022112570638":1509788624944,"1021295734360":1478686417004,"1019482258014":1509788624315,"1014742820050":1480585069062,"1022018065033":1478686417160,"1023129866433":1490882721866,"1022804673633":1509788624511,"1022018065024":1478686417160,"1020774075745":1478686416997,"1022008759290":1509788624441,"1025569074994":1509788624344,"1022611881974":1509788624388,"1022611881975":1509788624388,"1024186552796":1509788625071,"1020615476985":1509788624353,"4560316589":1465469681389,"1024303995438":1509788624972,"1023605388491":1509788625144,"1009848482007":1491634246513,"1022018065020":1478686417160,"1023565805070":1491634246523,"1020087527102":1509788625078,"1021747790763":1478686804066,"1025270239645":1509788624532,"1022190688269":1478686417188,"1022121483370":1478686417276,"1022202275673":1480585069084,"1021021150927":1478686417090,"1021021150926":1478686417090,"1021021150925":1478686417090,"1003237831302":1480585069064,"529856583":1478950494910,"1021845048719":1478686417009,"1021928933516":1478686417142,"1023866340415":1509788624931,"1021125220544":1478686417095,"1022138391353":1478686417184,"1023752190827":1509788624926,"1021287476861":1478686417040,"1021946632153":1478686417055,"1025909472231":1509788667406,"1024966411224":1509788624533,"1022202275605":1480585069084,"1019186555729":1509788624315,"1019496150617":1478686804066,"1019496150616":1478686804066,"1309451790":1491634246534,"1023702512000":1509788625008,"1019496150618":1478686804066,"1019529168968":1509788624315,"1020626225911":1478686804028,"1019767588355":1509788624317,"944820319":1491634246515,"1008869313970":1509788624276,"944820298":1491634246515,"1023888755828":1491634246517,"1020825453824":1478686417078,"1019300199414":1478686804018,"1021581734900":1509788624397,"1026225080123":1514456869772,"1023767000500":1509788667834,"1022076653686":1509788624417,"1023097757102":1509788624496,"1023097757098":1509788624496,"1023097757095":1509788624496,"1023097757093":1509788624496,"1019314617123":1509788624376,"1023097757091":1509788624496,"1020984713138":1478686417088,"1023097757117":1509788624496,"1022485788735":1478943089489,"1021112113106":1478686417002,"1023097757108":1509788624496,"1025796357864":1509788624274,"1022712673983":1509788624538,"1025627530372":1509788624832,"1023097757135":1509788624496,"1023097757132":1509788624496,"1025627530374":1509788624823,"1023097757129":1509788624496,"1025627530371":1509788624828,"1022485788736":1478943089489,"1023097757125":1509788624496,"1025627530378":1509788624746,"1256891066":1444487341706,"1023097757150":1509788624496,"1023097757148":1509788624496,"1023097757139":1509788624496,"944820238":1491634246515,"1022608601225":1509788624994,"1020862683300":1509788624998,"261285873":1444487341733,"1322690226":1444487341735,"1020862683299":1509788624998,"766428617":1491634246507,"1023097757161":1509788624496,"1023097757155":1509788624496,"1023097757152":1509788624496,"1021502176965":1509788624983,"1019529168955":1509788624313,"1019298757276":1509788625079,"1021789474574":1509788624394,"1022517902004":1509788625064,"1021099267617":1478686417036,"160882969":1444487341762,"1001249634118":1444487341749,"1025634608362":1509788624359,"1025634608364":1509788624359,"1025634608365":1509788624359,"1025634608366":1509788624359,"1025634608352":1509788624359,"1025634608353":1509788624359,"1025634608354":1509788624359,"1022401897364":1509788624389,"1022081634467":1478686417062,"1009851758484":1491634246520,"1021051163424":1478686417036,"1010827833929":1478686804064,"1009965256388":1491634246523,"1021809656006":1509788624896,"1021809656001":1509788624896,"1021660379105":1478686416974,"1021786591083":1509788624997,"1019638746980":1478686804028,"1021809656010":1509788624896,"1021729573881":1509788624218,"1021809655991":1509788624895,"1021729573880":1509788624218,"1021788426106":1509788624403,"1021809655990":1509788624896,"1021809655989":1509788624896,"1021809655988":1509788624896,"1021809655987":1509788624896,"1021809655986":1509788624896,"1021809655985":1509788624895,"1025634608304":1509788624359,"1021809655999":1509788624896,"1021809655998":1509788624896,"1022180857501":1478686417063,"1025634608306":1509788624359,"1021809655997":1509788624896,"1025634608307":1509788624359,"1021809655996":1509788624896,"1025634608308":1509788624359,"1021809655995":1509788624896,"1021809655994":1509788624895,"1021729573879":1509788624218,"1021809655993":1509788624895,"1021729573878":1509788624218,"1021809655992":1509788624896,"1019314617307":1509788624376,"1019314617306":1509788624376,"1024785412558":1509788625198,"1021885678894":1478686417257,"1021885678891":1478686417137,"1023173906922":1509788624996,"1021885678898":1478686417137,"1022453540586":1478686804072,"108195698":1444487341726,"1022747527529":1509788624394,"1022071411158":1478686417176,"1022071411168":1478686417176,"1022192522938":1478686416984,"1022191474424":1478686416989,"1020615477450":1509788624353,"1021908617016":1509788625166,"1020936084793":1478686417083,"1001517532847":1444487341755,"1019932479793":1509788624922,"1024334009997":1509788625071,"923852388":1478950494918,"1022998398701":1509788624362,"1021428775051":1478686417007,"490140852":1444487341729,"1022442006310":1478686416984,"1021137922533":1465470268307,"1021653562883":1509788624396,"1021259034246":1465470268198,"1021137922526":1465470268306,"1024862615509":1509788624948,"1023946559151":1491634246529,"1021873489220":1478686417136,"1008144896823":1465470268318,"1021873489222":1478686417136,"1021708995495":1478686417122,"1021708995502":1478686417122,"1021708995500":1478686417122,"1020825453820":1478686417078,"123662013":1444487341737,"1022064467650":1478686417012,"1022850551718":1509788625053,"1021087863938":1478686417002,"123661986":1444487341735,"1022349730349":1478686417069,"1018498828730":1478686804066,"1021832200964":1509788624220,"1024920275148":1509788624489,"1021259296000":1465470268198,"1021156141930":1478686416975,"1024920275149":1509788624489,"1024920275150":1509788624489,"1024920275140":1509788624489,"1024106863424":1509788667472,"1024223253168":1509788667496,"1024920275143":1509788624489,"1024920275136":1509788624489,"1024920275137":1509788624489,"1024920275138":1509788624489,"1022466516252":1478686417299,"1024223253165":1509788667496,"1024223253153":1509788667496,"1022998398368":1509788624362,"1024223253157":1509788667496,"1022105620717":1478686417275,"1022047558753":1478686417171,"1025017793913":1509788624908,"1020841051259":1478686417031,"1021997619561":1478686417011,"1024920275133":1509788624489,"1020555196266":1478686416995,"1024920275128":1509788624489,"1024920275130":1509788624489,"1021267550973":1478686417040,"1024920275120":1509788624489,"1025625433732":1509788624871,"1020935036656":1478686417000,"1025625433731":1509788624843,"1021610178266":1478686417008,"1025569465048":1509788624351,"1022485658249":1480585069127,"235332738":1491634246512,"1024920275049":1509788624488,"1024920275046":1509788624489,"1022394425616":1509788624957,"1024920275047":1509788624488,"1024920275040":1509788624489,"1025569465047":1509788624352,"1024920275042":1509788624488,"1022917918920":1509788624825,"1022425622321":1478686417070,"1021610178255":1478686417008,"1022700746693":1509788624973,"1021747793561":1478686804066,"1021316047196":1478686416972,"1024920275021":1509788624488,"1024920275022":1509788624488,"1024920275023":1509788624488,"1024920275017":1509788624489,"1024132290882":1509788624327,"1024920275018":1509788624488,"1021852385644":1478686417135,"1024920275019":1509788624488,"1024920275013":1509788624488,"1024920275014":1509788624489,"1023316764720":1509788624301,"1024920275036":1509788624488,"1024920275032":1509788624488,"1024920275033":1509788624488,"1020830696474":1478686417226,"1024920275028":1509788624488,"1012311676971":1478686804062,"1024920275030":1509788624488,"1024920275031":1509788624488,"1012311676973":1478686804062,"1012311676972":1478686804062,"1024920275025":1509788624488,"1012311676975":1478686804062,"1024920275026":1509788624488,"1020661091958":1478686417075,"1024920275027":1509788624488,"1024920274988":1509788625211,"1024920274985":1509788625212,"1024920274987":1509788625211,"1024920274982":1509788625211,"1024920274976":1509788625212,"1024920274978":1509788625212,"1022046903452":1478686417269,"1019917147630":1509788624361,"1019496150152":1478686804066,"1019314616797":1509788624376,"1020934643326":1478686417000,"1024920274959":1509788625212,"1022226525048":1478686417192,"1024920274954":1509788625212,"1023730692380":1509788624960,"1024920274948":1509788625212,"1024920274944":1509788625212,"1024920274972":1509788625212,"1024920274973":1509788625211,"1024920274975":1509788625211,"1024920274968":1509788625211,"1024920274969":1509788625211,"1022021082927":1509788625066,"1024920274971":1509788625211,"1024920274966":1509788625211,"1024920274967":1509788625211,"1023821777560":1491634246536,"1000309787915":1478686417018,"1024920274963":1509788625212,"1021606508443":1509788624815,"1018889163107":1509788625018,"1022252345627":1509788624175,"1022463501430":1478686417072,"1020615477901":1509788624353,"1018889163109":1509788624366,"1025767128989":1509788625166,"1024459828589":1509788625030,"1021046837466":1478686417036,"1023145333756":1509788624475,"1022780950972":1509788624816,"1025288985661":1509788624286,"1008037025893":1478686804025,"148562843":1444487341705,"1016956726524":1478686804016,"1021948861250":1478686417145,"444658121":1478950494910,"1021948861249":1478686417145,"1012471453607":1478686417223,"1022100247119":1478686417277,"1023978668632":1509788624392,"1021747793758":1478686804066,"1022594186473":1480585069076,"1023978668631":1509788624392,"1025090799517":1509788624959,"1021490511390":1478686417110,"1023391477094":1509788625079,"1021586714831":1478686417114,"1022349206445":1478686417202,"1022046248412":1478686804047,"1023097757195":1509788624496,"1023097757190":1509788624496,"1022292979212":1478686417068,"1023097757187":1509788624496,"1023850088795":1509788624972,"1020776562788":1478686416992,"1024430862263":1509788667890,"4914597759":1509788624164,"1025589387930":1509788624569,"1025593975127":1509788624998,"1025593975134":1509788624997,"1019560888800":1509788624316,"1025593975130":1509788625084,"1021726034129":1478686416972,"1021726034133":1478686416972,"1025593975138":1509788624426,"1023145333617":1509788624475,"1023924801001":1509788624325,"1023145333608":1509788624475,"1023145333609":1509788624475,"1023145333611":1509788624475,"1023145333612":1509788624475,"1022088057450":1478686417179,"1023145333613":1509788624475,"1022088057449":1478686417179,"1023145333615":1509788624475,"1022088057447":1478686417179,"1021770337554":1478686417254,"1021594448114":1509788624397,"1720356182":1478686804033,"1020294096247":1465470268289,"1021211455487":1478686804033,"1022222592569":1478686417192,"1021832200957":1509788624220,"1021832200955":1509788624220,"1020057119521":1465470268276,"1021832200948":1509788624220,"1015591509754":1478686804016,"1020057119536":1465470268277,"1025593975101":1509788624998,"1025593975098":1509788625007,"1024690518207":1509788624891,"1024690518205":1509788624891,"1024690518202":1509788624890,"1025006914501":1509788624332,"1024690518198":1509788624890,"1024690518196":1509788624891,"1024690518197":1509788624890,"1021886988759":1478686804027,"1024690518195":1509788624891,"1024690518192":1509788624891,"1025270241855":1509788624269,"1022192128923":1478686417064,"1022072460473":1478686417271,"1024690518190":1509788624891,"1024690518189":1509788624891,"1022016493584":1509788625076,"1024690518186":1509788624890,"1025767127173":1509788624549,"1024690518181":1509788624891,"1024690518177":1509788624891,"1023612336323":1509788624953,"1024690518172":1509788624891,"1023612336321":1509788624953,"158393684":1444487341703,"1024690518170":1509788624891,"1023612336327":1509788624953,"1023612336324":1509788624953,"1023612336325":1509788624953,"1023612336330":1509788624953,"1022271482087":1478686417285,"1023612336334":1509788624953,"1024690518163":1509788624891,"1023612336335":1509788624953,"1020526358751":1465470268323,"1025767127202":1509788624549,"1024690518158":1509788624890,"1023612336339":1509788624953,"1023612336336":1509788624953,"1023431976337":1509788624521,"1009999332473":1491634246516,"1000090908366":1478686417021,"1024936005163":1509788625006,"1023612336346":1509788624953,"1023612336347":1509788624953,"1023612336349":1509788624953,"1023211131020":1509788624578,"1023211131016":1509788624578,"1023211131013":1509788624578,"1019105422284":1478686804027,"1025801599528":1509788624304,"1023502885156":1509788624943,"1023211131009":1509788624578,"1024690518257":1509788624587,"1024690518254":1509788624587,"1024690518255":1509788624587,"1023211131038":1509788624578,"1023211131032":1509788624578,"1024690518251":1509788624587,"1024690518248":1509788624587,"1024690518249":1509788624587,"1024690518246":1509788624587,"1024690518247":1509788624587,"1024690518244":1509788624587,"1023211131024":1509788624578,"1024690518242":1509788624587,"1024690518243":1509788624587,"1024690518240":1509788624587,"1024690518241":1509788624587,"1021496932730":1478686417112,"1024690518237":1509788624587,"1023612336257":1509788624953,"1024690518235":1509788624587,"1023612336263":1509788624953,"1023612336260":1509788624953,"1023211131051":1509788624578,"1024690518233":1509788624587,"1023612336261":1509788624953,"1023612336266":1509788624953,"1023211131045":1509788624578,"1024690518231":1509788624587,"1023211131040":1509788624578,"1023612336270":1509788624953,"1022229015832":1509788624939,"1023612336268":1509788624953,"1025767127272":1509788624211,"1023211131057":1509788624578,"1024690518208":1509788624891,"1021942832153":1509788625019,"756072815":1444487341729,"1015640265843":1465470268264,"1000090908284":1478686417021,"1023211130953":1509788624578,"1023211130948":1509788624578,"1025009142575":1509788624178,"1023612336243":1509788624953,"1023211130974":1509788624578,"1023612336246":1509788624953,"1023211130969":1509788624578,"1023612336245":1509788624953,"1023211130964":1509788624578,"1023612336250":1509788624953,"1023612336251":1509788624953,"1021289178595":1478686417040,"1020805791922":1478686416998,"1010057396331":1491634246534,"1023612336255":1509788624953,"1023211130988":1509788624578,"1019932480763":1509788624922,"1021517118309":1478686417047,"1023211130991":1509788624578,"1021859596253":1478686417135,"1023211130984":1509788624578,"1021859596254":1478686417135,"1023211130980":1509788624578,"1001517531992":1444487341751,"1023211130976":1509788624578,"1022551324816":1509788625236,"1023211131005":1509788624578,"1008833269631":1480585069066,"1022112569084":1509788624943,"1023211130999":1509788624578,"341899484":1444487341751,"1023211130994":1509788624578,"1000090908219":1478686417021,"1022229015989":1509788624939,"1015589411312":1478686804065,"1025533553339":1509788625083,"1023612336164":1509788624953,"1025068910327":1509788624295,"1023612336170":1509788624953,"1023612336171":1509788624953,"1023612336168":1509788624953,"1021632721454":1509788624818,"1022551324909":1509788625236,"1023612336172":1509788624953,"1019932480651":1509788624922,"1021501258252":1478686417112,"1024153000008":1509788667495,"1023612336134":1509788624953,"1023612336138":1509788624953,"1023612336139":1509788624953,"1023612336136":1509788624953,"1023612336142":1509788624953,"1020294095449":1465470268289,"1023612336144":1509788624953,"1023612336150":1509788624953,"1022882268304":1509788624553,"1025270241996":1509788624269,"1021048936274":1478686417093,"1023612336156":1509788624953,"1025270242097":1509788624269,"1018513639882":1509788625229,"1024254187428":1509788624948,"1018513639885":1509788625229,"1018513639887":1509788625229,"1018513639873":1509788625229,"1018513639874":1509788625229,"1019496149847":1478686804066,"1018513639878":1509788625229,"1018513639898":1509788625229,"1023612336631":1509788624951,"1018513639900":1509788625229,"1018513639902":1509788625229,"1018513639888":1509788625229,"1023612336632":1509788624951,"1018513639891":1509788625229,"1023612336633":1509788624951,"1018513639893":1509788625229,"1023612336639":1509788624951,"309002059":1491634246533,"1023612336579":1509788624951,"1018513639912":1509788625229,"1021616337115":1478686417117,"1023612336577":1509788624951,"1023612336582":1509788624951,"1022434402333":1478686417212,"1022340556278":1480585069071,"1023612336580":1509788624951,"1018513639918":1509788625229,"1023612336586":1509788624951,"1018513639905":1509788625229,"1021507287891":1478686417244,"1019932480880":1509788624922,"1021826303065":1509788624403,"1022483561732":1478943089531,"1023612336589":1509788624951,"1023612336595":1509788624951,"1023612336592":1509788624951,"1022631801927":1509788624439,"1022483561744":1478943089532,"1021594580582":1478686417115,"1021153913898":1478686417300,"1025679827685":1509788624351,"1023612336556":1509788624951,"1016092458600":1509788624941,"1023612336561":1509788624951,"1021750806689":1509788624507,"1023612336566":1509788624951,"1021750806688":1509788624507,"1021750806691":1509788624507,"1023612336564":1509788624951,"1021750806690":1509788624507,"1023612336570":1509788624951,"1016092458598":1509788624941,"1016092458599":1509788624941,"179759063":1444487341754,"1022631801886":1509788624429,"1022046247733":1478686804047,"179759064":1444487341752,"1021803496895":1509788624403,"1021060601448":1478686417002,"1018513639870":1509788625229,"1022429159444":1478686417294,"1024132292198":1509788624327,"1025466576895":1509788624361,"1023612336481":1509788624951,"1018404204784":1509788625019,"1025508255850":1509788624340,"1011676897729":1478686804049,"1022032222370":1478686417166,"1021624070388":1509788625081,"1025466576872":1509788624361,"1025466576873":1509788624361,"1025466576871":1509788624361,"1019330738581":1509788624316,"1023612336450":1509788624951,"1023087663499":1509788624185,"1023087663500":1509788624185,"1022001944922":1509788624463,"1022008760636":1509788624868,"1023612336459":1509788624951,"1021677407742":1478686417050,"1021303727924":1478686417102,"1023087663491":1509788624185,"1023612336457":1509788624951,"341899724":1444487341753,"1023087663492":1509788624185,"1023612336462":1509788624951,"1023612336460":1509788624951,"1023087663495":1509788624185,"1023612336466":1509788624951,"1020890340503":1509788624986,"1025767127332":1509788624211,"1021677407727":1478686417050,"1023612336476":1509788624951,"226680893":1478686417024,"1023612336477":1509788624951,"1012128565944":1478686417073,"706136026":1478686804019,"1022974149437":1490882721866,"1000090908461":1478686417021,"1025767127367":1509788624211,"1023612336437":1509788624951,"1023612336443":1509788624951,"1012126599746":1478686417299,"1023612336447":1509788624951,"1021886595074":1478686417258,"1023612336445":1509788624951,"1022364279972":1478686417069,"1024010127049":1509788667538,"1022200255209":1478686417190,"1023567510633":1509788624304,"1021349339183":1478686416974,"1020615478379":1509788624353,"1022200255224":1478686417190,"1022476221762":1478943089315,"1018498829908":1478686804066,"1021006337448":1478686417231,"1022042970215":1478686417269,"1021757754213":1509788624993,"1024781350725":1509788625149,"1022057912734":1478686417059,"1024781350721":1509788625149,"1024781350722":1509788625149,"1022057912732":1478686417059,"1024781350723":1509788625149,"1025441411044":1509788624407,"1022320241146":1478686417200,"1016284606904":1480585069064,"1025441411040":1509788624428,"1025441411041":1509788624431,"1025441411042":1509788624425,"1022057912747":1478686417059,"1022057912749":1478686417059,"1025017792788":1509788624497,"341899853":1444487341751,"1022057912740":1478686417059,"1024726169777":1509788624342,"1022042970206":1478686417269,"1020754544495":1478686417076,"1020805268076":1478686416997,"1012402510144":1478686417026,"1021269911249":1478686804047,"1024018776827":1509788667493,"1024018776828":1509788667493,"1024018776831":1509788667493,"1021638488275":1478686417119,"1022455636396":1478686417216,"1021680553565":1478686804028,"1024018776823":1509788667493,"1020698052822":1509788625018,"1022295862034":1478686417068,"1022191210974":1478686417064,"1024781350719":1509788625149,"1020698052825":1509788625017,"341899789":1444487341755,"1020984449514":1478686417034,"1019575700973":1509788624315,"1021283542951":1478686417040,"1024686586511":1509788625083,"1022241598664":1509788624920,"1024781350869":1509788624218,"1021500995675":1478686804040,"1024781350870":1509788624218,"1024781350871":1509788624218,"1021747792514":1478686804066,"1021116174629":1478686417233,"1024781350872":1509788624218,"1021922640181":1478686417259,"1024781350874":1509788624218,"1021886595915":1478686417258,"1210230453":1444487341716,"1023730824558":1509788624960,"1022249200769":1509788624300,"1024132291933":1509788624327,"1021894460412":1509788624423,"1011676898037":1478686804049,"1021034386484":1478686417091,"1024434006824":1509788624447,"1020862684677":1509788625016,"1023926896867":1491634246528,"1025628054040":1509788624823,"1023612336678":1509788624951,"1025628054042":1509788624746,"1025628054036":1509788624828,"1025628054037":1509788624832,"1025074152713":1509788625007,"1024434006820":1509788624447,"1024434006821":1509788624447,"1024434006822":1509788624447,"1024434006823":1509788624447,"1022255754511":1478686417284,"1024840200967":1509788625016,"1023730693422":1509788624961,"245162051":1444487341747,"1021741763260":1509788624395,"1023612336643":1509788624951,"209642138":1444487341739,"1023612336646":1509788624951,"1023612336650":1509788624951,"1024567173876":1509788624408,"1024567173877":1509788624408,"1023612336655":1509788624951,"1024567173878":1509788624408,"1024567173879":1509788624408,"1023612336653":1509788624951,"1019960136768":1509788624518,"1023612336662":1509788624951,"1023612336661":1509788624951,"1013467322699":1478686804071,"1023612336670":1509788624951,"1021729573945":1509788624555,"1021729573944":1509788624555,"1021729573946":1509788624555,"1022313294196":1478686417287,"1024576873064":1509788624465,"1021729573943":1509788624555,"1020662139848":1478686804050,"1019396798260":1509788624316,"1021729573928":1509788624851,"1021729573930":1509788624851,"1021729573927":1509788624851,"1021729573926":1509788624851,"1004790750712":1480585069067,"1016655927980":1480585069075,"1000090908119":1478686417021,"1025270241538":1509788624269,"1870168139":1478686417021,"1025430059":1444487341724,"1022082029326":1478686417012,"1020924025866":1478686417033,"4551270526":1465469681388,"1025745894633":1509788625020,"1020948404970":1478686417085,"1022034319957":1478686417167,"1022701662816":1509788625059,"1018669744851":1509788625017,"1020662926304":1478686804034,"1022229016121":1509788624939,"1024535848096":1509788667463,"1025270241642":1509788624269,"892000881":1478686804029,"1022280133398":1478686417014,"1020937526035":1478686417033,"1025188715908":1509788624225,"1025188715904":1509788624225,"1025188715905":1509788624225,"1025188715906":1509788624225,"1025188715907":1509788624225,"1020662926303":1478686804032,"1002456909962":1491634246520,"1021384204368":1478686417042,"1021854221354":1478686417135,"1014669561952":1478686804016,"1022148481965":1478686417185,"1022068397945":1509788624944,"1014669561979":1478686804032,"1022812539671":1509788625074,"1022068397943":1509788624944,"1014669561974":1478686804028,"1014669561975":1478686804028,"1021802841920":1478686804065,"4818399378":1509788624163,"1021356679890":1478686417239,"1025406947407":1509788624423,"1021390364891":1478686417105,"1023243243871":1509788624367,"1003127595071":1478686804054,"1017239451407":1465470268268,"1024781350534":1509788624555,"1024781350535":1509788624555,"1024781350531":1509788624555,"1001517531176":1444487341752,"1024781350536":1509788624555,"1024781350539":1509788624555,"1025270241744":1509788624269,"1022424834638":1478686417293,"1021009352686":1478686417089,"1021693791930":1480585069064,"1021009352685":1478686417089,"1016676899254":1480585069076,"1016676899255":1480585069076,"1025784298142":1509788624348,"1025784298143":1509788624349,"1021680553982":1478686804028,"1015591246567":1478686804018,"1021603622079":1478686417048,"1021603622078":1478686417048,"1025715216779":1509788624909,"888194291":1444487341744,"1022076782688":1478686417177,"1025715216774":1509788624910,"1025715216794":1509788624910,"1025715216792":1509788624910,"1025715216799":1509788624910,"1025902652520":1509788667460,"1025902652517":1509788667460,"1025902652515":1509788667464,"1025902652512":1509788667460,"1025715216789":1509788624910,"1025715216810":1509788624910,"1025902652510":1509788667464,"1025715216808":1509788624910,"1025902652508":1509788667459,"1025715216813":1509788624910,"1025017796373":1509788624595,"1025715216805":1509788624910,"1025715216827":1509788624910,"1013059956685":1478686804052,"1025715216824":1509788624910,"1013059956684":1478686804052,"1025715216825":1509788624909,"1022086351297":1478686417273,"1022898002338":1509788624439,"1013059956682":1478686804052,"1013059956681":1478686804052,"1025715216819":1509788624910,"1025715216817":1509788624910,"1025715216823":1509788624910,"1025715216820":1509788624910,"1019932477541":1509788624922,"1025715216821":1509788624910,"1023251369561":1509788625083,"1019486056122":1478686804047,"1025715216863":1509788624848,"1021467960455":1478686417108,"1025715216861":1509788624835,"1025715216851":1509788624916,"1025715216849":1509788624916,"1025715216874":1509788624834,"1025715216878":1509788624834,"1025715216877":1509788624834,"1025715216868":1509788624824,"1021923041217":1478686417054,"1025715216894":1509788624868,"1021923041220":1478686417054,"1020870541365":1478686417031,"1025715216886":1509788624834,"1025023957155":1509788624973,"1021603622080":1478686417048,"1022190948153":1478686417279,"1025715216650":1509788624543,"1022190948152":1478686417279,"1022190948155":1478686417279,"1022190948154":1478686417279,"1021786855257":1478686417128,"1022190948147":1478686417279,"1022190948146":1478686417279,"1022190948149":1478686417279,"1025715216646":1509788624543,"1021786855262":1478686417128,"1022190948148":1478686417279,"1022190948151":1478686417279,"1022190948150":1478686417279,"1025715216645":1509788624543,"1021896695218":1478686417258,"1021709390552":1509788624918,"1008704432906":1444487341761,"1025715216656":1509788624566,"1022245663459":1478686417195,"1022245663460":1478686417195,"1019932477639":1509788624922,"231144795":1514795417100,"1025715216660":1509788624548,"1022400986007":1478686417292,"1019917141893":1509788624361,"1025715216685":1509788624548,"1021088386522":1478686417036,"1025715216698":1509788624538,"1012179819204":1478686417073,"1020294102554":1465470268289,"1021786855264":1478686417128,"1016866156970":1478686804034,"1025715216690":1509788624544,"1025507865862":1509788624343,"1025715216745":1509788624910,"1025715216750":1509788624910,"1022044800662":1478686417171,"1022551319752":1509788624912,"1013131383636":1444487341758,"1020160538186":1509788625081,"1025507865868":1509788624337,"1025507865867":1509788624337,"1025507865864":1509788624336,"1025715216740":1509788624909,"1025507865865":1509788624342,"1025715216741":1509788624910,"1025715216760":1509788624910,"1025715216765":1509788624910,"1020444043044":1478686804027,"1025715216522":1509788624607,"1025715216520":1509788624607,"1023211130318":1509788625190,"1025715216521":1509788624607,"1023211130319":1509788625190,"1025715216524":1509788624607,"1023211130315":1509788625191,"1023211130311":1509788625191,"1025715216518":1509788624607,"1025715216516":1509788624606,"1025715216539":1509788624607,"1023211130333":1509788625190,"1023211130335":1509788625190,"1025715216542":1509788624607,"1023211130331":1509788625190,"1023211130325":1509788625190,"1023211130326":1509788625190,"1025715216529":1509788624607,"1023211130327":1509788625190,"1022457347782":1478686417217,"1052299172":1478686804033,"1023211130320":1509788625190,"1025715216535":1509788624607,"1023211130322":1509788625190,"1025715216554":1509788624607,"1024794061747":1509788624989,"1022551319810":1509788624912,"1023211130350":1509788625191,"1025715216558":1509788624607,"1023211130344":1509788625191,"1023211130345":1509788625190,"1023211130347":1509788625191,"1022391286402":1478686417206,"1022240945033":1478686417194,"1023211130342":1509788625190,"1025715216545":1509788624607,"1023211130343":1509788625191,"1025715216551":1509788624607,"1025883777712":1509788667451,"1025715216549":1509788624607,"1023211130339":1509788625191,"1022240945040":1478686417194,"1025715216570":1509788624607,"231144695":1444487341698,"1025715216575":1509788624607,"1025715216573":1509788624607,"1025715216563":1509788624607,"1021666398657":1509788624421,"1025715216565":1509788624607,"1025715216584":1509788624607,"1025715216585":1509788624607,"1023211130249":1509788624476,"1023211130250":1509788624476,"1022099589192":1478686417063,"1025715216578":1509788624607,"1023211130245":1509788624476,"1023211130246":1509788624475,"1023211130240":1509788624476,"1025715216582":1509788624607,"1023211130241":1509788624476,"1022245663542":1478686417195,"1023211130242":1509788624475,"1023211130243":1509788624476,"1025781015791":1509788624299,"1024938234542":1509788624548,"1025715216606":1509788624612,"1025715216607":1509788624612,"1023211130285":1509788625191,"1022745170385":1509788624989,"1023211130280":1509788625190,"1022417501535":1478686417070,"1023561343104":1509788624417,"1025715216615":1509788624544,"1023220829495":1509788624825,"1019724864971":1509788624315,"1025715216635":1509788624543,"1023211130302":1509788625191,"1023211130296":1509788625191,"1021959471122":1478686417010,"1023211130288":1509788625191,"1025715216631":1509788624543,"1025715216628":1509788624538,"1022608599390":1509788624994,"1023211130205":1509788624475,"1020834504452":1478686804031,"1024106856700":1509788667889,"1023946430095":1491634246531,"1016549891683":1509788624944,"1021965500561":1478686417262,"1012432652482":1478686417074,"1016549891694":1509788624944,"1016549891689":1509788624944,"1023241145500":1509788624462,"1021745304968":1478686417051,"1022394825270":1478686417291,"1019932477944":1509788624922,"1024332435379":1509788624434,"1023211130219":1509788624476,"1023211130213":1509788624476,"1023211130214":1509788624476,"1023211130215":1509788624476,"1023211130208":1509788624476,"1023211130210":1509788624476,"1025017796243":1509788625226,"1023211130236":1509788624475,"1023211130237":1509788624475,"1023211130239":1509788624476,"1024134120059":1509788667503,"1023211130232":1509788624475,"1023211130233":1509788624475,"1023211130234":1509788624475,"1020783778337":1478686804065,"1023211130230":1509788624475,"1019922385229":1509788624354,"1023211130224":1509788624475,"1020090676087":1509788624361,"1023211130227":1509788624475,"1021780826079":1509788624403,"1022261392057":1478686417197,"1022191603306":1478686417188,"1020605780457":1478686417075,"1020796099843":1478686417077,"1023122655188":1509788625046,"1021272144273":1509788624433,"1023132485231":1509788625111,"1019873100853":1478686804032,"1021663260408":1478686417248,"1021272144266":1509788624433,"1025715217291":1509788625240,"1025715217288":1509788625240,"1021764310798":1478686417009,"1025715217295":1509788625240,"1025505113655":1509788624344,"1025505113656":1509788624341,"1025715217282":1509788625241,"1012116902972":1478686416993,"1025505113657":1509788624337,"1022848324709":1509788624393,"1025505113658":1509788624342,"1025715217280":1509788625240,"1025505113659":1509788624338,"1025505113660":1509788624336,"1022453414939":1478686417215,"1025715217306":1509788625240,"1025715217311":1509788625240,"1025715217301":1509788625240,"1009270001639":1509788624386,"1019036610970":1478686804029,"1025466576980":1509788624361,"1025715217314":1509788625240,"1025715217316":1509788625240,"1025715217340":1509788625128,"1025715217332":1509788625245,"1025715217333":1509788625244,"1021961437963":1509788625011,"1021961437962":1509788625011,"1021624069926":1509788625081,"1021961437961":1509788625011,"1021961437960":1509788625011,"1025466576952":1509788624361,"1021961437967":1509788625011,"1025466576953":1509788624361,"1025715217359":1509788625126,"1025466576954":1509788624361,"1025715217356":1509788625127,"1025715217357":1509788625126,"1021961437955":1509788625011,"1025715217346":1509788625142,"1021961437954":1509788625011,"1021961437952":1509788625011,"1022525628900":1480585069091,"1021961437959":1509788625011,"1768201002":1491634246533,"1023186487306":1509788624551,"1021961437957":1509788625011,"1021961437956":1509788625011,"1025715217370":1509788625136,"1021693793037":1480585069064,"1016549891494":1509788624944,"1025715217369":1509788625168,"1016549891488":1509788624944,"1016549891500":1509788624944,"1022248284169":1478686417196,"1018486116404":1480585069063,"1016549891501":1509788624944,"1021925530933":1478686417055,"1022248284170":1478686417196,"1011676904981":1478686804049,"1023776304998":1509788624920,"1022074030829":1509788625019,"1021925530930":1478686417055,"1021693530909":1478686804033,"1025715217364":1509788625126,"1021222991632":1478686417235,"1025715217365":1509788625126,"1025466576924":1509788624361,"1025466576925":1509788624361,"1025466576926":1509788624361,"1021638749412":1478686417119,"1022525628876":1480585069091,"1025466576921":1509788624361,"1025466576922":1509788624361,"1025466576923":1509788624361,"1022252085375":1478686417066,"1021967074168":1509788624983,"1025715217379":1509788625128,"1025715217376":1509788625135,"1025715217377":1509788625136,"1025715217381":1509788625110,"1021528778057":1478686417244,"1025466576900":1509788624361,"1025466576896":1509788624361,"1025466576897":1509788624361,"1025466576898":1509788624361,"1022525628887":1480585069091,"1025466576899":1509788624361,"1025715217162":1509788624265,"1021961962435":1509788624466,"1024434927486":1509788624435,"1025715217164":1509788624265,"1012179818749":1478686417073,"1024434927474":1509788624435,"1024434927475":1509788624435,"1024434927472":1509788624435,"1024434927478":1509788624435,"1019638748502":1478686804028,"1025715217157":1509788624265,"1025712726848":1509788624304,"1025459105886":1509788624351,"1025715217176":1509788624265,"1024434927464":1509788624452,"1022037853258":1478686417058,"1024434927470":1509788624435,"1025715217183":1509788624265,"1022941912685":1509788625018,"1725207618":1444487341737,"1025715217180":1509788624265,"1024434927458":1509788624452,"1012794801463":1478686417224,"1025715217169":1509788624265,"1024434927457":1509788624509,"1025715217175":1509788624265,"1024434927463":1509788624452,"1025715217172":1509788624265,"1024434927455":1509788624510,"1022436245428":1478686417295,"1021886078831":1509788624465,"1025459105888":1509788624350,"4984200122":1509788624165,"1025715217215":1509788625240,"1021603622406":1478686417008,"881247803":1509788625017,"1021654609167":1478686417050,"1023251369176":1509788625083,"1025412713842":1509788624456,"1025715217226":1509788625240,"1022075865681":1509788624190,"1025715217231":1509788625240,"1025715217218":1509788625241,"1953662651":1444487341707,"1025715217216":1509788625241,"1018051754684":1478686804031,"1025569471127":1509788624351,"1025715217223":1509788625240,"1025715217221":1509788625240,"1016399680536":1480585069069,"1024742810968":1509788624342,"1025715217236":1509788625240,"1025715217237":1509788625240,"1025715217257":1509788625240,"1022710705220":1509788624983,"1025715217248":1509788625240,"1003280165418":1478686804054,"1021624070024":1509788625081,"1025715217274":1509788625240,"1025715217264":1509788625240,"1024917263300":1509788624978,"1025715217268":1509788625240,"1019712542838":1478686804027,"1012209180595":1478686417073,"1022769943090":1509788624994,"1020922183766":1478686417228,"4984199685":1509788624164,"1021592086613":1478686417048,"1021718827206":1478686417051,"1422567382":1478686416993,"1020649296003":1478686417075,"1019596543810":1509788624942,"1025715217065":1509788624265,"1025715217071":1509788624265,"1022045848932":1478686417059,"1021592086631":1478686417048,"1023946560575":1491634246531,"1023450331552":1509788625082,"1023946560573":1491634246531,"1025715217063":1509788624265,"1025715217061":1509788624265,"1022052140242":1478686417270,"1025715217081":1509788624265,"1025715217086":1509788624265,"1016866157088":1478686804034,"1025715217098":1509788624265,"1023211130764":1509788624887,"1019208449569":1480585069068,"1021465470904":1478686417045,"1023211130760":1509788624887,"1025715217103":1509788624265,"1023211130761":1509788624887,"1023211130756":1509788624887,"1023211130757":1509788624887,"1020966487545":1478686417034,"1023211130752":1509788624887,"1025715217093":1509788624265,"1023211130755":1509788624887,"1023211130780":1509788624887,"1021778072836":1480585069064,"1023946560580":1491634246533,"1024655253898":1509788624345,"1023211130783":1509788624887,"1025715217118":1509788624265,"1023211130776":1509788624887,"1023211130773":1509788624887,"1023211130774":1509788624887,"1025715217110":1509788624265,"1023211130769":1509788624887,"1025715217131":1509788624265,"1025715217135":1509788624265,"1025715217145":1509788624265,"292479511":1444487341723,"1025715217141":1509788624265,"1023211130700":1509788624247,"1020783777816":1478686804040,"1021778073047":1480585069064,"1025715216905":1509788624843,"1023211130696":1509788624247,"1025715216910":1509788624821,"1024917263038":1509788624978,"1023211130697":1509788624247,"1021974544646":1509788624463,"1023211130698":1509788624247,"1023211130692":1509788624248,"1025715216898":1509788624843,"1023211130694":1509788624247,"1023211130695":1509788624248,"1021249598555":1478686804028,"1012226481667":1478686804028,"1023211130690":1509788624247,"1023211130716":1509788624887,"1021199791928":1465470268192,"1023211130714":1509788624887,"1023211130715":1509788624887,"1025715216914":1509788624825,"1023211130733":1509788624887,"1022674792294":1480585069068,"1025715216936":1509788624214,"1020180198452":1509788624321,"1020180198451":1509788624321,"1023211130728":1509788624887,"1021961437935":1509788625010,"1025715216943":1509788624198,"1020180198450":1509788624321,"1020180198449":1509788624321,"1022332040437":1478686417201,"1020180198448":1509788624321,"1025715216930":1509788624270,"1025715216931":1509788624270,"1023211130720":1509788624887,"1025715216932":1509788624205,"1025715216933":1509788624205,"1023211130723":1509788624887,"1025715216955":1509788624205,"1023211130749":1509788624887,"1021961437944":1509788625011,"836289132":1478950494916,"1021961437950":1509788625011,"1023211130746":1509788624887,"1018546541901":1480585069070,"1021961437937":1509788625012,"1023211130743":1509788624887,"1022332040431":1478686417201,"1023211130737":1509788624887,"1021961437942":1509788625011,"1025715216948":1509788624205,"1021568493928":1509788624401,"1021961437940":1509788625012,"1023211130639":1509788624247,"1025715216962":1509788624205,"1023211130653":1509788624248,"1021624069813":1509788625081,"1020783777866":1478686804065,"1012570534613":1478686417223,"1019079735000":1509788625076,"1023211130645":1509788624248,"1023211130668":1509788624247,"1482468286":1478950494923,"1023211130664":1509788624247,"1021991583866":1478686417265,"1025214660742":1509788625104,"1012128568476":1478686417073,"1025715216994":1509788624210,"1025715216995":1509788624211,"1023211130662":1509788624248,"1023211130663":1509788624248,"1025715216998":1509788624206,"1023211130659":1509788624248,"1023211130684":1509788624247,"1023211130686":1509788624247,"1023211130682":1509788624247,"1023211130676":1509788624247,"1021620399686":1509788624401,"1023211130678":1509788624247,"1025715217014":1509788624199,"1023211130672":1509788624247,"1023211130673":1509788624247,"1020940797890":1478686417084,"1023211130675":1509788624247,"1020654409554":1478686417028,"1021340170353":1478686417103,"1023371686232":1509788624445,"1024184451790":1509788624480,"1022213813337":1478686417191,"1023371686237":1509788624445,"1023371686226":1509788624446,"1023371686227":1509788624446,"1015843680743":1478686804065,"1024184451781":1509788624480,"1023657419359":1509788624863,"1024184451782":1509788624480,"1024184451783":1509788624480,"1024184451801":1509788624480,"1023371686223":1509788624445,"1024184451806":1509788624480,"1024184451792":1509788624480,"1013059955684":1478686804052,"1022144284797":1478686417184,"1024184451797":1509788624480,"1013131384731":1444487341758,"1022882929754":1509788624553,"4984200509":1509788624165,"245168818":1444487341741,"1023657419362":1509788624863,"1023657419363":1509788624863,"1023657419361":1509788624863,"1012174184085":1478686417073,"1021434406630":1478686417241,"1021716338640":1478686417250,"1020374181854":1478686804047,"1022077832257":1478686417061,"1023657419368":1509788624863,"1023406289681":1509788625040,"1025772101657":1509788625022,"1022037852831":1478686417058,"1024184451738":1509788624480,"1024184451741":1509788624480,"1024184451733":1509788624480,"1019873100193":1478686804031,"1024669935512":1509788624199,"1020180198391":1509788624321,"1020180198390":1509788624321,"1024184451754":1509788624480,"1024184451756":1509788624480,"1020180198397":1509788624321,"1022977432240":1509788624559,"1020180198396":1509788624321,"1020180198395":1509788624321,"1020180198394":1509788624321,"1024184451749":1509788624480,"1020180198393":1509788624321,"1021663259490":1478686417248,"1020180198392":1509788624321,"1024184451751":1509788624480,"1024184451770":1509788624480,"1024184451775":1509788624480,"1024184451760":1509788624480,"1025508258201":1509788624337,"1022977432227":1509788624559,"1024785411439":1509788624584,"1022977432225":1509788624559,"1012102353559":1478686417073,"1022977432228":1509788624559,"1020612466092":1478686417027,"1024184451767":1509788624480,"1022977432229":1509788624559,"1022281052376":1478686417197,"1022281052377":1478686417197,"1022470192031":1478686417219,"1025406946147":1509788624512,"1021188782055":1465470268188,"1022599029723":1509788624462,"1021606242318":1509788624449,"1021606242317":1509788624449,"1021606242316":1509788624449,"1021606242315":1509788624449,"1017168275334":1478686804027,"815973380":1444487341736,"1022152280397":1478686417277,"1020294101534":1465470268289,"1002628220185":1491634246510,"1019932478619":1509788624921,"1025627666439":1509788624566,"1021680555210":1478686804028,"1023730560806":1509788624970,"1023474843619":1509788625082,"1021513835212":1509788624405,"1023305233804":1509788625041,"1021778072248":1480585069064,"1023721647758":1509788625166,"841533151":1491634246535,"1021606242711":1509788624859,"1021606242709":1509788624859,"1021299933136":1480585069071,"1022247761747":1478686417195,"1021606242713":1509788624859,"1021606242712":1509788624859,"1010024505309":1491634246526,"1010024505308":1491634246521,"1010024505306":1491634246526,"1010024505303":1491634246521,"1010024505315":1491634246521,"1012205509110":1478686417223,"1011943237968":1509788624842,"1022447647503":1480585069105,"1608821411":1444487341733,"1008549504927":1478686804032,"1024992498674":1509788625018,"1022335316559":1478686417015,"1022643990511":1509788624368,"1021688419547":1509788624396,"1009340970205":1478686804055,"1248509705":1491634246505,"1014754750879":1478686804071,"1024794062841":1509788624989,"1020995980677":1478686417088,"1025278755341":1509788625171,"1022041260801":1478686417170,"1023007447700":1509788624264,"1023007447703":1509788624264,"1025715217410":1509788624510,"1023007447705":1509788624264,"1025715217411":1509788624510,"4976467219":1509788624165,"1025715217414":1509788624433,"1021924612628":1478686417141,"1022470584990":1478686804065,"1023007447710":1509788624264,"1023007447711":1509788624264,"1025715217413":1509788624433,"1004386922329":1478686804061,"1004386922328":1478686804061,"1025715217435":1509788624432,"1004386922331":1478686804061,"1004386922330":1478686804061,"1021278043539":1478686416988,"1004386922333":1478686804061,"1004386922332":1478686804061,"1004386922335":1478686804061,"1004386922334":1478686804061,"1004386922321":1478686804061,"1021278043550":1478686416988,"1004386922325":1478686804061,"1023007447692":1509788624264,"1025715217430":1509788624432,"1004386922324":1478686804061,"1004386922327":1478686804061,"1025715217428":1509788624432,"1004386922326":1478686804061,"1023007447695":1509788624264,"1021778072565":1480585069064,"1025715217450":1509788624455,"1004386922337":1478686804061,"1004386922336":1478686804061,"1004386922339":1478686804061,"1023007447739":1509788624264,"1004386922340":1478686804061,"1023007447715":1509788624264,"1023007447719":1509788624264,"1025715217459":1509788624437,"1025715217456":1509788624453,"1022986738583":1509788624175,"1025715217457":1509788624437,"1025715217462":1509788624426,"1021455509037":1509788624398,"1025715217460":1509788624434,"1023007447727":1509788624264,"1025715217461":1509788624424,"1025715217482":1509788624505,"1023007447764":1509788624264,"1024352351502":1509788624179,"1022477657422":1478943089223,"1013131384428":1444487341758,"1008898019897":1480585069067,"1023007447745":1509788624264,"1025715217499":1509788624505,"1025715217496":1509788624505,"1025715217497":1509788624505,"1025715217503":1509788624505,"1022394564173":1509788624958,"1021848199132":1509788624394,"1025715217490":1509788624506,"1022183607248":1478686417187,"1025715217491":1509788624505,"1025632647500":1509788624348,"1025632647501":1509788624348,"1025715217489":1509788624506,"1025715217495":1509788624506,"1025715217492":1509788624505,"1025715217493":1509788624506,"836289592":1478950494916,"1023007447792":1509788624264,"1022238717730":1509788624930,"1025715217515":1509788624505,"1022238717731":1509788624941,"1025715217512":1509788624506,"1022238717728":1509788624947,"1025715217513":1509788624505,"1022238717729":1509788624932,"1025715217518":1509788624505,"1012151901690":1478686804067,"1018923633052":1509788624282,"1025715217519":1509788624505,"1025715217516":1509788624506,"1023007447799":1509788624264,"1025715217517":1509788624505,"1025715217506":1509788624505,"1023007447801":1509788624264,"1023007447802":1509788624264,"1025715217504":1509788624505,"1025715217510":1509788624505,"1023007447806":1509788624264,"1025715217508":1509788624505,"1023007447807":1509788624264,"1023007447781":1509788624264,"1025001542594":1509788624996,"1020570659797":1509788624353,"1025715217520":1509788624505,"1025715217521":1509788624505,"1023007447788":1509788624264,"1021734949583":1478686804047,"1021153916773":1478686417300,"1022477788815":1478943089487,"1024518290677":1509788625027,"1023957048941":1509788624519,"1022341217931":1478686417202,"1023957048921":1509788624520,"1020180197799":1509788624286,"1007156365801":1478686804025,"1006848219661":1478686804040,"1020982608279":1478686417087,"1020180197801":1509788624286,"1636997078":1478686417024,"1021776105523":1509788624400,"1022449743976":1478686417296,"1025278755269":1509788624569,"132837818":1444487341728,"1022837445473":1509788625054,"1021413566021":1509788624818,"446754045":1478686804024,"1021014724490":1478686417035,"1009748340539":1491634246511,"1008335205374":1478686804046,"1019017999549":1509788624367,"1017827560906":1478686804032,"1025629371072":1509788625022,"1022933130496":1509788624384,"1022035492994":1478686417167,"123662805":1444487341740,"1021014200140":1478686417089,"1021014200142":1478686417231,"1019841381695":1509788624285,"1025278755090":1509788624870,"1023730691433":1509788624960,"1025756112295":1509788624970,"1020612466546":1478686417027,"1021896694660":1478686417139,"1025017794968":1509788624261,"1010768453688":1478950494939,"1020764380176":1478686417028,"1021928806884":1509788624974,"132837666":1444487341733,"1023371686804":1509788624556,"1023371686795":1509788624556,"1022595359061":1480585069076,"1023371686796":1509788624556,"1023371686797":1509788624556,"1023371686787":1509788624556,"1020982608248":1478686417087,"1016335717477":1478686804016,"1012151246563":1478686804068,"123662781":1444487341737,"1012151246567":1478686804068,"1012151246570":1478686804068,"1024205947250":1509788624185,"1024058366143":1509788624353,"1001042404571":1444487341752,"1018468816736":1509788624427,"1025712727846":1509788624306,"1012226481013":1478686804028,"1012151246586":1478686804068,"1012151246588":1478686804068,"1021839023176":1478686416983,"1012151246590":1478686804068,"1025147295845":1509788625133,"1012151246595":1478686804068,"1012151246597":1478686804068,"1012151246600":1478686804068,"1012151246603":1478686804068,"1012151246602":1478686804068,"1021384865972":1478686417006,"1021678851897":1509788624396,"1000526185418":1444487341712,"1025147295813":1509788625165,"1025147295808":1509788625166,"1025147295809":1509788625166,"1021424969318":1509788624978,"1000526185409":1444487341731,"1025147295823":1509788625104,"1025147295831":1509788625110,"1021425231463":1509788625014,"1025147295839":1509788625133,"1025147295832":1509788625133,"1025147295833":1509788625133,"1025147295834":1509788625133,"1025784291885":1509788624349,"132837548":1444487341717,"1021257461774":1478686417004,"1020626228649":1478686804028,"1025147295804":1509788625246,"1025147295805":1509788625246,"1022233081444":1478686417282,"1025147295800":1509788625244,"1025756111965":1509788624970,"4984200829":1509788624160,"1024205947115":1509788624184,"1022233081428":1478686417282,"1024205947117":1509788624184,"1022337941377":1478686417069,"1022469404796":1478686417219,"1022484080554":1478943089532,"1012660973612":1478686804016,"1024981357289":1509788624924,"1021042249113":1478686417092,"1012110086453":1478686417223,"944820217":1491634246515,"1024005282879":1491634246530,"1022235702953":1478686417193,"1019873100300":1478686804032,"1024818048201":1509788624929,"1013131383916":1444487341758,"1023888757693":1491634246517,"1021429425864":1509788624861,"1001042404857":1444487341751,"1021429425866":1509788624861,"1021429425863":1509788624861,"1021429425862":1509788624861,"873645047":1478686804024,"1023623865276":1509788624178,"1022319063533":1478686416978,"1022438078746":1478686417071,"4914598672":1509788624164,"1021354325402":1465470268230,"1021896693028":1478686417258,"1020821656912":1478686417078,"1025636578382":1509788624337,"1016728011087":1478686804017,"1017436183317":1478686804025,"1021882143779":1478686417137,"1019960132243":1509788624518,"1021778075238":1480585069064,"1023932014543":1491634246529,"1020805141610":1478686417030,"1025714694642":1509788624915,"1021885945224":1478686417054,"1025714694641":1509788624835,"1009388682490":1478686804066,"1022787377748":1509788624379,"1025714694632":1509788624822,"1022243830473":1478686417283,"1025714694637":1509788624835,"1025714694613":1509788624836,"1025714694616":1509788624842,"1023176000150":1509788625079,"1017581671438":1478686804020,"1021164665409":1478686417038,"1025714956555":1509788624229,"1004390982193":1478686804033,"1024154438712":1509788667409,"1021748714651":1478686804068,"1025714956572":1509788624745,"1024154438688":1509788667409,"1025714956570":1509788624832,"1024154438695":1509788667409,"1022241208868":1509788624920,"1022084382862":1478686417272,"1024154438699":1509788667410,"1024794059278":1509788624989,"1022451316392":1478686416992,"1024527200996":1509788624281,"1024154438674":1509788667409,"1021666400348":1509788624195,"1024527200987":1509788624280,"1024527200990":1509788624281,"1025067471490":1509788624294,"1024687238228":1509788624420,"1020294100492":1465470268289,"1021774405313":1509788625231,"1024154438684":1509788667409,"1024154438658":1509788667409,"1017312847050":1478686804019,"1024154438661":1509788667410,"1021852128115":1478686417053,"1024154438669":1509788667410,"1025041649936":1509788624430,"1025041649938":1509788624430,"1022908617271":1509788624304,"1025041649939":1509788624456,"1025041649940":1509788624427,"1024527200959":1509788624337,"1025041649942":1509788624454,"1025041649943":1509788624441,"1025041649944":1509788624438,"1025041649945":1509788624424,"1038140716":1444487341717,"1025041649948":1509788624438,"1020913273612":1478686416978,"1025041649949":1509788624426,"1019739673882":1509788624173,"1025041649920":1509788624440,"1024154438754":1509788667409,"1021395482581":1478686417105,"678219967":1509788625020,"1025041649925":1509788624430,"1025041649926":1509788624430,"1832424929":1491634246509,"1025041649930":1509788624430,"1020853245865":1478686417031,"1021685930251":1478686417249,"1025041649935":1509788624430,"1024154438765":1509788667409,"1021259431879":1465470268200,"1024985554400":1509788624279,"1024985554401":1509788624279,"1024985554402":1509788624279,"1024154438744":1509788667409,"1019674136912":1509788624366,"1021259431885":1465470268200,"1024985554406":1509788624279,"1024154438723":1509788667409,"1025041649956":1509788624434,"1024154438725":1509788667409,"1019861961879":1509788625081,"1024154438734":1509788667409,"1001042406097":1444487341753,"1022240815709":1478686417283,"1016634166770":1478686804053,"1016634166771":1478686804053,"1016634166768":1478686804053,"1016634166769":1478686804053,"1022679377298":1509788624462,"1016634166767":1478686804053,"1017168276026":1478686804021,"1021229416394":1478686417099,"1023316769701":1509788624301,"1021112370881":1478686417232,"1025041649913":1509788624511,"1025041649917":1509788624509,"1025041649919":1509788624440,"1016930647060":1478686804019,"1025223708100":1509788624272,"1021521571509":1509788624398,"1025715611836":1509788624431,"1025715611837":1509788624425,"1025715611838":1509788624406,"1025715611834":1509788624428,"1024797729560":1509788624241,"1017162639926":1478686804053,"1024017339800":1509788624610,"1024017339799":1509788624610,"1024017339795":1509788624610,"1024017339793":1509788624610,"1021693663245":1478686804028,"1024017339789":1509788624610,"1024017339786":1509788624610,"1024632842587":1509788624461,"1024017339784":1509788624610,"1024017339783":1509788624610,"1024017339776":1509788624610,"1021698907022":1478686417122,"1016092453467":1509788624941,"1024017339828":1509788624610,"1008938651881":1509788624353,"1025719805994":1509788624348,"1024017339825":1509788624610,"1019761563419":1509788624362,"1019761563418":1509788624362,"1019761563417":1509788624362,"1019761563416":1509788624362,"1024017339821":1509788624610,"1015545236142":1478686804065,"1024017339818":1509788624610,"1019761563420":1509788624362,"1020936211743":1478686417083,"1024797729568":1509788624241,"1019489724355":1509788624301,"1022108238837":1478686417182,"1024797729573":1509788624241,"1019761563412":1509788624362,"1021721451062":1478686804047,"1021721451059":1478686804047,"1019021146894":1509788624313,"1021470715139":1478686417045,"1021721451069":1478686804047,"1022622097504":1509788624836,"1024479887008":1509788624934,"1021721451064":1478686804047,"1024479887011":1509788624934,"1021846229936":1509788625076,"1022421431401":1478686417209,"544659946":1478686417019,"1020985626125":1478686804039,"1022468093590":1478686417218,"1024017339774":1509788624610,"1025558196551":1509788624336,"1012599372520":1478686416994,"1024662465506":1509788625025,"1024017339767":1509788624610,"1024479887004":1509788624934,"1024479887006":1509788624934,"1024479887007":1509788624934,"1025270239117":1509788624532,"1023657422738":1509788624564,"1023657422736":1509788624563,"1023877487351":1491634246512,"1023657422737":1509788624564,"1023657422740":1509788624563,"1012842375984":1478686417026,"5000319948":1509788667399,"1023657422744":1509788624563,"1012321634859":1478686804062,"1016857638991":1509788624976,"1013389855624":1444487341759,"1017165130487":1478686804020,"1832424679":1491634246509,"1022403343091":1478686417207,"1025270239187":1509788624532,"1021989489242":1478686417155,"917294921":1509788625019,"1018471700655":1478686804031,"1020612466740":1478686417027,"1021667055901":1478686416979,"1020744192030":1478686416996,"1025784425601":1509788624349,"1023560296937":1509788625039,"1021721451075":1478686804047,"1021622756455":1478686417049,"1021108176858":1465470268306,"1021611877936":1478686417049,"1010024632547":1491634246521,"1013131385244":1444487341758,"1024146573611":1509788667505,"1021767720149":1509788624533,"1022824603605":1509788624510,"1017378642614":1478686804016,"1016993428289":1509788624353,"1024146573615":1509788667504,"1022543851156":1509788625063,"1020747338638":1478686416996,"1024146573607":1509788667504,"1024146573604":1509788667504,"1021971925145":1478686417149,"1021767720131":1509788624194,"1024146573631":1509788667505,"1017168275758":1478686804031,"1020948402065":1478686417085,"1024146573618":1509788667505,"1024146573623":1509788667505,"1023958356480":1509788625037,"1017168275803":1478686804031,"1024146573641":1509788667504,"1021778074640":1480585069064,"1021767720123":1509788624815,"1010023059638":1491634246518,"1024146573659":1509788667505,"1024146573656":1509788667505,"1022421432235":1478686417210,"1024727870513":1509788624927,"1024146573663":1509788667505,"1024146573652":1509788667505,"1022350783083":1478686417203,"1025568682521":1509788624336,"1024146573677":1509788667505,"1024470056363":1509788624522,"1020391878303":1478686804027,"1024470056361":1509788624522,"1021307662382":1478686417005,"1024470056367":1509788624522,"1024146573668":1509788667505,"1017168275831":1478686804040,"1023716139168":1491634246523,"1024146573689":1509788667505,"1024146573694":1509788667505,"1022082155072":1509788624944,"1024146573683":1509788667505,"1024146573686":1509788667505,"1022177182738":1478686417278,"1017168275870":1478686804027,"1012476692023":1444487341701,"4818396606":1509788624165,"1022442009652":1478686416984,"1007839894914":1509788624389,"1017168275845":1478686804040,"1018470521818":1509788624837,"1021275681421":1478686417101,"1210233483":1444487341732,"1021288657866":1465469681397,"1022030516100":1478686417058,"1004243135447":1478686804052,"1004243135446":1478686804052,"1004243135445":1478686804052,"1004243135444":1478686804052,"1004243135443":1478686804052,"1016655925043":1480585069075,"1011676903161":1478686804049,"1004243135454":1478686804052,"1004243135453":1478686804052,"1024736914752":1509788624520,"1021952789364":1478686417146,"1004243135452":1478686804052,"1021001089593":1478686417089,"1004243135451":1478686804052,"1004243135450":1478686804052,"1004243135449":1478686804052,"1004243135448":1478686804052,"1727437878":1444487341755,"1025509048116":1509788667537,"1025509048117":1509788667537,"1021390108087":1478686417042,"1025041650451":1509788624539,"1010024632326":1491634246521,"1025509048113":1509788667537,"1025509048124":1509788667537,"1025509048127":1509788667537,"1025041650462":1509788624542,"1025627665938":1509788625139,"1025041650435":1509788624551,"1025627665937":1509788625138,"1025627665942":1509788625138,"1025509048097":1509788667538,"1025509048098":1509788667537,"1021783579958":1509788624395,"1025627665941":1509788625138,"1025509048099":1509788667537,"1021953575706":1478686417146,"1017168275905":1478686804031,"1022046243968":1478686804047,"1025627665947":1509788625138,"1727437868":1444487341708,"1025627665944":1509788625138,"1019849378292":1509788624285,"1019849378291":1509788624285,"1025509048106":1509788667537,"1021395482072":1478686417105,"1022827618120":1509788624990,"1022320246021":1478686417200,"1025041650483":1509788624536,"1025627665953":1509788625138,"1021663258088":1478686417248,"1740545366":1444487341724,"1020385192375":1509788625080,"1025041650489":1509788624537,"1021426936781":1509788624405,"1022320246027":1478686417200,"1022320246024":1478686417200,"1022460097887":1478686417217,"1025041650464":1509788624542,"1025041650466":1509788624542,"1025041650468":1509788624542,"1017168275951":1478686804031,"1022435063799":1478686417294,"1025041650473":1509788624566,"1018797543164":1478686804038,"1023957046133":1509788624520,"1018797543161":1478686804038,"1018797543160":1478686804037,"1018797543163":1478686804038,"1018797543162":1478686804038,"1018797543156":1478686804037,"1020662276049":1478686804039,"1018797543155":1478686804037,"1023957046119":1509788624519,"1022544375710":1509788625075,"1022238849494":1509788624946,"1021744127815":1509788624403,"1021668629446":1509788624814,"1022238849498":1509788624931,"1023957046125":1509788624520,"1023957046122":1509788624519,"1017168275461":1478686804029,"1021051027601":1465470268305,"1021051027600":1465470268305,"1020913273054":1478686416978,"1020856521734":1478686417079,"1023657422195":1509788624226,"1023657422192":1509788624226,"1023657422193":1509788624226,"1023957046101":1509788624520,"1023957046110":1509788624519,"1021711489287":1478686417050,"1025041650427":1509788624613,"1025041650429":1509788624611,"1018797543117":1478686804057,"1018797543116":1478686804057,"1018797543119":1478686804057,"1018797543118":1478686804057,"1021711489305":1478686417050,"1018797543113":1478686804057,"1018797543112":1478686804057,"1018797543115":1478686804057,"1018797543109":1478686804057,"1022350783246":1478686417203,"1018797543111":1478686804057,"5000319281":1509788667399,"1018797543110":1478686804057,"1023657422191":1509788624226,"1023657422189":1509788624226,"1023957046069":1509788624519,"1017168275541":1478686804040,"1023957046055":1509788624519,"1023957046062":1509788624520,"1022261524487":1478686417284,"1019930772243":1509788624386,"1023957046046":1509788624519,"1021693532717":1509788624533,"1020971207997":1478686417086,"4818396233":1509788624165,"1022021340759":1478686417011,"1021735870303":1509788624395,"1018797543029":1478686804057,"1018797543028":1478686804057,"1018797543025":1478686804057,"1018797543024":1478686804057,"1018797543027":1478686804057,"1018797543026":1478686804057,"1010756267680":1509788624276,"1020979727455":1478686417034,"1018797543021":1478686804057,"1018797543020":1478686804057,"1018797543023":1478686804057,"1018797543022":1478686804057,"1020612467271":1478686417027,"124058866":1444487341742,"1022021340749":1478686417011,"1022147561418":1478686417185,"1021288657659":1465469681397,"725799129":1444487341718,"1022021340745":1478686417011,"1015061589264":1478686804018,"1013109496189":1478686804062,"725799136":1444487341728,"1015061589289":1478686804027,"1021900363074":1478686417054,"1025714956862":1509788625123,"1025714956861":1509788625115,"1022517242268":1509788625065,"1018071413392":1509788625076,"1013110282565":1478686417074,"1021693532924":1509788624815,"1018797542968":1478686804057,"1004333968855":1444487341756,"1023877880008":1491634246506,"1025607086554":1509788624368,"1021742292914":1478686417253,"1018797542967":1478686804057,"1018797542966":1478686804057,"1018797542959":1478686804057,"1023520454051":1509788625039,"292481675":1444487341741,"1021693532844":1509788624193,"1365420690":1444487341730,"1023957046150":1509788624520,"1017168275695":1478686804031,"1018844859639":1478686804064,"1021044867088":1478686417092,"1018844859638":1478686804064,"1018844859637":1478686804064,"1018844859636":1478686804064,"1018844859635":1478686804064,"1008341104954":1478686804052,"1008341104955":1478686804052,"1008341104952":1478686804052,"1008341104953":1478686804052,"1024961304729":1509788624970,"1008341104956":1478686804052,"1008341104946":1478686804052,"1025629630638":1509788625087,"1008341104945":1478686804052,"1008341104951":1478686804052,"1025629630633":1509788625115,"1008341104948":1478686804052,"1025629630634":1509788625124,"1008341104949":1478686804052,"1025629630635":1509788625106,"1008341104943":1478686804052,"1008341104941":1478686804052,"1021668629703":1509788624193,"1018517706902":1480585069070,"1022154244565":1478686417185,"1025672229413":1509788624921,"1021398232285":1478686417043,"1001056956265":1478686804033,"1021398232286":1478686417043,"1021367300861":1478686417006,"1585095246":1444487341742,"1023186486908":1509788624894,"1023186486909":1509788624894,"1023186486910":1509788624894,"1021706903211":1478686417122,"1023186486907":1509788624894,"1574609297":1491634246509,"1025714695650":1509788624910,"1025714695651":1509788624910,"1022755134536":1509788624393,"1025714695648":1509788624910,"1025714695649":1509788624910,"1025907105902":1509788667456,"1025714695655":1509788624910,"1025714695652":1509788624910,"1025907105900":1509788667457,"1025714695653":1509788624910,"1025907105901":1509788667458,"1025715613148":1509788624185,"1025714695658":1509788624910,"1025714695659":1509788624910,"1020435393030":1465470268318,"1025714695657":1509788624910,"1025715613144":1509788624200,"1025715613145":1509788624203,"1025715613146":1509788624197,"1025714695660":1509788624910,"1025714695661":1509788624910,"1021664699259":1478686417120,"1021295736176":1478686417004,"1025628844213":1509788624540,"1025628844215":1509788624537,"1025628844217":1509788624523,"1025714695643":1509788624910,"1004769250408":1478686804064,"1025714695647":1509788624910,"1025714695645":1509788624910,"1021207656485":1478686804026,"1021207656480":1478686804026,"1007164359475":1478686804032,"1022370313875":1478686417204,"1022364939740":1509788624957,"1021278041222":1478686417004,"1023186486983":1509788624894,"1023186486977":1509788624894,"1022364939737":1509788624958,"1022364939738":1509788624957,"1022364939739":1509788624958,"1020804354251":1478686417030,"1020795572300":1478686417029,"1022364939733":1509788624957,"1017591238988":1478686804025,"1022364939734":1509788624959,"1022364939735":1509788624958,"1022364939728":1509788624958,"4818396094":1509788624165,"1019314614172":1509788624375,"1012759802190":1478686417074,"1022364939722":1509788624957,"1021778074306":1480585069064,"1022364939713":1509788624957,"1021906391596":1478686417140,"1022364939715":1509788624958,"1022364939772":1509788624957,"1016930646405":1478686804067,"1024785409461":1509788624481,"1026231897210":1514456869769,"1022364939767":1509788624958,"1019802324151":1509788624931,"1021129276494":1478686417233,"224850391":1491634246512,"1022364939752":1509788624958,"1023186487026":1509788624493,"1023186487036":1509788624494,"1022364939748":1509788624957,"1022364939744":1509788624958,"1022364939745":1509788624957,"1022067739567":1478686417175,"1022364939746":1509788624958,"1023186486917":1509788624894,"1023186486912":1509788624894,"1019802324191":1509788624309,"1022434275837":1478686417071,"1021236230729":1509788624172,"1023186486932":1509788624894,"1023186486933":1509788624894,"1023186486928":1509788624894,"1223603257":1478686804016,"1020783777603":1478686804064,"1020783777605":1478686804064,"1020783777604":1478686804064,"1020783777606":1478686804064,"1023186486948":1509788624894,"1023186486950":1509788624894,"1023186486951":1509788624894,"1022364939711":1509788624958,"1023186486944":1509788624894,"1023186486946":1509788624894,"1023186486947":1509788624894,"1022364939700":1509788624957,"1022364939696":1509788624958,"1023186486953":1509788624894,"1022364939697":1509788624958,"1022076650630":1509788624928,"1023186486964":1509788624894,"1021354586470":1465470268232,"1023830039835":1509788624969,"1023830039836":1509788624969,"1022192255856":1509788624176,"1025406944018":1509788624511,"1025672229570":1509788624942,"1023830039825":1509788624969,"1023186486974":1509788624894,"1023186486970":1509788624894,"1021354586472":1465470268232,"1021506235241":1478686416981,"1022357992623":1509788625018,"1024685402598":1509788624438,"1022357992619":1509788625016,"1017403022350":1478686804020,"1025480212123":1509788624306,"1022283151655":1478686417286,"1021465602525":1478686417108,"1021630750775":1478686417049,"1023186487044":1509788624494,"1023186487046":1509788624494,"1023186487042":1509788624494,"1021622755548":1478686417049,"1023186487054":1509788624494,"490659957":1444487341732,"1023186487050":1509788624494,"1023186487060":1509788624494,"1022095655961":1478686417012,"1023186487062":1509788624494,"1023186487063":1509788624494,"1023186487058":1509788624494,"1023186487059":1509788624494,"1023186487068":1509788624494,"1023186487064":1509788624494,"1025911300262":1509788667458,"1023186487065":1509788624494,"1023186487066":1509788624494,"1025911300261":1509788667464,"1023309954954":1509788624417,"1023186487078":1509788624494,"1024687237523":1509788625102,"1023309954956":1509788624416,"1021434539957":1478686417241,"1023015833078":1509788624389,"1023186487074":1509788624494,"1021273584940":1478686417101,"1023309954959":1509788624416,"1020933851619":1478686417083,"1023186487084":1509788624493,"1023309954945":1509788624416,"1023186487085":1509788624494,"1021694975042":1480585069067,"1023309954947":1509788624417,"1023309954948":1509788624417,"1023186487080":1509788624494,"1023309954950":1509788624417,"1023309954951":1509788624417,"1023309954968":1509788624416,"1023309954971":1509788624417,"1019070953671":1509788624314,"1023309954961":1509788624416,"1019070953674":1509788624314,"1023309954963":1509788624416,"1019070953677":1509788624315,"1023309954964":1509788624416,"1023309954967":1509788624416,"1021680557446":1478686804028,"1021138320895":1478686417037,"1024780428486":1509788624567,"1024780428485":1509788624567,"1024780428490":1509788624567,"1025509832768":1509788625082,"4984198300":1509788624165,"1012685223391":1478686417026,"1024780428488":1509788624567,"1021781875604":1478686417009,"1021781875602":1478686417009,"1021411339711":1478686417043,"1022129604305":1478686417063,"1019314613913":1509788624323,"1019314613912":1509788624323,"1019314613911":1509788624323,"1022340429134":1478686417288,"1021288658175":1465469681397,"1020997682503":1478686417230,"1557963075":1444487341752,"1038139458":1444487341724,"1025607743419":1509788624829,"1020254385825":1509788625077,"1025607743420":1509788624823,"1557963038":1444487341753,"1024334660145":1509788624997,"1025607743444":1509788624833,"1025607743445":1509788624799,"1025607743450":1509788624428,"1020294099808":1465470268289,"1025607743448":1509788624431,"1025607743449":1509788624425,"1025607743453":1509788624407,"1025607743426":1509788624198,"1025607743427":1509788624186,"1025607743424":1509788624201,"1025607743425":1509788624204,"1022053321241":1478686417172,"1022053321242":1478686417172,"1021668629766":1509788624532,"1022053321232":1478686417172,"1021425101991":1478686417043,"1024780428458":1509788624567,"1024780428459":1509788624567,"1024780428462":1509788624567,"1557963058":1444487341750,"1024780428465":1509788624567,"1024780428470":1509788624567,"1024780428471":1509788624567,"1021411339721":1478686417043,"1010076274735":1491634246534,"1021411339722":1478686417043,"1024780428476":1509788624567,"1557963043":1444487341755,"1018471702344":1478686804031,"1021038969923":1478686417092,"1025284524369":1509788624945,"1022608467657":1509788624366,"1019391026825":1509788624302,"1022075340424":1478686417061,"1021289051997":1478686417040,"1024936008767":1509788625007,"1021997616402":1478686417011,"1022400328980":1478686417292,"4984198945":1509788624164,"1022112564336":1509788624943,"1025672228986":1509788624921,"1024936008798":1509788625006,"1019932476952":1509788624922,"1024785409873":1509788624250,"1024936008791":1509788625006,"1024936008784":1509788625006,"1021597066579":1509788624492,"1020294230257":1465470268298,"1022273977074":1478686417067,"1024936008768":1509788625007,"1019674007549":1509788624315,"1025278757329":1509788624234,"1022646478065":1509788624368,"1021157326652":1478686417234,"1025058034852":1509788624330,"1022579108076":1480585069125,"1021138189836":1478686417096,"1021983853671":1509788625067,"1024936008805":1509788625006,"1022033791840":1478686417267,"1012121360820":1478686417073,"1024936008803":1509788625007,"1003975622645":1478686417221,"1019345021919":1509788624302,"1003975622644":1478686417221,"1019345021918":1509788624282,"1003975622641":1478686417221,"1003975622643":1478686417221,"1003975622642":1478686417221,"1021776763086":1509788624399,"1025883907355":1509788667402,"1025714695994":1509788624822,"1003975622652":1478686417221,"1025714695995":1509788624842,"1003975622655":1478686417221,"1025714695992":1509788624915,"1003975622654":1478686417221,"1003975622649":1478686417221,"1025714695998":1509788624836,"1003975622651":1478686417221,"1003975622650":1478686417221,"1025714695997":1509788624835,"1025714695970":1509788624914,"1025714695968":1509788624914,"1025714695969":1509788624914,"1025714695974":1509788624914,"1022314346710":1478686417068,"1022551321270":1509788624267,"1025714695972":1509788624914,"1022314346712":1478686417068,"1025910776698":1509788667579,"1025910776699":1509788667579,"1025910776696":1509788667579,"1025714695977":1509788624914,"1025910776697":1509788667578,"1025714695983":1509788624914,"1025714695980":1509788624914,"1025910776700":1509788667579,"1010057400919":1491634246534,"1025714695962":1509788624914,"1025714695963":1509788624914,"1025714695961":1509788624914,"1025714695966":1509788624914,"1025714695967":1509788624914,"1025714695964":1509788624914,"1025714695965":1509788624914,"1025012029732":1509788624436,"1025714695939":1509788624914,"1025714695937":1509788624914,"1025714695942":1509788624914,"1025714695943":1509788624914,"1024642412329":1509788667536,"1025714695940":1509788624914,"1024642412330":1509788667536,"1025714695941":1509788624914,"1024642412331":1509788667536,"1025714695944":1509788624914,"1025714695945":1509788624914,"5000320183":1509788667399,"1025714695949":1509788624914,"1025714696050":1509788624836,"1025714696051":1509788624836,"1025714696048":1509788624915,"1025714696049":1509788624836,"1021680557761":1478686804028,"1025714696054":1509788624836,"1025714696058":1509788624836,"1832424435":1491634246509,"1025714696062":1509788624836,"1025714696061":1509788624836,"1020919827881":1478686417081,"1025714696016":1509788624846,"1025784032118":1509788624350,"1021694975937":1480585069067,"1025714696002":1509788624836,"1021927100804":1478686417142,"1025714696008":1509788624836,"1022551321307":1509788624267,"1025714696014":1509788624836,"1025714696015":1509788624836,"1025784032110":1509788624352,"1025714696012":1509788624836,"1832423997":1491634246524,"1022816082801":1509788624439,"1038140139":1444487341747,"1025714695870":1509788624913,"1021042378046":1478686417092,"1025714695843":1509788624913,"1025593849300":1509788624425,"1025714695840":1509788624913,"1025783769735":1509788624367,"1025593849301":1509788624407,"1025714695841":1509788624913,"1025593849298":1509788624428,"1025714695846":1509788624913,"1025593849299":1509788624431,"1025714695844":1509788624913,"1019018788282":1509788624317,"1022430212704":1478686417211,"1025714695850":1509788624913,"1025714695848":1509788624913,"1018144944605":1509788625081,"1025714695849":1509788624913,"1025628058561":1509788624453,"1025714695852":1509788624913,"1025714695853":1509788624913,"1020428446090":1509788624371,"1025715613357":1509788625114,"1025715613358":1509788625123,"1025714695833":1509788624913,"1025715613359":1509788625106,"1025714695838":1509788624913,"1025714695839":1509788624913,"1025714695836":1509788624913,"1025714695837":1509788624913,"1025714695808":1509788624911,"1022747533149":1509788624402,"1025714695809":1509788624911,"1025715613360":1509788625087,"1025672229133":1509788624921,"1019455513497":1478686804021,"1013135055911":1478686804046,"1025714695927":1509788624914,"1025714695930":1509788624914,"1021764442703":1478686417052,"1020778534018":1478686417076,"1025714695929":1509788624914,"1025714695934":1509788624914,"1025714695935":1509788624914,"1025714695932":1509788624914,"1019720537005":1509788624276,"1024214730831":1509788625070,"1021435719147":1478686417241,"1024527594799":1509788625027,"1025179012833":1509788624536,"1025714695888":1509788624913,"1025714695889":1509788624914,"1021721976041":1509788624403,"1022041917946":1478686417170,"1021901934994":1509788624394,"1023933847728":1491634246529,"1020824277592":1478686417226,"1022041917936":1478686417170,"1025714695874":1509788624914,"1025714695875":1509788624913,"408086304":1509788624366,"1025714695872":1509788624914,"1023933847724":1491634246529,"1025714695879":1509788624913,"1023933847726":1491634246529,"1025714695876":1509788624914,"1025714695877":1509788624913,"1025714695883":1509788624913,"1021710179643":1478686417122,"1025714695880":1509788624913,"1025714695881":1509788624913,"1025714695886":1509788624913,"1025714695887":1509788624913,"1025714695884":1509788624913,"1022708605250":1509788625058,"1025714695734":1509788624822,"1025714695732":1509788624915,"1016732337811":1478686804049,"1025714695733":1509788624915,"1025672229298":1509788624942,"1025714695737":1509788624842,"1025714695742":1509788624836,"5000320391":1509788667399,"1025714695743":1509788624836,"1025714695740":1509788624836,"1025714695741":1509788624836,"1025627665229":1509788624845,"1025714695714":1509788624911,"1024633237402":1509788624991,"1025714695713":1509788624910,"1025714695718":1509788624911,"1025714695719":1509788624911,"1025714695716":1509788624911,"1016092454062":1509788624941,"1025627665237":1509788624549,"1025714695717":1509788624911,"1022038640948":1478686416991,"1021899313797":1478686417139,"1020185311423":1478686804023,"1008818724152":1509788624372,"1025627665241":1509788624549,"1025627665246":1509788624549,"1022007708440":1478686417158,"1025627665247":1509788624549,"1019300195445":1478686804018,"1025714695698":1509788624910,"1025627665251":1509788624845,"1025714695699":1509788624911,"1025627665248":1509788624549,"1025714695696":1509788624911,"1025714695697":1509788624911,"1025714695703":1509788624911,"1025714695701":1509788624910,"1020826243771":1478686417031,"1025714695704":1509788624911,"1018767920138":1465470268272,"1025714695708":1509788624911,"1022194090200":1478686417013,"1025879975017":1509788667403,"1022427984422":1478686417211,"1016937199998":1478686804022,"1025714695693":1509788624910,"1025714695794":1509788624911,"1022159618650":1478686417186,"1025714695795":1509788624911,"1007156363290":1478686804025,"1025714695793":1509788624911,"1022159618655":1478686417186,"1021964062436":1478686417010,"1025714695797":1509788624911,"1000873064335":1478686804022,"1025714695803":1509788624911,"1022154244610":1478686417185,"1025714695806":1509788624911,"1025714695804":1509788624911,"1022079797129":1478686417061,"1025714695782":1509788624911,"1022024223324":1509788624466,"1025714695781":1509788624911,"1025714695786":1509788624911,"1025714695787":1509788624911,"1021778073999":1480585069064,"1025714695790":1509788624911,"1025714695791":1509788624911,"1020985624693":1478686804039,"1016335719773":1478686804016,"1025459109158":1509788624350,"1017390571057":1478686804016,"1022962750032":1509788625050,"1021606241126":1478686417116,"1025714695744":1509788624836,"1010076275234":1491634246534,"1025714695748":1509788624836,"1021329552614":1478686417239,"1025714695754":1509788624836,"1025714695752":1509788624836,"1021226138305":1478686417235,"1022827616854":1509788624990,"1025050913063":1509788624568,"1022242783880":1478686417195,"1025593821915":1509788624848,"1025593821914":1509788624847,"1025593821919":1509788624831,"1020882039230":1478686416999,"1025593821909":1509788624916,"1025593821908":1509788624917,"1021564279088":1478686417048,"1018969145219":1480585069065,"1024954574021":1509788624923,"1025552140130":1509788624337,"1025593821934":1509788624831,"1025517143376":1509788624308,"1025593821922":1509788624831,"1025593821945":1509788624822,"1018477880029":1478686804033,"1025593821946":1509788624846,"1025593821948":1509788624836,"1023319818821":1509788624288,"1019835413046":1509788624354,"1025593821936":1509788624868,"1025593821939":1509788624826,"1025593821940":1509788624867,"1009328390268":1478686804024,"1025593821943":1509788624848,"1025593821833":1509788624917,"1022387489699":1478686417205,"1025593821838":1509788624916,"1024638423452":1509788667502,"1023453383220":1509788624869,"1016399636126":1480585069069,"1021969429159":1478686417056,"1025593821852":1509788624831,"1025593821854":1509788624831,"1024638423436":1509788667502,"635118979":1491634246506,"1025593821843":1509788624847,"1025593821844":1509788624848,"1025593821847":1509788624831,"1014050003620":1478686804064,"1025593821846":1509788624831,"1025593821865":1509788624824,"1025593821864":1509788625000,"1025593821867":1509788624999,"1025593821857":1509788624831,"1025593821859":1509788624998,"1025593821858":1509788624868,"1025593821860":1509788625005,"1025593821863":1509788624822,"1025593821862":1509788625000,"1022897891816":1509788624850,"1022897891820":1509788624850,"1023000260355":1509788624462,"1022897891812":1509788624850,"1022897891815":1509788624850,"1024638423461":1509788667502,"1022897891814":1509788624850,"1025593821769":1509788624917,"1025593821773":1509788624916,"1025593821775":1509788624847,"1025879956316":1509788667403,"1024954573930":1509788624923,"1025593821786":1509788624831,"1021494023600":1478686417243,"1022220894566":1478686417281,"1025593821788":1509788624831,"1025593821790":1509788624831,"1025593821776":1509788624847,"1025593821779":1509788624826,"1020946527574":1478686416990,"1025593821781":1509788624831,"1025593821780":1509788624831,"1025593821782":1509788624831,"1007134408107":1509788624374,"1021249308541":1478686417100,"1025593821806":1509788624868,"1023808724872":1509788625071,"4818411419":1509788624159,"1020202289290":1465470268243,"1020016950782":1509788624280,"1020202289289":1465470268243,"1025593821816":1509788624824,"1019630020341":1509788624933,"1021494023580":1478686417243,"1025593821809":1509788624826,"1025593821811":1509788624867,"1025593821813":1509788624844,"1025593821815":1509788624846,"1020946527605":1478686416990,"1025593821705":1509788624542,"1024164984019":1509788624925,"1024954573860":1509788624923,"1025593821698":1509788624538,"1025593821700":1509788624541,"1025593821702":1509788624541,"1019111360498":1509788624320,"4981598257":1509788624154,"1025593821718":1509788624542,"1022897891705":1509788624216,"1022708489763":1509788624546,"1022897891704":1509788624216,"1022897891706":1509788624216,"1022897891709":1509788624216,"1022708489764":1509788624564,"1022897891699":1509788624216,"1025593821730":1509788624542,"1025593821733":1509788624566,"1025593821735":1509788624566,"1022708489778":1509788624538,"1021631651297":1509788624819,"1022042044013":1478686416974,"1025593821744":1509788624550,"1022267950078":1478686417197,"1017020795710":1478686804023,"1021397815323":1509788624509,"1025593821748":1509788624544,"1025593822152":1509788624197,"1019675371663":1509788624321,"1019941189845":1478686804026,"1021927878208":1509788624432,"1024453347279":1509788624992,"1025593822148":1509788624214,"1024453347276":1509788624992,"1024453347282":1509788624992,"1021931023914":1478686417010,"1021931023915":1478686417010,"1024453347280":1509788624992,"1024453347286":1509788624992,"1024453347290":1509788624992,"1024453347289":1509788624992,"1025593822162":1509788624206,"1024840277192":1509788624970,"1025499710843":1509788624369,"1024453347293":1509788624992,"1022202282446":1478686417190,"1025593822189":1509788624269,"1019034026721":1509788624317,"1024300121295":1509788624519,"1025593822182":1509788624270,"1021952127179":1478686416973,"1025593822193":1509788624214,"4834402586":1509788624154,"1025593822199":1509788624214,"1022096701466":1478686417275,"1025593822091":1509788624229,"1025593822090":1509788624199,"1022238720902":1509788624932,"1025593822092":1509788625001,"1022238720901":1509788624947,"1025593822094":1509788624197,"1022238720906":1509788624931,"1022238720905":1509788624941,"1003850546050":1478686417220,"1003850546051":1478686417221,"1022238720910":1509788624941,"1003850546048":1478686417220,"1022880721361":1509788625144,"1025593822086":1509788624230,"1022238720908":1509788624931,"1022120032935":1478686417013,"1022099060832":1509788624190,"1020992140907":1478686417088,"1025593822096":1509788624198,"1025593822121":1509788624269,"1025593822120":1509788624270,"1025593822123":1509788624214,"1025593822127":1509788624214,"1022262051352":1480585069113,"1016301593037":1480585069066,"1022487236989":1478943089489,"1025593822136":1509788624203,"1023298977987":1509788625072,"1015102962":1444487341752,"1025593822138":1509788624230,"1025593822141":1509788624199,"1020294041563":1465470268283,"1021700465536":1478686804046,"1025593822133":1509788624203,"1025593822135":1509788624203,"1025593822134":1509788624203,"1023532289577":1509788624430,"1025593822025":1509788624866,"1023532289581":1509788624454,"1025593822029":1509788624846,"1021208282537":1478686804027,"1023532289582":1509788624438,"1025593822030":1509788624824,"1023532289569":1509788624430,"1022917946319":1509788624467,"1015159676254":1478686804029,"1025593822016":1509788624831,"1022118198173":1478686417183,"1023532289574":1509788624430,"1025593822022":1509788624868,"1025593822045":1509788624270,"1024322797342":1509788667508,"1025593822046":1509788624269,"1023532289584":1509788624426,"1017239558469":1478686804022,"1023532289587":1509788624424,"1023532289586":1509788624434,"1003850546030":1478686417220,"1025784009779":1509788624351,"1003850546031":1478686417220,"1025593822056":1509788624199,"1003850546028":1478686417220,"1003850546026":1478686417220,"1025784009782":1509788624350,"1024322797358":1509788667508,"1025784009781":1509788624350,"1003850546025":1478686417220,"1025784009780":1509788624351,"1025593822053":1509788624214,"1018778301098":1509788624367,"1024322797351":1509788667508,"1025593822052":1509788624214,"1003850546046":1478686417220,"1025593822073":1509788624203,"1023532289560":1509788624429,"1885172207":1478686417021,"1024322797368":1509788667508,"1003850546042":1478686417220,"1025593822077":1509788624203,"1003850546040":1478686417220,"1003850546041":1478686417220,"1025593822078":1509788624203,"1003850546038":1478686417220,"1023532289553":1509788624440,"1003850546039":1478686417220,"1023836381232":1491634246536,"1003850546037":1478686417220,"1003850546034":1478686417220,"1003850546035":1478686417220,"1025593822068":1509788624203,"1023532289556":1509788624441,"1024322797386":1509788667508,"1024322797385":1509788667508,"1025593821967":1509788624917,"1022430743734":1478686417294,"1023453383604":1509788624870,"1022450405359":1478686417302,"1024322797377":1509788667508,"1022430743741":1478686417294,"1024322797383":1509788667508,"1024322797382":1509788667508,"1022450405355":1478686417215,"1016421000778":1480585069070,"1025593821976":1509788624847,"1025560660247":1509788624308,"1022450405362":1478686417302,"1025593821970":1509788624915,"1025593821994":1509788624848,"1018923662748":1509788624301,"1025593821999":1509788624831,"911947699":1478950494918,"1021769672497":1478686417052,"1022079269293":1478686417061,"1025593821986":1509788624847,"1025499710857":1509788624370,"1025499710856":1509788624369,"1025499710858":1509788624370,"1021769672491":1478686417052,"1021769672494":1478686417052,"1023670572703":1509788624915,"1025593822014":1509788624831,"1022917946302":1509788624467,"1025593822000":1509788624831,"1022917946297":1509788624467,"1021848447994":1509788624534,"1021330443547":1478686416981,"1009548857127":1491634246510,"1021700464889":1478686804046,"764227467":1478686417020,"1021987779024":1509788624463,"1021981749306":1509788625168,"1023961950723":1509788625005,"1022415933020":1480585069074,"1021456798060":1478686417108,"1025505609243":1509788624972,"1023961950749":1509788625005,"1020738120270":1478686417075,"1022249730085":1478686417284,"1023961950764":1509788625004,"1023961950767":1509788625005,"1025688718610":1509788624336,"1022190943625":1478686417188,"1001388189107":1480585069061,"1021618020348":1509788624397,"1021411578480":1478686417043,"1021445132406":1478686417007,"1021411578484":1478686417043,"1003850545288":1478686417220,"1024786798757":1509788624438,"1021411578485":1478686417043,"1025281996088":1509788667889,"1003850545286":1478686417220,"1003850545282":1478686417220,"1023317721311":1509788624196,"1021500970123":1478686804028,"1022355245991":1478686417203,"1024687314601":1509788625084,"1022788575303":1509788624824,"1021411578478":1478686417043,"1021411578479":1478686417043,"1021138027037":1478686417096,"1021686047671":1478686417249,"1022788575348":1509788624821,"1025472708719":1509788624829,"1025472708720":1509788624834,"1023317721312":1509788624196,"1022788575342":1509788624867,"1021138027016":1478686417096,"1011947511387":1478686804030,"1021331885700":1509788624976,"1022259429872":1478686417196,"1022788575338":1509788624827,"1022788575332":1509788624869,"1021804014293":1478686417131,"1021610024483":1478686417116,"1018182963965":1465470268237,"1021792085476":1478686416977,"1025908924037":1509788667456,"1025628950102":1509788624233,"1021932072322":1478686417055,"1025628950106":1509788624232,"1022126848480":1478686417184,"1020792514969":1478686417077,"1020777179500":1478686417029,"1025628950082":1509788624232,"1025628950086":1509788624232,"1021490092027":1478686417110,"1022281975474":1478686417198,"1025628950092":1509788624233,"1020917690653":1478686417081,"1025628950094":1509788624232,"1022677556763":1509788624850,"1021841762511":1478686417135,"1022677556761":1509788624850,"1022677556760":1509788624850,"1019097597110":1509788624389,"1022677556754":1509788624850,"1022677556759":1509788624850,"1021729300878":1509788624993,"1021494417292":1478686417244,"1022803386773":1509788625055,"1003850545276":1478686417220,"1022338599548":1478686417069,"1025628950114":1509788624233,"1003850545268":1478686417220,"1003850545267":1478686417220,"1003850545265":1478686417220,"664741208":1478950494913,"1021631651807":1478686417248,"1022261395851":1478686417197,"1025628950071":1509788624232,"1025628950075":1509788624232,"1025628950077":1509788624233,"1025628950076":1509788624233,"1020822532032":1478686417226,"1023154666181":1509788625044,"1025628950078":1509788624233,"1024352551484":1509788624178,"1022168530923":1478686417278,"1024687314445":1509788624998,"1023319818382":1509788624289,"1024687314444":1509788625007,"1023994980555":1491634246517,"1025050913755":1509788624568,"1025593821647":1509788624542,"1022241604017":1509788624920,"1018335009429":1478686804022,"1000753398381":1478686804068,"1021782385949":1509788624228,"1025593821634":1509788624611,"1019922840542":1478686804026,"1025593821657":1509788624542,"1025593821658":1509788624542,"1025593821661":1509788624541,"1019922840532":1478686804026,"1000753398392":1478686804068,"1025593821653":1509788624542,"1022677557146":1509788624216,"1019922840556":1478686804026,"1022677557145":1509788624216,"1022677557144":1509788624216,"1020294040970":1465470268283,"1025472708901":1509788624407,"1022677557150":1509788624216,"1025593821665":1509788624551,"1575444174":1491634246515,"1024667783473":1509788624199,"1025593821667":1509788624536,"1025593821666":1509788624548,"1025593821669":1509788624538,"1020294172037":1465470268295,"1022677557142":1509788624216,"1025593821668":1509788625000,"1025593821670":1509788624544,"1025593821689":1509788624551,"1025593821691":1509788624551,"1018928119559":1509788624368,"1019922840571":1478686804026,"1025593821694":1509788624551,"1021938758559":1478686417010,"1022441754000":1478686417214,"1021740836782":1478686417125,"1000753398360":1478686804068,"1025593821685":1509788624612,"1019922840561":1478686804026,"1025593821686":1509788624611,"1025593821577":1509788624542,"1025593821569":1509788624551,"1025593821571":1509788624551,"1025593821570":1509788624551,"1025593821573":1509788624539,"1021630602829":1509788624815,"642721024":1478950494913,"1020016950787":1509788624300,"1025593821595":1509788624542,"906966362":1491634246511,"1010812541612":1509788624299,"1022788575556":1509788624198,"1025593821608":1509788624552,"1020653969464":1478686804057,"1025593821615":1509788624538,"1021927484443":1478686417145,"1025593821600":1509788624542,"1025593821604":1509788624542,"1025593821606":1509788624539,"4644738989":1478686416965,"1022788575594":1509788624197,"1025593821630":1509788624613,"1025593821616":1509788624544,"1022788575591":1509788624199,"1024785881709":1509788625198,"1022788575587":1509788624230,"1024256473368":1509788624991,"1012325134370":1478686417223,"1021613563795":1509788624401,"1022629190199":1509788624462,"1001660691705":1478686417024,"1012117120440":1478686417025,"1025593821565":1509788624613,"1022788575656":1509788624538,"1025593821566":1509788624611,"1022291412487":1478686417068,"1022050825645":1478686417269,"1000307811758":1478686417018,"1020876534699":1478686417227,"1024597396882":1509788624937,"1022897891929":1509788624446,"1000753398437":1478686804068,"1021975720272":1509788625011,"1021440807349":1478686417107,"1022897891921":1509788624446,"1022897891920":1509788624446,"1020438222332":1478686804047,"1022897891923":1509788624446,"1020878500414":1509788624934,"1022897891922":1509788624446,"1000753398454":1478686804068,"1022362323632":1478686417289,"1022788575685":1509788624540,"1025906171893":1509788667450,"1021743720356":1478686416988,"1000753398407":1478686804068,"1000753398402":1478686804068,"1022241472848":1478686417066,"1021981749727":1509788624566,"1021981749724":1509788624538,"1024481133776":1509788624282,"1000753398411":1478686804068,"1024718378723":1509788624371,"1000753398417":1478686804068,"1022228234906":1478686417065,"1016711330720":1478686804063,"1020810341914":1480585069080,"1021622737304":1478686417049,"1019788227824":1478686804070,"1019971469284":1480585069076,"1022191205307":1478686417188,"1012572341993":1478686804056,"1019788227825":1478686804070,"1019971469285":1480585069076,"1012572341994":1478686804056,"1019788227826":1478686804070,"1019788227827":1478686804070,"1008774798151":1478686804023,"1012572341996":1478686804056,"1019788227828":1478686804070,"1012572341997":1478686804056,"1019788227829":1478686804070,"1025524613868":1509788624997,"1019788227830":1478686804070,"1012572341999":1478686804056,"1019788227831":1478686804070,"1019971469283":1480585069076,"1012572341984":1478686804055,"1019788227832":1478686804070,"1012572341985":1478686804055,"1019788227833":1478686804070,"1012572341986":1478686804055,"1019788227834":1478686804070,"1024462520925":1509788624988,"1012572341987":1478686804055,"1019788227835":1478686804070,"1025593822914":1509788624430,"1012572341988":1478686804055,"1019788227836":1478686804070,"1022462331746":1478686417217,"1012572341989":1478686804055,"1019788227837":1478686804070,"1025593822916":1509788624455,"1019788227838":1478686804070,"1012572341991":1478686804056,"1019788227839":1478686804070,"1012572342008":1478686804056,"1012572342011":1478686804056,"1012572342012":1478686804056,"1012572342001":1478686804056,"1012572342002":1478686804056,"1025593822931":1509788624437,"1012572342003":1478686804056,"1019788227820":1478686804070,"1025593822933":1509788624438,"1019788227821":1478686804070,"1025593822932":1509788624424,"1012572342006":1478686804056,"1019788227822":1478686804070,"1019788227823":1478686804070,"1012572341961":1478686804055,"1012572341962":1478686804055,"1012572341963":1478686804055,"1022827897217":1509788625054,"1012572341965":1478686804055,"1012572341966":1478686804055,"1012572341967":1478686804055,"1015382764864":1478686804019,"1012572341955":1478686804055,"1022244226626":1478686417195,"1012572341957":1478686804055,"1012572341958":1478686804055,"1015382764868":1478686804016,"1012572341959":1478686804055,"1025593822969":1509788624511,"1024686264528":1509788625024,"1025593822973":1509788624509,"1012572341982":1478686804055,"1019971469276":1480585069076,"1023835071877":1491634246533,"1021602551958":1509788624420,"1024912106832":1509788624927,"1023731916673":1509788625082,"1025285010194":1509788624329,"1025050914147":1509788624232,"1025285010199":1509788624329,"1012572341920":1478686804055,"1012572341922":1478686804055,"1025285010202":1509788624329,"1022076648483":1509788624216,"1022076648480":1509788624216,"1025285010207":1509788624329,"1025285010177":1509788624328,"1025593822875":1509788624511,"1025593822876":1509788624509,"1021253108704":1465469681395,"1012572341896":1478686804055,"1021166339789":1465470268184,"1023021757526":1509788624992,"1025529070279":1509788624336,"1012572341899":1478686804055,"1012572341901":1478686804055,"1012572341902":1478686804055,"1020836162071":1478686416976,"1025593822885":1509788624440,"1026232415415":1514456869770,"1012572341912":1478686804055,"1025593822905":1509788624429,"1022076648479":1509788624216,"1012572341914":1478686804055,"1012572341915":1478686804055,"1022076648477":1509788624216,"1012572341916":1478686804055,"1012572341917":1478686804055,"1013728608886":1478686804068,"1025285010212":1509788624329,"1012572341918":1478686804055,"1012572341919":1478686804055,"1025593822910":1509788624430,"1013743420229":1478686804048,"1012572341904":1478686804055,"1013728608891":1478686804068,"1025593822897":1509788624430,"1012572341905":1478686804055,"1025593822896":1509788624430,"1012572341906":1478686804055,"1013728608889":1478686804068,"1012572341907":1478686804055,"1013728608888":1478686804068,"1012572341908":1478686804055,"1025285010221":1509788624328,"1012572341911":1478686804055,"1019922840654":1478686804026,"1021928270788":1509788624465,"1021376842404":1478686417042,"1011127906181":1478686804019,"1012572341870":1478686804055,"1019922840646":1478686804026,"790309776":1444487341730,"1022437165666":1478686417071,"1019922840643":1478686804026,"1025593822809":1509788624440,"1025593822811":1509788624427,"1025593822810":1509788624440,"1022084250764":1478686417179,"1025593822814":1509788624430,"1032010010":1478686804024,"1025593822803":1509788624511,"1023932588886":1491634246530,"1025593822804":1509788624509,"1025593822807":1509788624440,"1012572341832":1478686804055,"1025593822825":1509788624430,"1012572341833":1478686804055,"1012572341834":1478686804055,"1025593822827":1509788625005,"1012572341835":1478686804055,"1025593822826":1509788624430,"1012572341836":1478686804055,"1025593822828":1509788624427,"1012572341838":1478686804055,"1012572341839":1478686804055,"1025593822830":1509788624454,"1024280461208":1509788625076,"1012572341826":1478686804055,"1012572341827":1478686804055,"1012572341829":1478686804055,"1021210902698":1465470268195,"1012572341830":1478686804055,"1025593822823":1509788624430,"1012572341831":1478686804055,"1024840276322":1509788624970,"1024280461188":1509788625021,"1025715066168":1509788624197,"1024056191704":1509788624289,"1012572341840":1478686804055,"1024056191703":1509788624289,"1025593822833":1509788624424,"1012572341841":1478686804055,"1025593822832":1509788624438,"1012572341842":1478686804055,"1025593822835":1509788624998,"1012572341843":1478686804055,"1025630521346":1509788624309,"1025593822834":1509788624438,"1012572341844":1478686804055,"1012572341845":1478686804055,"1025593822836":1509788624434,"1012572341846":1478686804055,"1019922840590":1478686804026,"1012572341800":1478686804055,"1012572341801":1478686804055,"1012572341802":1478686804055,"1012572341803":1478686804055,"1019922840586":1478686804026,"1012572341804":1478686804055,"1012572341805":1478686804055,"1025593822732":1509788624511,"1012572341806":1478686804055,"1012572341807":1478686804055,"1025593822734":1509788624509,"1011821285660":1478686804051,"1012572341792":1478686804055,"1012572341793":1478686804055,"1021502411373":1509788624977,"1019922840580":1478686804026,"1011821285662":1478686804051,"1011821285663":1478686804051,"1011821285656":1478686804051,"1020294171238":1465470268295,"1022029197708":1478686417164,"1019922840606":1478686804026,"1019922840607":1478686804026,"1025593822744":1509788624430,"1021356001712":1478686417042,"1019922840604":1478686804026,"1021356001713":1478686417042,"1022086217004":1478686417062,"1021356001719":1478686417042,"1019922840598":1478686804026,"1012572341808":1478686804055,"1012572341809":1478686804055,"1012572341810":1478686804055,"1025593822739":1509788624440,"1025593822738":1509788624440,"1025593822740":1509788624427,"1024840276238":1509788624970,"1025593822742":1509788624430,"1022185569036":1478686417187,"1020294040143":1465470268283,"1025593822760":1509788624455,"1021924469630":1478686417141,"1019922840620":1478686804026,"1019922840621":1478686804026,"1025593822762":1509788624454,"1025593822765":1509788625000,"1025715066218":1509788624431,"1025593822767":1509788625000,"1021384837965":1478686417239,"1025593822766":1509788624424,"1012572341760":1478686804055,"1025593822753":1509788624430,"1008475032008":1478686804030,"1012572341761":1478686804055,"1012572341762":1478686804055,"1012572341763":1478686804055,"1025593822757":1509788624430,"1019922840611":1478686804026,"1019922840608":1478686804026,"1012572341786":1478686804055,"1023580788279":1509788625078,"1019922840635":1478686804026,"1011821285665":1478686804051,"1012572341789":1478686804055,"1012572341790":1478686804055,"1023580788275":1509788625017,"1025593822769":1509788624434,"1025593822768":1509788624426,"1019922840629":1478686804026,"1025715066224":1509788624406,"1021231219698":1478686417235,"1515544405":1491634246505,"1515544406":1491634246505,"165743856":1478686804024,"1021283126477":1478686417004,"1022247896896":1478686417066,"1538875042":1444487341702,"1016831916567":1478686804017,"1016399635408":1480585069069,"1021286403237":1478686417040,"1012125508270":1478686804055,"1012125508268":1478686804055,"1021286403242":1478686417040,"4975701409":1509788624156,"1017363814986":1478686804040,"1021926959674":1478686417142,"1021472526638":1478686417045,"1021472526634":1478686417045,"1024332233553":1509788625086,"1012125508293":1478686804055,"1025431946556":1509788624176,"1025431946555":1509788624176,"1025431946554":1509788624176,"1025431946553":1509788624176,"1025431946552":1509788624176,"1016956437223":1478686804051,"1016956437222":1478686804051,"1016956437221":1478686804051,"1016956437220":1478686804051,"1016956437219":1478686804051,"1016956437218":1478686804051,"1016956437217":1478686804051,"1016956437216":1478686804051,"1016956437215":1478686804051,"1025788465231":1509788624186,"1016956437214":1478686804051,"1016956437213":1478686804051,"1016956437212":1478686804051,"1016956437211":1478686804051,"1021592067625":1478686417114,"1016956437210":1478686804051,"1025788465224":1509788624197,"1025788465223":1509788624203,"1025788465222":1509788624200,"1024840276157":1509788624970,"1020066891051":1465470268308,"1021973362482":1478686417150,"1021645413287":1509788625017,"1021973362480":1478686417150,"1025714803775":1509788624469,"198905429":1491634246512,"1005848179777":1509788624373,"1008550139706":1478686804025,"1020878500968":1509788624934,"1019788227920":1478686804070,"1008058479037":1480585069062,"1019788227921":1478686804070,"1025285010162":1509788624329,"1025285010165":1509788624329,"1018928118175":1509788624368,"1023317722943":1509788624820,"1025285010172":1509788624329,"1019788227904":1478686804070,"1019788227905":1478686804070,"1019788227906":1478686804070,"1019788227907":1478686804070,"1019788227908":1478686804070,"1012287255643":1478686416994,"1019788227909":1478686804070,"1019788227910":1478686804070,"1019788227911":1478686804070,"1025285010150":1509788624329,"1019788227912":1478686804070,"1023382078212":1509788625084,"1025285010156":1509788624329,"1019788227919":1478686804070,"1019788227888":1478686804070,"1019788227889":1478686804070,"1021244982238":1478686417039,"1019788227890":1478686804070,"1021817252899":1478686417053,"1019788227891":1478686804070,"1019788227892":1478686804070,"1019788227896":1478686804070,"1019788227897":1478686804070,"1019788227898":1478686804070,"1019788227899":1478686804070,"1025593822978":1509788624440,"1019788227900":1478686804070,"1022487369181":1478943089489,"1019788227901":1478686804070,"1019788227902":1478686804070,"1019788227903":1478686804070,"1019788227872":1478686804070,"1019788227873":1478686804070,"1025593823000":1509788624430,"1023317722946":1509788624820,"1019788227874":1478686804070,"1019788227875":1478686804070,"1019788227876":1478686804070,"1019788227877":1478686804070,"1019788227878":1478686804070,"1025593823007":1509788624430,"1019788227879":1478686804070,"1021985945134":1478686417153,"1019788227880":1478686804070,"1025593822993":1509788624440,"1019788227881":1478686804070,"1019788227882":1478686804070,"1025593822995":1509788624440,"1022297047186":1478686417287,"1019788227883":1478686804070,"1019788227884":1478686804070,"1025593822997":1509788624440,"1019788227885":1478686804070,"1019788227886":1478686804070,"1025593822999":1509788624427,"1019788227887":1478686804070,"1019788227856":1478686804070,"1019788227857":1478686804070,"1012357902385":1509788625080,"1019788227858":1478686804070,"1025593823019":1509788624826,"1019788227859":1478686804070,"1025593823018":1509788624455,"1019788227860":1478686804070,"1025593823021":1509788624454,"1019788227861":1478686804070,"1019788227862":1478686804070,"1025593823023":1509788624437,"1019788227863":1478686804070,"1025593823022":1509788624440,"1019788227864":1478686804070,"1025593823009":1509788624430,"1019788227865":1478686804070,"1019788227866":1478686804070,"1019788227867":1478686804070,"1019788227868":1478686804070,"1020850711153":1478686804057,"1019788227869":1478686804070,"1019788227870":1478686804070,"1019788227871":1478686804070,"1025593823014":1509788624429,"1019788227840":1478686804070,"1019788227841":1478686804070,"1019788227842":1478686804070,"1025714803777":1509788624469,"1019788227843":1478686804070,"1025909709286":1509788667461,"1019788227844":1478686804070,"1025714803783":1509788624469,"1025714803782":1509788624469,"1019788227846":1478686804070,"1019788227847":1478686804070,"1025714803780":1509788624469,"1019788227848":1478686804070,"1019788227849":1478686804070,"1019788227850":1478686804070,"1025714803785":1509788624469,"1025593823027":1509788624846,"1019788227851":1478686804070,"1025714803784":1509788624469,"1025593823026":1509788624822,"1019788227852":1478686804070,"1025593823029":1509788624434,"1019788227853":1478686804070,"1025593823028":1509788624824,"1019788227854":1478686804070,"1023042467589":1509788625073,"1019788227855":1478686804070,"1025164031591":1509788624327,"1022052790762":1478686804045,"1022052790763":1478686804045,"1025593822424":1509788625243,"1022052790760":1478686804045,"1022052790761":1478686804045,"1022052790766":1478686804045,"1025593822429":1509788625141,"1022052790767":1478686804045,"1025593822428":1509788625141,"1022052790764":1478686804045,"1025593822431":1509788625143,"1022052790765":1478686804045,"1022052790754":1478686804045,"1022052790755":1478686804045,"1022052790752":1478686804045,"1022052790753":1478686804045,"1022052790758":1478686804045,"1022052790759":1478686804045,"1022052790756":1478686804045,"1025593822423":1509788625245,"1022052790757":1478686804045,"1025593822441":1509788625122,"1024667784250":1509788625220,"1024667784248":1509788625220,"1022052790750":1478686804045,"1024667784255":1509788625220,"1022052790751":1478686804045,"1024667784254":1509788625220,"1022052790748":1478686804045,"1022052790749":1478686804045,"1025593822446":1509788625121,"1024667784252":1509788625220,"1024667784241":1509788625220,"1025593822437":1509788625112,"1024667784247":1509788625220,"1024667784239":1509788625220,"1015102132":1444487341754,"1025593822462":1509788625168,"1025593822451":1509788625121,"1020102673419":1509788624353,"1022203332287":1478686417013,"1024667784280":1509788625220,"1021428094832":1478686804026,"1024667784275":1509788625220,"1023220595222":1509788624434,"1024667784272":1509788625220,"1025593822341":1509788625141,"1020118402408":1509788624299,"1024667784277":1509788625220,"1024667784266":1509788625220,"1024667784265":1509788625220,"1024667784264":1509788625220,"1025630915303":1509788624373,"1024667784270":1509788625220,"1025593822367":1509788625122,"1024667784268":1509788625220,"1024667784258":1509788625220,"1019061289598":1478686804022,"1024667784256":1509788625220,"1018567533035":1478686804032,"1024667784261":1509788625220,"1021257957637":1465470268198,"1016539490506":1478686804023,"1025593822380":1509788625143,"1023442243439":1509788625082,"777857072":1444487341740,"1000920386821":1478686417219,"1025593822375":1509788625169,"1022461020656":1478686417016,"1025593822387":1509788625110,"1025593822386":1509788625140,"1025593822389":1509788625129,"1021166339281":1465470268184,"1022039683295":1478686417169,"1025756091712":1509788624958,"1021646198967":1509788624974,"1025593822283":1509788624202,"1021646198964":1509788624974,"1007618202833":1509788624986,"1021646198962":1509788624974,"1024667784350":1509788625207,"1024912107501":1509788624926,"1025593822273":1509788624203,"1021663369604":1509788624616,"1021646198974":1509788624974,"1024667784339":1509788625207,"1024667784338":1509788625208,"1025593822275":1509788624202,"1021646198972":1509788624974,"1024667784336":1509788625208,"1021646198968":1509788624974,"1024667784341":1509788625207,"1022076649185":1509788624850,"1025470612657":1509788625016,"1025593822296":1509788624229,"1024667784330":1509788625208,"1021744767684":1478686417126,"1025593822298":1509788625136,"1024667784328":1509788625208,"1024667784334":1509788625208,"1022184519819":1478686417187,"1025593822302":1509788624213,"1021646198958":1509788624974,"1024667784323":1509788625208,"1022067995019":1478686804035,"1024667784321":1509788625207,"1022067995017":1478686804035,"1025593822290":1509788624202,"1021646198957":1509788624974,"1025593822292":1509788624203,"1025069264016":1509788625019,"1022067995020":1478686804035,"1020066891467":1465470268308,"1021646198953":1509788624974,"1025291566701":1509788624948,"1019061289600":1478686804022,"1025608240457":1509788624915,"1019930312415":1509788624390,"1024667784371":1509788625207,"1024667784369":1509788625208,"1021757088567":1509788624395,"1024667784374":1509788625208,"1021288239046":1478686417101,"1024997302488":1509788625020,"1025593822329":1509788625246,"1024667784362":1509788625207,"1025593822332":1509788625243,"1024667784365":1509788625207,"1024667784353":1509788625207,"1024667784359":1509788625207,"1024667784358":1509788625207,"1024667784356":1509788625207,"1024363169506":1509788624927,"1025608240431":1509788624822,"1025593822221":1509788624203,"1022249731324":1478686417284,"1004158175839":1478686804052,"1025593822232":1509788624197,"1025593822234":1509788624198,"1025608240437":1509788624837,"1025593822227":1509788624199,"1025593822226":1509788624230,"1025608240434":1509788624835,"1025593822253":1509788624269,"1025593822252":1509788624270,"1025593822254":1509788624214,"1021410006721":1478686417043,"1004158175844":1478686804052,"1016709758593":1478686804023,"1025593822269":1509788624203,"1004158175841":1478686804052,"1004158175842":1478686804052,"1021646198976":1509788624974,"1004158175843":1478686804052,"1025453836246":1509788624945,"1021693519801":1478686804033,"1025593822256":1509788624214,"1012572341736":1478686804055,"1024667784475":1509788625208,"1012572341738":1478686804055,"1025593822667":1509788624509,"1024667784473":1509788625208,"1012572341739":1478686804055,"1025593822666":1509788624511,"1024667784472":1509788625208,"1012572341740":1478686804055,"1024667784479":1509788625208,"1012572341741":1478686804055,"1012572341742":1478686804055,"1024667784477":1509788625208,"1024667784476":1509788625208,"1023317722523":1509788624518,"1021484716765":1509788624398,"1024667784470":1509788625209,"1024667784468":1509788625208,"1012572341752":1478686804055,"1012572341753":1478686804055,"1022273455040":1509788624268,"1025593822680":1509788624430,"1012572341754":1478686804055,"1024785882629":1509788624250,"1012572341757":1478686804055,"1012572341758":1478686804055,"1025593822687":1509788624430,"1024667784460":1509788625209,"1012572341744":1478686804055,"1024667784451":1509788625208,"1012572341746":1478686804055,"1012572341748":1478686804055,"1012572341750":1478686804055,"1012572341751":1478686804055,"1024667784452":1509788625209,"1021592722535":1478686417048,"1022395878471":1478686417070,"1952019327":1458304307281,"1025593822702":1509788624440,"1952019313":1458304307281,"1024667784499":1509788625209,"1025593822691":1509788624430,"1024667784497":1509788625208,"1025593822692":1509788624430,"1024954573773":1509788624923,"1024667784501":1509788625209,"1022395878474":1478686417070,"1024667784500":1509788625208,"1024667784488":1509788625208,"1024112817722":1509788624325,"1024667784492":1509788625208,"1025593822705":1509788624438,"1022383033616":1478686417069,"1025593822704":1509788624424,"1024667784482":1509788625208,"1024667784487":1509788625208,"1024667784484":1509788625208,"1020726456228":1480585069079,"1009893058042":1491634246523,"1024248348250":1495284743421,"1023527831717":1509788624325,"1016474611001":1478686804016,"1022032998987":1478686417267,"1025593822617":1509788625143,"1023605822486":1509788624551,"1843751600":1444487341724,"1014811934779":1478686804018,"1025593822611":1509788625246,"1025593822612":1509788625243,"1025593822615":1509788625141,"1021257826360":1478686417237,"1022076649226":1509788624850,"1022076649225":1509788624850,"1025593822624":1509788625121,"170724679":1491634246515,"1007159834877":1478686804030,"1025593822650":1509788625139,"1022076649243":1509788624850,"1021960254985":1509788624464,"1022044533003":1509788625066,"1025593822536":1509788625243,"1025593822540":1509788625141,"1025593822533":1509788625245,"542713805":1478686417020,"4786297567":1509788624153,"1843751548":1444487341727,"1025050914494":1509788624232,"1025593822548":1509788625141,"1019720330076":1509788624313,"1025593822568":1509788625121,"1025593822571":1509788625120,"1025593822570":1509788625122,"1016530447015":1478686804056,"1025593822573":1509788625120,"1016530447014":1478686804056,"1016530447013":1478686804056,"1016530447019":1478686804056,"1016530447018":1478686804056,"1016530447017":1478686804056,"1016530447016":1478686804056,"1016530447023":1478686804056,"1016530447022":1478686804056,"1023319819742":1509788624288,"1016530447021":1478686804056,"1025593822567":1509788625121,"1016530447020":1478686804056,"1022631550678":1480585069131,"1025593822566":1509788625121,"1016530447027":1478686804056,"1025593822585":1509788625139,"1016530447026":1478686804056,"1025593822584":1509788625105,"1016530447025":1478686804056,"1016530447024":1478686804056,"1021958420013":1478686417147,"1020826069677":1478686417226,"1021729301659":1509788624986,"1025593822576":1509788625168,"1025593822581":1509788625143,"1025042919038":1509788624498,"1025593822465":1509788625167,"1001660690562":1478686417024,"1021428225787":1509788624827,"1025593822466":1509788625143,"1025593822468":1509788625136,"1025628162828":1509788624186,"1022185568312":1478686417187,"1025628162825":1509788624204,"1025628162824":1509788624200,"1025628162827":1509788624198,"1952019330":1458304307281,"1952019334":1458304307281,"1025593822486":1509788625139,"1059403983":1444487341746,"1021049683018":1478686417001,"1024937403397":1509788625006,"1021513814506":1478686417244,"1021523775633":1509788624398,"1022081368019":1478686417012,"1021811224481":1478686417131,"1022368616186":1478686417069,"1022471117032":1478686417219,"1025593426635":1509788624435,"1022471117036":1478686417219,"1022073368756":1478686417176,"1025593426631":1509788624435,"1022897889684":1509788624419,"1025593426626":1509788624435,"1025593426624":1509788624435,"270735411":1444487341741,"1025365488757":1509788624186,"1023031982473":1509788624610,"1025365488753":1509788624201,"1023031982479":1509788624610,"1025365488755":1509788624198,"1025365488754":1509788624205,"1025593426647":1509788624434,"1025593426646":1509788624424,"1012550846538":1478686416977,"1025593426644":1509788624454,"1025593426642":1509788624427,"1025593426641":1509788624455,"1022471117046":1478686417219,"1025529597591":1509788624336,"1021403846825":1478686417043,"4561504212":1465469681389,"1020917693364":1478686417081,"1021982145076":1509788625068,"1025593426678":1509788624564,"1025593426674":1509788624565,"1025593426673":1509788624611,"1025593426672":1509788624611,"1025593426573":1509788624436,"1022245538360":1478686417014,"1021959993633":1478686417147,"1023031982552":1509788625084,"1025593426571":1509788624436,"1023031982558":1509788625084,"1025593426565":1509788624436,"1025593426563":1509788624436,"1025593426589":1509788624454,"1022129337113":1478686417184,"1025593426586":1509788624427,"1025593426585":1509788624455,"1025505610845":1509788624933,"1020653054739":1478686417028,"1025569439754":1509788624352,"1025593426582":1509788624436,"1021872563439":1478686417136,"1025593426580":1509788624436,"1025627636888":1509788624431,"1021926958884":1478686417141,"1025593426576":1509788624436,"1021914244702":1509788625142,"4994834896":1509788667392,"1022112821814":1478686417013,"1024794268385":1509788624427,"1025593426622":1509788624435,"1025593426619":1509788624440,"1021849100906":1509788624561,"1021849100904":1509788624561,"1021849100902":1509788624561,"1025593426614":1509788624452,"1021849100903":1509788624561,"209782011":1444487341752,"1022489074061":1478943089489,"1025593426613":1509788624509,"1025593426611":1509788624509,"1021959993631":1478686417147,"1020938665155":1478686417084,"1024887072879":1509788625004,"1021395978129":1478686417106,"1019608001824":1509788625078,"1021395978123":1478686417106,"1025365488893":1509788625109,"1025365488892":1509788625126,"1018928116910":1509788624368,"1025365488895":1509788625089,"1025365488891":1509788625117,"1020938665186":1478686417084,"1025593426543":1509788624452,"1025365488837":1509788624524,"1025593426539":1509788624509,"1025365488833":1509788624541,"1025365488835":1509788624537,"1518031580":1444487341735,"1025365488834":1509788624543,"1025593426533":1509788624509,"1021995645934":1509788624426,"1021743983852":1509788624403,"1025508101463":1509788624346,"1025508101462":1509788624343,"1025593426554":1509788624440,"1025593426550":1509788624451,"1000307814063":1478686417018,"1021592720378":1478686417048,"1025593426545":1509788624452,"1021964057057":1478686417010,"1025593426444":1509788624270,"1022897889631":1509788624193,"1025593426440":1509788624269,"1024462392977":1509788624855,"1021937842201":1478686804072,"1024462392976":1509788624855,"1021937842202":1478686804072,"1024462392978":1509788624855,"1025593426462":1509788624215,"1024462392975":1509788624855,"1024462392974":1509788624855,"1021849100999":1509788624221,"1021849100996":1509788624221,"1025593426452":1509788624228,"1021849100994":1509788624221,"1021849100995":1509788624221,"1013139762142":1478686804027,"1025593426473":1509788624210,"1025593426470":1509788624210,"4994834778":1509788667392,"1025593426466":1509788624215,"1021354558842":1465470268232,"1025365488789":1509788624426,"1025365488788":1509788624432,"1021937842212":1478686804072,"1025593426491":1509788624229,"1021937842213":1478686804072,"1025365488787":1509788624429,"1021937842216":1478686804072,"1018850652205":1509788625079,"1025593426483":1509788624210,"1025365488792":1509788624408,"1018850652203":1509788625079,"1025593426481":1509788624210,"1025593426480":1509788624210,"1025628554710":1509788624435,"1025628554709":1509788624435,"1025100326231":1509788624273,"1025100326230":1509788624273,"1025100326229":1509788624273,"1025593426889":1509788624864,"1025628554704":1509788624440,"1025593426887":1509788624865,"1021279584486":1478686417040,"1025593426885":1509788624865,"1025100326232":1509788624273,"1691053509":1509788624374,"1025593426881":1509788624916,"1025593426906":1509788624841,"1025628554702":1509788624451,"1025593426901":1509788624840,"1025593426897":1509788624841,"1023970205841":1509788625037,"1021234368386":1478686417235,"1021849101118":1509788624859,"1025628554742":1509788624863,"1025593426925":1509788624841,"1021849101114":1509788624859,"1021849101115":1509788624859,"1021849101112":1509788624859,"1020653972086":1478686804057,"1025593426914":1509788624841,"1021234368397":1478686417235,"1025902499148":1509788667462,"1020817286315":1478686417078,"1021890782389":1478686417300,"1025593426935":1509788624866,"1022008753571":1509788624426,"1025593426932":1509788624868,"1025630913933":1509788624371,"1025365488933":1509788624834,"1025365488932":1509788624829,"1025365488934":1509788624824,"1022067998298":1478686804035,"1022293904592":1478686417068,"1022067998299":1478686804035,"1024132348588":1509788624324,"1025593426821":1509788624907,"1025593426820":1509788624907,"1022067998302":1478686804035,"1025593426819":1509788624907,"1020668128559":1478686417028,"1025365488936":1509788624800,"1025593426818":1509788624907,"1025593426817":1509788624908,"1025593426816":1509788624907,"1022008753610":1509788624427,"1024132348592":1509788624324,"1021982145370":1478686417263,"1022008753613":1509788624456,"1024132348605":1509788624324,"1024132348606":1509788624324,"1012970672246":1480585069077,"1024132348601":1509788624324,"1024132348600":1509788624324,"1024132348602":1509788624324,"1025628554673":1509788624440,"1025628554672":1509788624451,"1014840115373":1478686804028,"1023745675873":1509788624517,"1021354296553":1465470268230,"1025593426878":1509788624916,"1022067998304":1478686804035,"1021729565261":1509788624533,"1021550514352":1478686417245,"1025100326355":1509788624173,"1025593426767":1509788624455,"1025100326353":1509788624172,"1025593426765":1509788624435,"1024730570718":1509788624923,"1021988960802":1478686417264,"1025100326357":1509788624173,"1025100326356":1509788624173,"1025593426756":1509788624435,"1021023465694":1478686417091,"1021715016585":1509788624426,"1022046240710":1478686804047,"1023820785935":1491634246535,"1025593426774":1509788624434,"1025593426771":1509788624424,"1025593426770":1509788624454,"1025593426768":1509788624427,"1025593426799":1509788624908,"1025593426798":1509788624908,"1025593426797":1509788624907,"1024730570751":1509788624924,"1021261762229":1478686804026,"1024576292038":1509788667504,"1021356393682":1465469681398,"1025593426815":1509788624907,"1024730570732":1509788624923,"1025593426813":1509788624907,"1025593426812":1509788624907,"1024730570734":1509788624923,"1025593426811":1509788624907,"1025593426810":1509788624907,"1024730570728":1509788624923,"1025593426809":1509788624907,"1024730570731":1509788624923,"1024730570730":1509788624923,"1025593426807":1509788624907,"1024730570725":1509788624923,"1021928007411":1509788624461,"1025593426806":1509788624907,"1018899149384":1509788624367,"1025593426805":1509788624907,"1025593426804":1509788624907,"1024730570726":1509788624923,"1025593426802":1509788624907,"1024730570720":1509788624924,"1025593426801":1509788624907,"1025593426800":1509788624907,"1024730570722":1509788624924,"1025593426701":1509788624566,"1019533158854":1509788625079,"1025593426696":1509788624547,"1025507970095":1509788624339,"1025593426694":1509788624547,"1025507970092":1509788624340,"1025507970091":1509788624343,"1022071795992":1509788624945,"1025593426690":1509788624547,"1024928885690":1509788667497,"1025378333810":1509788624304,"1023798367769":1509788624444,"1024928885695":1509788667497,"1023798367771":1509788624444,"1024928885693":1509788667496,"1025507970096":1509788624338,"1023798367770":1509788624444,"1024928885692":1509788667497,"1013940165310":1478686804030,"1025593426710":1509788624544,"1024928885682":1509788667497,"1023798367767":1509788624444,"1024928885681":1509788667497,"1025593426708":1509788624536,"1021234368383":1478686417235,"1024928885685":1509788667496,"1025593426704":1509788624539,"1021624702110":1478686417117,"1025593426735":1509788624509,"1025593426731":1509788624509,"1007134405871":1509788624373,"1021234368331":1478686417235,"1019177943739":1509788624314,"1020974317519":1478686417034,"1023798367776":1509788624444,"1012178068358":1478686417025,"1021234368339":1478686417235,"1025593426749":1509788624436,"1020294170459":1465470268295,"1025593426748":1509788624440,"1024928885656":1509788667496,"1021234368340":1478686417235,"1025593426744":1509788624440,"1024928885660":1509788667497,"1013146316075":1478686804027,"1025593426742":1509788624451,"1021151397962":1509788624931,"1024928885649":1509788667496,"1025593426740":1509788624452,"1025593426739":1509788624452,"1024928885655":1509788667496,"1021151397966":1509788624920,"1025862389958":1509788667578,"1021513817112":1478686417244,"4994835381":1509788667392,"1025862389956":1509788667578,"1025862389955":1509788667578,"1025702484554":1509788624545,"1025862389954":1509788667578,"1023730864629":1509788624960,"1023730864628":1509788624960,"1021862863136":1478686417257,"1025792007952":1509788624419,"1022241605822":1509788624920,"1024056059037":1509788624928,"1025862389961":1509788667578,"1025862389960":1509788667578,"1022022385596":1478686417266,"1023821441659":1491634246536,"1021183642047":1478686417098,"1020076592060":1480585069142,"1021726681431":1478686417123,"1023730864622":1509788624960,"1025702484561":1509788624545,"1025702484560":1509788624545,"1022711764115":1509788624465,"1022633382778":1509788625074,"1021581578688":1478686804045,"1021581578689":1478686804045,"1021413546559":1509788624406,"1021052170668":1478686804038,"1022029201265":1478686417164,"1025276100074":1509788625017,"1021052170666":1478686804038,"1021052170667":1478686804038,"1021052170664":1478686804038,"1021739265725":1478686417252,"1021052170665":1478686804038,"1021052170662":1478686804038,"1021052170663":1478686804038,"1021052170660":1478686804038,"1021052170661":1478686804038,"1022332570903":1509788624277,"1021341582944":1509788624180,"1021325066512":1465470268214,"673129043":1444487341745,"1021729565042":1509788624194,"1019720591029":1509788624312,"1021325066507":1465470268213,"1021581578685":1478686804045,"1021581578686":1478686804045,"1025601945631":1509788624309,"1021581578687":1478686804045,"1021581578680":1478686804045,"1021325066511":1465470268214,"1021581578681":1478686804045,"1021325066508":1465470268213,"1021581578682":1478686804045,"1021325066509":1465470268213,"1021581578683":1478686804045,"1021581578676":1478686804045,"1018546564270":1480585069070,"1021581578677":1478686804045,"1021581578678":1478686804045,"1021581578679":1478686804045,"1021581578672":1478686804045,"1021581578673":1478686804045,"1021581578674":1478686804045,"1021581578675":1478686804045,"1025100326449":1509788624181,"1025100326448":1509788624181,"1025702484522":1509788624612,"1016877926435":1478686804019,"1025792008051":1509788624419,"1025702484543":1509788624539,"1021641217040":1509788624818,"1025702484535":1509788624565,"1025702484532":1509788624611,"1023808591146":1509788625071,"1025100326447":1509788624181,"1021577252911":1478686416985,"1025100326445":1509788624181,"1025628554838":1509788624526,"1022223911716":1509788624938,"1020294169642":1465470268295,"1025628554836":1509788624526,"1025628554835":1509788624526,"1025628554834":1509788624526,"1025628554833":1509788624526,"1025628554832":1509788624526,"1025628554823":1509788624526,"1022185567613":1478686417187,"1025628554821":1509788624526,"1025628554820":1509788624526,"1025628554819":1509788624526,"1021259271603":1478686417040,"1025628554831":1509788624526,"4646706799":1478881022010,"1022037851202":1478686417058,"1025628554827":1509788624526,"1021459814906":1478686417108,"1024555058812":1509788624928,"4563999420":1465469681387,"1021959076824":1478686417261,"1022486321856":1478943089532,"1019971596590":1509788624369,"1020600756911":1478686417027,"1023820786270":1491634246535,"1025711921940":1509788624345,"1022837600252":1509788625074,"1025792008151":1509788624419,"1025628554759":1509788624840,"4994835299":1509788667392,"1020600756912":1478686417027,"1016682101964":1465470268314,"1025628554763":1509788624866,"1025628554761":1509788624840,"1025628554760":1509788624840,"1021263069703":1478686417237,"1025628554791":1509788624199,"1025628554789":1509788624227,"1023031982953":1509788624507,"1022093554587":1478686417274,"1025628554788":1509788624227,"1025628554787":1509788624227,"1022093554589":1478686417274,"1102924616":1509788625019,"1023031982946":1509788624507,"1025628554797":1509788624211,"1025628554796":1509788624209,"1023317723247":1509788624535,"1025628554794":1509788624209,"1023317723246":1509788624535,"1025628554793":1509788624209,"1021782650133":1509788624214,"1023820786585":1491634246535,"1022453286155":1478686417215,"1022371234286":1478686417069,"4981597174":1509788624154,"1023031982720":1509788624915,"1013095328484":1478686417023,"1350785967":1444487341751,"1021483540214":1478686417110,"1020596562837":1478686417027,"1023387061572":1509788625040,"1023087427348":1509788624987,"1022074549170":1509788624507,"1021379331361":1478686804026,"1020167687446":1509788625077,"1023946353752":1491634246531,"1021236465099":1478686417003,"1023946353751":1491634246531,"1023946353750":1491634246531,"1021893666341":1478686417138,"1022464951325":1478686417298,"1006207585579":1478686804052,"4910821337":1509788624155,"1019310331967":1509788624313,"1018928117580":1509788624368,"1021613299571":1478686417116,"4994835146":1509788667392,"1021381690503":1478686417042,"1011826794233":1509788624945,"1023820786448":1491634246535,"1024120420657":1509788667495,"1023087427470":1509788624987,"1022754368418":1509788624185,"4981596996":1509788624154,"1019365514670":1509788624315,"1022066949298":1478686417271,"1020891085441":1478686417032,"1019365514672":1509788625081,"1024112818866":1509788624325,"1024161710053":1509788667562,"1021714360769":1478686417300,"1021782650331":1509788624229,"1021641217459":1509788624420,"1022957135812":1509788624509,"1021160966874":1478686417097,"1021094770382":1478686417232,"1022460757094":1480585069076,"1020956884682":1478686417033,"1020677959215":1478686417028,"1023031982706":1509788624915,"1019029572066":1509788624314,"1022340301630":1478686417069,"4994835035":1509788667392,"1021729564880":1509788624815,"1022377787766":1478686417069,"1020850316402":1509788624940,"1020605344709":1478686417075,"1016566758647":1478686804042,"1016566758653":1478686804042,"1016566758652":1478686804042,"1016566758655":1478686804042,"1000526182626":1444487341713,"1016566758654":1478686804042,"1016566758648":1478686804042,"1016566758651":1478686804042,"1016566758650":1478686804042,"1021932462869":1478686417142,"1017020794833":1478686804046,"1021961567580":1509788624464,"1024020668565":1509788624378,"1024020668566":1509788624378,"1022038506228":1478686417058,"393419605":1444487341717,"168363566":1444487341722,"1021646066204":1509788625084,"1021882916898":1478686416986,"1022226795937":1478686417065,"1023173276979":1509788625083,"1024020668609":1509788624378,"1024020668608":1509788624378,"1024020668610":1509788624378,"1000526182585":1444487341713,"1025164033078":1509788624327,"1009158978052":1478686804030,"1024244544820":1509788624949,"1024887860383":1509788625023,"1025507182709":1509788624338,"1025507182708":1509788624336,"1024453741233":1509788625030,"1024020668660":1509788624378,"1018923397127":1509788625019,"1020339919982":1465470268324,"1020339919983":1465470268324,"1024020668659":1509788624378,"1020339919981":1465470268324,"1011826792952":1509788624945,"1021685919062":1478686417249,"1583436526":1491634246510,"124062711":1444487341743,"1021719998270":1509788624919,"1025810094967":1509788667448,"1021719998271":1509788624918,"1021719998266":1509788624918,"1021719998267":1509788624919,"1018311283812":1478686804031,"1021695749512":1478686804071,"1025507445084":1509788624341,"1024020668473":1509788624378,"1024020668472":1509788624378,"1025507445080":1509788624344,"1024954574939":1509788624924,"1024020668471":1509788624378,"1024020668470":1509788624378,"1025507445075":1509788624340,"1021498219098":1478686417112,"1023820786729":1491634246535,"1024146767798":1509788625071,"1350786117":1444487341741,"1021675039926":1478686416980,"1016399636992":1480585069069,"1021719998307":1509788624918,"1021719998285":1509788624918,"1021719998286":1509788624918,"1019192885422":1509788624971,"1022138904631":1478686417184,"1025505609960":1509788624972,"1021719998281":1509788624918,"1021719998282":1509788624918,"1021719998283":1509788624918,"1024020668517":1509788624378,"1021719998276":1509788624918,"1024020668516":1509788624378,"1021719998277":1509788624919,"1021719998278":1509788624918,"1021719998279":1509788624918,"1021719998272":1509788624919,"1024020668515":1509788624378,"1025627766834":1509788624540,"1021719998301":1509788624918,"1021719998297":1509788624919,"1025497483376":1509788624367,"1025627766836":1509788624542,"1025627766840":1509788624523,"1021719998288":1509788624919,"1022385129206":1478686417290,"1021719998291":1509788624918,"1025285012048":1509788624329,"1025285012051":1509788624328,"1025285012050":1509788624328,"1025285012053":1509788624328,"1024686922226":1509788625160,"1022240690083":1478686417283,"1024686922224":1509788625160,"1025285012057":1509788624327,"1025285012059":1509788624328,"1025285012058":1509788624327,"1022304521211":1478686417068,"1025285012060":1509788624328,"1017177037210":1478686804016,"1024510755943":1509788667830,"1024056058756":1509788624928,"1665101352":1444487341708,"1024686922222":1509788625160,"1024686922221":1509788625160,"1021785926361":1509788625020,"1025285012045":1509788624329,"1024686922219":1509788625160,"1025515702449":1509788624344,"1024687446508":1509788624534,"1022060132943":1478686417012,"1025285012065":1509788624329,"1025285012067":1509788624329,"4994835588":1509788667392,"1025285012071":1509788624329,"1025285012073":1509788624329,"1025609287360":1509788625107,"1025609287362":1509788625088,"1024670015161":1509788625025,"1025609287358":1509788625116,"1020855689749":1478686416978,"1020855689753":1478686416978,"1020855689755":1478686416978,"1020855689756":1478686416978,"1021362946119":1509788624394,"4994835683":1509788667392,"1020878372003":1509788624934,"1022258253525":1478686417067,"1025711791278":1509788624346,"1007588054390":1478686804032,"1008238572076":1478686804018,"1021740837348":1478686417125,"777855776":1444487341738,"4994835509":1509788667392,"1022125274626":1478686417276,"1012152902754":1478686417025,"1018928116158":1509788624368,"1001519653440":1478686417022,"1024487556426":1509788624920,"1022316579747":1478686417200,"1022879147286":1509788624558,"1019195244938":1480585069068,"1022879147285":1509788624558,"1019477971158":1478686804021,"1021824984266":1509788624394,"1022879147283":1509788624558,"1022879147281":1509788624558,"1019833974685":1478686804021,"1025042916369":1509788624498,"1022879147289":1509788624558,"4564000167":1465469681389,"1022102468436":1478686416976,"1021953571961":1478686417146,"1024112819380":1509788624325,"1021574240192":1509788624397,"1021681593823":1478686417249,"1023031983184":1509788625020,"1000307813339":1478686417018,"1023031983176":1509788625020,"4890373793":1509788624155,"1020710464038":1478686416996,"168364008":1444487341726,"1022341350726":1509788624291,"1024487556413":1509788624920,"1021797722859":1478686417255,"1024487556412":1509788624920,"1022341350723":1509788624290,"1022425759829":1478686417210,"1022341350733":1509788624290,"1022341350735":1509788624290,"1022086476831":1478686417062,"1022341350734":1509788624290,"1022425759825":1478686417210,"1022341350728":1509788624291,"255001309":1444487341747,"1022425759827":1478686417210,"1022341350731":1509788624290,"1022341350741":1509788624290,"1022341350743":1509788624291,"1022341350737":1509788624290,"1022341350736":1509788624290,"1022341350739":1509788624290,"1022341350738":1509788624290,"1021044045792":1478686417036,"1022219717657":1478686417192,"1020438222902":1478686804046,"1025593427148":1509788624210,"1022072714926":1478686417176,"1024686922483":1509788624223,"1025593427144":1509788624210,"1012034023169":1509788624929,"1021350757338":1509788624843,"1022072714915":1478686417176,"1020966844602":1478686417086,"1020469155412":1509788625077,"1025593427140":1509788624209,"1025593427139":1509788624209,"1025593427137":1509788624215,"1025593427136":1509788624227,"1024686922469":1509788624223,"1024686922468":1509788624223,"1024686922467":1509788624223,"1025593427160":1509788624197,"1025593427159":1509788624229,"1025593427157":1509788624230,"1022091851677":1478686417273,"1009893059736":1491634246520,"1022037588193":1478686417058,"1019782455563":1509788624312,"1020963305708":1478686417229,"1025902760533":1509788667449,"1024686922459":1509788624223,"1021833111358":1509788624815,"1020294168709":1465470268295,"1009893059733":1491634246520,"1025052616484":1509788667843,"4981597916":1509788624153,"1022041520309":1478686417058,"1019941582744":1509788624320,"1019941582745":1509788624320,"1019941582746":1509788624320,"1024056058023":1509788624928,"1019941582747":1509788624320,"1016399636726":1480585069069,"1021886981091":1478686804027,"1008664303556":1478686804030,"1019782455573":1509788624313,"1020984932828":1478686417230,"1022089754594":1478686417273,"1025593427083":1509788624227,"1021833111380":1509788624193,"1025593427079":1509788624228,"1021602550500":1509788624420,"1025593427078":1509788624270,"1025593427077":1509788624269,"1024342716725":1509788625070,"1021143010912":1478686417096,"1025593427100":1509788624209,"1022416323192":1478686417292,"1025593427098":1509788624209,"1020047487274":1509788625076,"1025593427096":1509788624210,"1024984984420":1509788624279,"1020047487275":1509788625076,"1022464950559":1478686417218,"1025593427095":1509788624210,"1020047487260":1509788625078,"1020047487261":1509788625077,"1021768362157":1478686417052,"1020047487263":1509788625076,"1020047487256":1509788625076,"1020047487257":1509788625076,"1025593427112":1509788624229,"1012171908258":1478686416992,"1025593427107":1509788624199,"1021925515521":1478686417054,"1021143010910":1478686417096,"1023106825066":1509788624269,"1024687446688":1509788625102,"1025593427135":1509788624228,"1025593427133":1509788624270,"1025593427131":1509788624269,"1025050912604":1509788624568,"1022319987089":1478686417068,"1021768362165":1478686417052,"1025593427020":1509788624210,"1025593427019":1509788624210,"1025068475581":1509788625223,"1001519653205":1478686417022,"1022928037160":1509788624300,"1025593427017":1509788624210,"1024112820104":1509788624325,"1025593427015":1509788624215,"1025593427013":1509788624215,"1009997522668":1491634246520,"1025593427039":1509788624229,"1021599011447":1478686417048,"1025593427037":1509788624199,"1025593427035":1509788624230,"1021646065825":1509788625084,"1025593427033":1509788624210,"1019941582644":1509788624319,"1025414508803":1509788624294,"1019941582646":1509788624319,"1025593427042":1509788624206,"1025593427040":1509788624197,"860962188":1491634246514,"1025593426990":1509788624270,"1025593426989":1509788624269,"1009015317503":1478686804054,"1024687446565":1509788624195,"1020439795957":1465470268312,"1022228238220":1478686417192,"1025593427007":1509788624227,"1025593427005":1509788624228,"1021561657290":1478686804040,"4981597723":1509788624153,"1022632859582":1509788625061,"1020587774422":1478686417027,"1023017827980":1509788624509,"1021480131359":1478686417243,"1024056189285":1509788624289,"1022330341446":1478686417201,"1024056189283":1509788624289,"1022447649090":1478686804027,"1024056189280":1509788624289,"1021749357305":1478686417126,"1022098535975":1478686417063,"1020896460262":1478686417032,"1021886980857":1478686804027,"1020444776694":1478686417026,"1024056189258":1509788624289,"1018905703494":1509788624311,"1024056189254":1509788624289,"1020391824341":1478686804033,"1023262798058":1509788625041,"1024056189274":1509788624289,"1022044010820":1509788625066,"1021260580875":1465470268200,"1021480131361":1478686417243,"1022020025076":1478686417161,"1024056189269":1509788624289,"1021480131363":1478686417243,"1020806144795":1478686417077,"1021764692550":1478686417052,"1024686922677":1509788624448,"1012145956660":1478686417073,"1022239903126":1478686417194,"1024686922672":1509788624448,"1021619458791":1478686417049,"1022239903128":1478686417194,"1023579348401":1491634246515,"642722048":1478950494913,"1024056189246":1509788624289,"1024056189245":1509788624289,"1022238723478":1509788624931,"1022238723477":1509788624931,"1022238723476":1509788624947,"1024686922671":1509788624448,"1024686922670":1509788624448,"1024686922668":1509788624448,"1024056189234":1509788624289,"1009997522688":1491634246520,"1024056058364":1509788624928,"1022239903136":1478686417194,"1022239903138":1478686417194,"1009997522707":1491634246533,"1012126034166":1478686417073,"139659045":1444487341740,"1009997522712":1491634246520,"4981598059":1509788624153,"1025901974497":1509788667450,"1025901974496":1509788667450,"1021932069017":1478686417055,"1021748702080":1478686804068,"1021646066094":1509788625084,"1023734797356":1509788624970,"1021079827049":1509788624279,"1024143097059":1509788667499,"1008095443045":1478686804032,"1024462260732":1509788624988,"1022242262333":1480585069113,"1022242262335":1480585069113,"1351180080":1491634246512,"1016489419822":1478686804022,"1025009231972":1509788624332,"1024686922545":1509788624859,"1021490354868":1478686417046,"1022242262338":1480585069113,"1024686922543":1509788624859,"1019817459439":1509788624302,"1021833111243":1509788624533,"1024686922542":1509788624859,"1024686922541":1509788624859,"1019817459437":1509788624281,"1024686922538":1509788624859,"1021739264878":1478686417252,"494867087":1478686804029,"1023537004688":1509788624459,"1021796280541":1509788624394,"1021886980647":1478686804027,"1022466662184":1478686417299,"1025737343568":1509788624331,"1021559294292":1478686417008,"1025737343567":1509788624331,"1025737343566":1509788624331,"1025737343565":1509788624331,"1025737343564":1509788624331,"1022044399202":1478686417171,"1023612372162":1509788624950,"1021948452884":1478686417055,"1021782915018":1509788624395,"1025737343603":1509788624331,"140843087":1444487341729,"1020819127625":1478686417078,"1025737343604":1509788624331,"1020073972218":1465470268310,"1021973619338":1478686417150,"1021973619339":1478686417150,"1022431272307":1509788624292,"1020258131151":1464448510787,"1025737343519":1509788624331,"1023612372135":1509788624950,"1025737343518":1509788624331,"1025737343517":1509788624331,"1025737343516":1509788624331,"4818407290":1509788624155,"1022066550613":1478686417175,"1023612372146":1509788624950,"1022455390125":1478686417016,"1022221947290":1478686417281,"1020819127615":1478686417078,"1023612372100":1509788624950,"1023612372104":1509788624950,"1535200237":1444487341738,"1024961393910":1509788624969,"1023612372114":1509788624950,"1020752673031":1478686417076,"1025628953764":1509788624233,"1001645483560":1444487341709,"1025737343521":1509788624331,"1025737343520":1509788624331,"1023612372125":1509788624950,"1021581577107":1478686804065,"1023612372067":1509788624950,"1023961954445":1509788625005,"1025406906220":1509788624455,"1023612372066":1509788624950,"1021350894895":1509788624917,"1023612372064":1509788624950,"1021350894888":1509788624917,"1023612372070":1509788624950,"1025406906213":1509788624441,"1021647507082":1509788624533,"1021350894884":1509788624917,"1023612372073":1509788624950,"1024223569951":1509788625128,"1025406906214":1509788624507,"1022412397797":1478686417208,"1021350894882":1509788624917,"1025406906210":1509788624441,"1022486053012":1509788625065,"1021350894910":1509788624917,"1021629549987":1509788624401,"1024223569921":1509788625171,"1023612372086":1509788624950,"1021350894906":1509788624917,"1025737343683":1509788624330,"1021350894902":1509788624917,"1025737343685":1509788624330,"1021350894898":1509788624917,"1025737343684":1509788624330,"1024223569970":1509788625243,"1021350894852":1509788624918,"1021948453023":1478686417055,"1025441386832":1509788624198,"1013091266730":1478686804040,"1021515122518":1509788624860,"1025406906204":1509788624466,"1021515122519":1509788624860,"1024223569956":1509788625128,"1025901972698":1509788667460,"1025406906207":1509788624423,"1021350894878":1509788624917,"1025901972697":1509788667461,"1025406906206":1509788624466,"1021515122517":1509788624860,"1021350894872":1509788624917,"1025406906203":1509788624512,"1025901972701":1509788667459,"1025406906202":1509788624511,"1021350894875":1509788624917,"1025901972700":1509788667460,"1021350894864":1509788624918,"1024223569960":1509788625104,"1021515122520":1509788624860,"1024223569962":1509788625242,"1025737343643":1509788624331,"1024370118937":1509788624927,"1025737343642":1509788624331,"1025737343641":1509788624331,"1025737343647":1509788624331,"1021695619557":1478686804043,"1025737343646":1509788624331,"1021695619558":1478686804043,"1025737343645":1509788624331,"1005848174869":1509788624390,"1021695619559":1478686804043,"1021695619560":1478686804043,"1020904055483":1478686417032,"1015188377046":1465470268263,"1020827516462":1478686417031,"1022452244185":1478686417215,"1021351943533":1478686417005,"1021729305588":1509788624986,"1021351943531":1478686417005,"1020294045302":1465470268284,"1021129773094":1478686417233,"1025642716448":1509788624455,"1021350894923":1509788624917,"1023612371972":1509788624950,"1023612371979":1509788624950,"1021350894917":1509788624917,"1023987513964":1509788624915,"1023612371976":1509788624950,"1023612371983":1509788624950,"1021350894914":1509788624917,"1023612371980":1509788624950,"1023612371987":1509788624950,"1023612371986":1509788624950,"1023612371990":1509788624950,"1023612371989":1509788624950,"1023612371988":1509788624950,"1025737343650":1509788624331,"1023612371994":1509788624950,"1025737343649":1509788624331,"1023670568849":1509788624847,"1023612371993":1509788624950,"1020856090581":1478686417079,"1025737343648":1509788624331,"1023612371992":1509788624950,"1024008879038":1509788667493,"1025737343835":1509788624330,"1021719999148":1509788624514,"1025875888921":1509788667402,"1025737343834":1509788624330,"1021647507200":1509788624194,"1025737343833":1509788624330,"1022966971512":1509788624195,"1025737343832":1509788624330,"1025737343837":1509788624330,"1021719999146":1509788624514,"1025737343836":1509788624330,"1021719999147":1509788624514,"1025737343831":1509788624330,"1025609423606":1509788624455,"1021388906087":1478686804026,"1021719999164":1509788624514,"1013139763756":1478686804027,"1021719999160":1509788624514,"1021719999162":1509788624514,"1022074546585":1478686417061,"1021719999163":1509788624514,"1021719999158":1509788624514,"1021719999159":1509788624514,"1024248342535":1495284743422,"1020258131436":1464448510787,"1021719999155":1509788624514,"1021719999116":1509788624513,"1021719999117":1509788624513,"1024735414066":1509788667507,"1025188405297":1509788624319,"1024735414065":1509788667507,"1025530648494":1509788624509,"1021719999115":1509788624514,"1021867064768":1478686417257,"1021847665434":1509788625078,"1021719999111":1509788624513,"1021719999104":1509788624513,"1021847665437":1509788625077,"1021719999106":1509788624514,"1025188405308":1509788624280,"1022260220584":1478686417196,"1025530648506":1509788624452,"1024735414052":1509788667507,"1025530648503":1509788624510,"1013979219059":1478686804028,"1025530648524":1509788624436,"1023612372386":1509788624950,"1023612372385":1509788624950,"1023612372391":1509788624950,"1025530648520":1509788624436,"1025530648523":1509788624436,"1012615075116":1478686804049,"1025530648517":1509788624436,"1023612372395":1509788624950,"1025530648516":1509788624436,"1023612372394":1509788624950,"1025530648519":1509788624436,"1025530648515":1509788624440,"1024735414083":1509788667507,"1025737343753":1509788624330,"1024735414081":1509788667507,"1025188405312":1509788624300,"1025737343752":1509788624331,"1024735414080":1509788667508,"1021867064765":1478686417257,"1025530648536":1509788624434,"1021867064767":1478686417257,"1025188405316":1509788624281,"1025737343751":1509788624331,"1025737343750":1509788624331,"1025530648528":1509788624427,"1024480482939":1509788624283,"1021719999182":1509788624514,"1019423837163":1478686804028,"1024374706416":1509788625086,"1000813434029":1478950494933,"1021719999178":1509788624514,"1021719999172":1509788624514,"1024362385735":1509788667467,"1021719999173":1509788624514,"1025406905991":1509788624455,"1021719999175":1509788624514,"1023844905067":1491634246533,"1021719999168":1509788624514,"1021647507311":1509788624815,"1024780372010":1509788624567,"1023612372364":1509788624950,"1023612372370":1509788624950,"1021486154959":1509788624402,"1025737343791":1509788624330,"1021719999192":1509788624514,"1023612372375":1509788624950,"1025737343790":1509788624330,"1025737343789":1509788624330,"1021719999194":1509788624514,"1025530648571":1509788625243,"1025737343788":1509788624330,"1023612372372":1509788624950,"1025892403818":1509788667443,"1023612372379":1509788624950,"1021719999189":1509788624514,"1025441386630":1509788624537,"1025441386629":1509788624543,"1023612372377":1509788624950,"1021054134791":1478686417001,"1021719999191":1509788624514,"1023612372382":1509788624950,"1023612372381":1509788624950,"1025406905965":1509788624511,"1022456438347":1478686417016,"1025406905967":1509788624466,"1025406905966":1509788624512,"1021685919839":1478686417249,"1021988954665":1478686417154,"1022632986828":1509788625062,"1025406905977":1509788624507,"1021865622164":1478686417136,"1025406905979":1509788624507,"1022355249254":1478686417203,"1025406905972":1509788624441,"1021966147739":1478686417262,"1024928887754":1509788667496,"1024187787029":1509788624566,"1019775385104":1509788625084,"1024928887758":1509788667496,"1025513083920":1509788624335,"1019166153294":1478686804026,"1024928887751":1509788667497,"1016444074378":1478686804017,"1024928887768":1509788667497,"1024928887761":1509788667496,"1020850716199":1478686804057,"1024928887767":1509788667496,"1024928887766":1509788667497,"1020928566584":1478686417082,"1020928566586":1478686417082,"1023612372257":1509788624950,"1021719999087":1509788624513,"1022966971576":1509788624818,"1008818975588":1509788624372,"1021719999081":1509788624514,"1023612372262":1509788624950,"1022455127610":1478686417216,"1023612372260":1509788624950,"1025737343891":1509788624330,"1021459415708":1509788624817,"1025737343890":1509788624330,"1021719999077":1509788624513,"1023612372266":1509788624950,"1020928566578":1478686417082,"1025737343889":1509788624330,"1021719999078":1509788624514,"1020928566579":1478686417082,"1025737343895":1509788624330,"1023612372271":1509788624950,"1020928566581":1478686417082,"1025737343894":1509788624330,"1025737343893":1509788624330,"1025737343892":1509788624330,"1021719999100":1509788624513,"1024450467647":1509788624957,"1023612372274":1509788624950,"1021719999103":1509788624513,"1021719999096":1509788624513,"1021719999098":1509788624513,"1021719999099":1509788624513,"1022966971564":1509788624534,"1023612372276":1509788624950,"1020507556810":1509788624375,"1021620243576":1509788624401,"1021719999094":1509788624513,"1021719999095":1509788624513,"1023612372280":1509788624950,"1021719999088":1509788624514,"1021719999091":1509788624513,"1022470594292":1478686417073,"1025671946180":1509788624942,"1023612372228":1509788624950,"1020898157376":1478686417080,"1023612372233":1509788624950,"1021738218836":1478686417251,"1023612372243":1509788624950,"1025608505882":1509788624746,"1013091267052":1478686804028,"1022470594283":1478686417073,"1025608505875":1509788624828,"1023612372248":1509788624950,"1025608505877":1509788624833,"1025608505876":1509788624823,"1023612372253":1509788624950,"1017124078525":1478686804024,"1020930008772":1478686417082,"1022438743285":1480585069098,"1022001014511":1478686417057,"1022438743283":1480585069098,"1022438743282":1480585069098,"1021987643871":1478686417154,"1022438743280":1480585069098,"1022270183146":1480585069091,"1024727811182":1509788624169,"1023612372714":1509788624949,"1022270183145":1480585069091,"1022438743293":1480585069098,"1011254649241":1478686804030,"1022270183144":1480585069091,"1023612372712":1509788624949,"1020438217786":1478686804047,"1026223242569":1514456869775,"1022270183149":1480585069091,"1024803572205":1509788625023,"1022370060512":1509788625018,"1022270183155":1480585069091,"1022438743271":1480585069098,"1024727811189":1509788624170,"1025693172463":1509788667463,"1022438743268":1480585069098,"1023612372720":1509788624949,"4818406695":1509788624155,"1022270183163":1480585069091,"1022438743279":1480585069098,"1022270183162":1480585069091,"1022438743278":1480585069098,"1022438743277":1480585069098,"1023612372729":1509788624949,"1022270183160":1480585069091,"1022438743276":1480585069098,"1022438743275":1480585069098,"1022041777311":1478686417268,"1022270183166":1480585069091,"1022438743274":1480585069098,"1022487364111":1478943089489,"1022438743273":1480585069098,"1022438743272":1480585069098,"1022438743253":1480585069098,"1022438743251":1480585069098,"1820294746":1478686417024,"1022438743250":1480585069098,"1820294745":1478686417024,"1022438743249":1480585069098,"1022438743248":1480585069098,"1022438743259":1480585069098,"1022438743257":1480585069098,"1022438743239":1480585069098,"1022438743236":1480585069097,"1020919128415":1478686804032,"1022438743232":1480585069097,"1024838045634":1509788624948,"1022438743246":1480585069098,"1022438743245":1480585069098,"1022438743243":1480585069098,"1024727811163":1509788624168,"1020183811356":1465470268277,"1021143011952":1478686417096,"1022438743223":1480585069097,"1023612372643":1509788624950,"1022438743221":1480585069097,"1019714566423":1478686804066,"1020986369314":1478686417088,"1022438743231":1480585069097,"1022438743229":1480585069097,"1022438743227":1480585069097,"1022438743226":1480585069097,"1022438743225":1480585069097,"1022438743224":1480585069097,"1019000869778":1480585069067,"1019945380810":1509788624392,"1023612372611":1509788624951,"1023233175549":1509788624957,"1025710736274":1509788624304,"1023612372615":1509788624950,"1023612372618":1509788624950,"1021143011930":1478686417096,"1023612372621":1509788624950,"1023612372626":1509788624950,"1023612372629":1509788624950,"1023612372635":1509788624950,"1023612372639":1509788624950,"1023612372636":1509788624950,"1010402022088":1478686804067,"1021985022312":1478686417152,"1023612372587":1509788624950,"1022377793552":1478686417290,"1022776520775":1509788624465,"1023612372593":1509788624951,"1022063928767":1478686417174,"1010091899989":1491634246527,"1010091899991":1491634246522,"1010091899993":1491634246522,"1021343555232":1478686417005,"1023612372606":1509788624951,"1023612372545":1509788624950,"4997856072":1509788667392,"1020953864140":1478686417085,"1020101234925":1465470268257,"1023612372518":1509788624950,"1024519936002":1509788624854,"1023612372522":1509788624950,"1024519936001":1509788624854,"1024519936000":1509788624854,"1014706426640":1509788624944,"1023612372520":1509788624950,"1023612372527":1509788624950,"1024519936004":1509788624854,"1021391134104":1478686417240,"1020993447370":1478686417230,"1023612372535":1509788624950,"1023612372534":1509788624950,"1023612372532":1509788624950,"1023612372539":1509788624950,"1023612372537":1509788624950,"1020050632183":1509788624375,"1023612372536":1509788624950,"1023612372543":1509788624950,"1023612372540":1509788624950,"1021729305034":1509788624986,"1019533030113":1509788624317,"1020438217923":1478686804047,"1024727811217":1509788624169,"1024687966150":1509788667833,"1023738464377":1491634246523,"1021353516683":1478686417005,"1019355940261":1509788624314,"1021807164298":1478686417131,"1023065268361":1509788625047,"1021714362654":1478686417300,"1021695619642":1478686804067,"1021695619643":1478686804067,"1021695619644":1478686804067,"1021695619645":1478686804067,"1025876281613":1509788667406,"1018928115478":1509788624368,"1024055934391":1509788624928,"1021678711555":1478686417120,"1021048760565":1478686417001,"1024669483212":1509788625025,"1024884050946":1509788624439,"1022478713775":1478943089487,"1022632987263":1509788625060,"1021667046327":1478686416979,"165747364":1478686804022,"1022223913706":1509788624938,"1021637414368":1509788624404,"1022724213888":1509788624394,"1024547592278":1509788667496,"1024547592274":1509788667496,"1024547592284":1509788667496,"1022400338011":1478686804067,"1020938135350":1478686417084,"1024547592281":1509788667496,"1022466661550":1478686417299,"1022438743409":1480585069098,"1022438743408":1480585069098,"1021043255695":1478686417092,"1025048820436":1509788624273,"1022438743396":1480585069098,"1022438743395":1480585069098,"1022438743406":1480585069098,"1022438743405":1480585069098,"1022438743404":1480585069098,"1022438743403":1480585069098,"1022438743400":1480585069098,"1022438743383":1480585069098,"1025737343480":1509788624331,"1025737343475":1509788624331,"1022897109549":1509788625052,"1022438743390":1480585069098,"1025737343474":1509788624331,"1025737343473":1509788624331,"1025737343479":1509788624331,"1025737343478":1509788624331,"1022438743385":1480585069098,"1025507448385":1509788624335,"1022438743384":1480585069098,"1021581576285":1478686804066,"1024781552359":1509788625019,"1025910885975":1509788667579,"1025910885974":1509788667579,"1021088083648":1478686417002,"1024055934249":1509788624969,"1001660687605":1478686417024,"1023612372774":1509788624949,"1020258131764":1464448510787,"1011024754409":1478686804030,"1023612372779":1509788624949,"1010091900169":1491634246527,"1010091900177":1491634246527,"1025507448381":1509788624339,"1025507448378":1509788624343,"1022948753223":1509788624929,"1025608505393":1509788624428,"1025608505395":1509788624425,"1025608505394":1509788624431,"1021645802980":1509788624535,"1025608505397":1509788625088,"1025608505399":1509788624407,"1022270183169":1480585069091,"1022438743317":1480585069098,"1022270183168":1480585069091,"1022438743314":1480585069098,"1022270183173":1480585069091,"1023612372747":1509788624949,"1023612372745":1509788624949,"1018242334975":1509788624372,"1023612372751":1509788624949,"1022438743322":1480585069098,"1022438743321":1480585069098,"1023612372749":1509788624949,"1023612372753":1509788624949,"1025737343407":1509788624331,"1025608505373":1509788625116,"1022438743298":1480585069098,"1023612372758":1509788624949,"1021975716199":1509788625011,"1025608505375":1509788625107,"1025608505374":1509788625125,"1022438743306":1480585069098,"1024529505881":1509788625175,"1020771024477":1478686416996,"1024529505883":1509788625175,"1024529505882":1509788625175,"1024529505885":1509788625175,"1022050034181":1509788624435,"1021350893993":1509788624513,"1024529505884":1509788625175,"1008793416745":1478686804054,"1024529505887":1509788625175,"1024529505886":1509788625175,"1021350893989":1509788624513,"1021350893990":1509788624513,"1025883361164":1509788667462,"662385527":1478686804029,"1025050787115":1509788624461,"1021350893984":1509788624513,"1024529505877":1509788625175,"1021350893985":1509788624513,"1021350893986":1509788624513,"1024529505879":1509788625175,"1021350893987":1509788624513,"1024529505878":1509788625175,"1021350894012":1509788624513,"1022400339763":1478686804054,"1022400339762":1478686804042,"1022400339765":1478686804054,"1022400339764":1478686804054,"1025050787122":1509788624461,"1021350894010":1509788624513,"1021350894011":1509788624513,"1021350894005":1509788624513,"1021350894006":1509788624513,"1021350894000":1509788624513,"1025050787129":1509788624461,"1021695620415":1478686804050,"1024529505913":1509788625175,"1021964707099":1478686417056,"1024529505912":1509788625175,"1024529505915":1509788625175,"1024529505917":1509788625175,"1025050918144":1509788624457,"1024529505916":1509788625175,"1024529505919":1509788625175,"1021969950432":1478686416984,"1025104132146":1509788624585,"1024313223441":1509788624327,"1024529505909":1509788625175,"1012341907585":1478686417026,"1021350893980":1509788624513,"1024529505896":1509788625175,"1021350893972":1509788624513,"1024529505888":1509788625175,"1024529505891":1509788625175,"1021350893975":1509788624513,"1021393230612":1478686417042,"1022089096594":1478686417062,"1021350893971":1509788624513,"1019971465120":1480585069076,"1020898158305":1478686417080,"1019971465133":1480585069076,"1019971465134":1480585069076,"1025050787181":1509788624461,"1020891866434":1509788624930,"1019971465130":1480585069076,"1020258130082":1464448510787,"1025050787190":1509788624461,"1019971465142":1480585069076,"1019971465143":1480585069076,"1019971465136":1480585069076,"1019971465138":1480585069076,"1019971465148":1480585069076,"1019971465151":1480585069076,"1019971465145":1480585069076,"1019971465147":1480585069076,"1023627051106":1509788624917,"1023627051111":1509788624917,"1012108997353":1478686417023,"1023627051114":1509788624847,"1022239905469":1478686417014,"1025050787147":1509788624461,"1023627051123":1509788624847,"1023627051125":1509788624849,"1008833787824":1480585069066,"1022467709766":1478686417299,"1025050787164":1509788624461,"1025050787161":1509788624461,"1023627051133":1509788624827,"1024529506009":1509788624477,"1024529506008":1509788624477,"1024529506011":1509788624476,"1024529506010":1509788624477,"1023627051143":1509788624827,"1024529506012":1509788624476,"1025050787233":1509788624461,"1024529506015":1509788624476,"1024529506014":1509788624476,"1025050787243":1509788624461,"1024529506006":1509788624476,"1023627051155":1509788624846,"1025721353662":1509788624822,"1025721353661":1509788624832,"1025721353660":1509788624828,"1021699815030":1478686417009,"1021654190894":1478686417120,"1025050787249":1509788624461,"1024529505984":1509788624236,"1024529506043":1509788624476,"1024529506045":1509788624476,"1024529506044":1509788624476,"1025050787201":1509788624461,"1024529506047":1509788624477,"1024529506046":1509788624476,"1024529506035":1509788624476,"1023035123168":1509788624175,"1024529506039":1509788624476,"1024529506025":1509788624476,"1024529506024":1509788624476,"1024529506027":1509788624476,"1024529506026":1509788624476,"1025050787219":1509788624461,"1025050787230":1509788624461,"1024529506016":1509788624476,"1024529506019":1509788624476,"1024529506023":1509788624476,"1022400339937":1478686804042,"1022400339936":1478686804042,"1022400339939":1478686804042,"1022400339938":1478686804042,"1024529505949":1509788624236,"1022400339940":1478686804042,"1021925522342":1478686417054,"1021198323720":1465470268191,"1023627051219":1509788624875,"1022094994852":1478686417274,"1022094994853":1478686417274,"1023627051223":1509788624875,"1024529505921":1509788625175,"1024529505920":1509788625175,"1022223914367":1509788624939,"1024529505922":1509788625175,"1023627051231":1509788624875,"1023627051229":1509788624875,"1023627051235":1509788624875,"1024529505976":1509788624236,"1024529505979":1509788624236,"1021264649235":1465469681395,"1024529505978":1509788624236,"1024529505981":1509788624236,"1021583150864":1509788624397,"1023627051239":1509788624875,"1024529505980":1509788624236,"1021729437657":1509788624403,"1023730863894":1509788624929,"1023627051237":1509788624875,"1024529505969":1509788624236,"1024529505968":1509788624236,"1023627051242":1509788624875,"1024529505971":1509788624236,"1024529505970":1509788624236,"1021727602612":1478686804065,"1024529505973":1509788624236,"1023627051247":1509788624875,"1023627051245":1509788624875,"1024529505974":1509788624236,"1025721353664":1509788624616,"1023627051244":1509788624875,"1023627051250":1509788624875,"1024529505962":1509788624236,"1024529505965":1509788624236,"1024529505964":1509788624236,"1023627051253":1509788624875,"1024529505966":1509788624236,"1023627051252":1509788624875,"1023627051259":1509788624875,"1022400339931":1478686804042,"1024529505955":1509788624237,"1024529505954":1509788624237,"1022400339933":1478686804042,"1024529505957":1509788624237,"1022400339932":1478686804042,"4997856537":1509788667392,"1022400339935":1478686804042,"1024529505959":1509788624236,"1023627051261":1509788624875,"1022400339934":1478686804042,"1024529505958":1509788624236,"1023627051260":1509788624875,"1013139764796":1478686804027,"1023627051271":1509788624875,"1023402398306":1509788624222,"1022244493164":1478686417066,"1022400339501":1478686804071,"1024528457543":1509788624237,"1022021198027":1509788625236,"1024528457558":1509788625175,"1024529506173":1509788624456,"1021041422087":1465470268237,"1024529506175":1509788624414,"1022460631719":1478686417298,"1022074809765":1478686417061,"1021894719606":1478686804048,"1023402398292":1509788624221,"1012211890516":1478686417073,"1023402398298":1509788624222,"1023402398297":1509788624222,"1023402398296":1509788624222,"1020616357072":1478686417027,"1025332719409":1509788624281,"1025332719408":1509788624311,"1025332719411":1509788624283,"1021695620212":1478686804050,"1024529506048":1509788624476,"1025608769215":1509788625083,"1012497360958":1478686417223,"1021484318909":1509788624398,"1022398111269":1478686417291,"1021854219974":1478686417135,"1011803718070":1478686804015,"1022238988192":1478686417283,"1016779745703":1478686804063,"1016779745702":1478686804063,"1022227715304":1478686417014,"1024008093381":1509788667462,"1016779745706":1478686804063,"1016779745705":1478686804063,"1016779745704":1478686804063,"1024008093378":1509788667499,"4806478826":1509788624155,"1019835672509":1509788625078,"1015291670867":1480585069068,"1021729306250":1509788624986,"1025901971905":1509788667450,"1023728111530":1491634246523,"1019372585474":1509788624302,"1019193940383":1478686804049,"1019689008923":1509788624284,"1025879952919":1509788667403,"1017092233815":1478686804019,"1020916115055":1478686417032,"1025909705155":1509788667459,"1025901971895":1509788667451,"1023627051494":1509788624917,"1021354301566":1465470268230,"1023627051499":1509788624847,"1023627051497":1509788624917,"1023627051505":1509788624847,"1023627051512":1509788624849,"1019193940384":1478686804049,"1019193940385":1478686804049,"1019193940386":1478686804049,"1019193940387":1478686804049,"1023627051516":1509788624827,"1023627051523":1509788624827,"1025569447516":1509788624351,"1023612371680":1509788624951,"1023627051525":1509788624827,"1023605818688":1509788625142,"1023627051534":1509788624868,"1023627051533":1509788624827,"1023627051532":1509788624827,"1022966971243":1509788625102,"1021311048733":1465470268203,"1021311048735":1465470268203,"1021311048729":1465470268203,"1020998037196":1478686417088,"1006864923417":1509788624380,"1021603728031":1509788624816,"1023612371653":1509788624951,"1019067454434":1509788624315,"1023576721199":1491634246536,"1023576721198":1491634246536,"1023612371662":1509788624951,"4997857225":1509788667398,"1016779745815":1478686804063,"1023576721202":1491634246536,"1023576721200":1491634246536,"1019256194745":1509788624312,"1021301742729":1480585069071,"1023612371668":1509788624951,"1016779745823":1478686804063,"1016779745822":1478686804063,"1016779745821":1478686804063,"1016779745820":1478686804063,"1023612371672":1509788624951,"1016779745819":1478686804063,"1023612371679":1509788624951,"1016779745818":1478686804063,"1025569447520":1509788624350,"1016779745816":1478686804063,"1023612371676":1509788624951,"1023612371622":1509788624951,"1021337262800":1478686804045,"1021337262801":1478686804045,"1021337262802":1478686804045,"1021337262803":1478686804045,"1021603728113":1509788624419,"1023612371628":1509788624951,"1000037269607":1478686417021,"1021337262798":1478686804045,"1023612371633":1509788624951,"1024632915547":1509788624467,"1021337262794":1478686804045,"1023612371637":1509788624951,"1021337262795":1478686804045,"1023612371641":1509788624951,"1022072844024":1478686417271,"1020987941167":1478686416984,"1023612371645":1509788624951,"1025815593454":1509788667452,"1022400339265":1478686804042,"1021581577613":1478686804028,"1022479762948":1478943089487,"1022400339267":1478686804054,"1022400339266":1478686804042,"1022400339269":1478686804054,"1022400339268":1478686804054,"1021990790639":1478686417155,"1022089752530":1478686417273,"1024753897102":1509788624949,"1021768364111":1478686417052,"1021768364108":1478686417052,"1001351492445":1444487341700,"635122524":1491634246517,"1022044659936":1509788625065,"1012418588334":1478686417074,"1021583019358":1509788624397,"1025772733079":1509788624998,"1024977253152":1509788624938,"1016779745943":1478686804058,"666972532":1491634246534,"666972536":1491634246534,"1016779745948":1478686804058,"1016779745947":1478686804058,"1016779745946":1478686804058,"1022966971334":1509788624420,"1016779745945":1478686804058,"1016779745944":1478686804058,"1021969949707":1478686416984,"1021117704567":1478686417095,"787167269":1491634246509,"1021699814449":1478686417009,"1016779746047":1478686804058,"1016779746046":1478686804058,"1016779746045":1478686804058,"1020294043765":1465470268284,"1016779746044":1478686804058,"1024838044462":1509788624948,"1016779746043":1478686804058,"1020258130448":1464448510787,"1021076810477":1478686417094,"1022476879453":1478943089487,"1025120517107":1509788624935,"1017827552551":1478686804021,"1020258130931":1464448510787,"1001212414722":1478686417220,"1024977253018":1509788624938,"1021723145353":1478686417009,"1024977253020":1509788624938,"1025636555591":1509788624308,"1022392343716":1478686417291,"1023612371910":1509788624952,"1016779746048":1478686804058,"1023612371915":1509788624952,"1023612371916":1509788624952,"1024838044356":1509788624948,"1023612371879":1509788624952,"1023612371890":1509788624952,"1021379074391":1478686417239,"1023612371893":1509788624952,"1023612371899":1509788624952,"1023612371902":1509788624952,"1007542174085":1478686804033,"1023612371847":1509788624952,"1023612371845":1509788624952,"1021138163478":1478686417037,"1021914773852":1478686417054,"1021535047610":1509788624509,"1023612371855":1509788624952,"1010093865427":1491634246528,"1022044266764":1478686417171,"1021356399117":1465469681398,"1015291671424":1480585069068,"1023612371862":1509788624952,"1010093865434":1491634246522,"1021451945170":1509788624179,"1021105514806":1478686417095,"1010093865433":1491634246522,"1022483302228":1509788624217,"1022483302227":1509788624217,"1022483302226":1509788624217,"1023612371870":1509788624952,"1022483302225":1509788624217,"1025200858590":1509788625082,"1021968377214":1509788625068,"1023612371779":1509788624951,"1023612371777":1509788624951,"1017714828236":1478686804056,"1023612371785":1509788624951,"1002289056343":1444487341751,"1023995510176":1491634246532,"1019824399621":1509788624281,"1023612371790":1509788624951,"1023612371792":1509788624951,"1023122153864":1509788624977,"1021931550859":1478686416984,"1022983879109":1509788625050,"1025120516770":1509788624935,"1000970197330":1478686804039,"1023612371755":1509788624951,"1017246240676":1478686804023,"1023612371760":1509788624952,"1023612371767":1509788624952,"1022440970499":1478686417071,"1023612371764":1509788624952,"1023612371770":1509788624951,"1023612371769":1509788624951,"1023612371775":1509788624951,"1023612371772":1509788624951,"1021290208942":1478686417102,"1020741271522":1478686417075,"1023820789630":1491634246535,"1018165663841":1478686804023,"1021645801939":1509788624196,"1024838044166":1509788624948,"1010813062715":1509788624276,"1022067990763":1478686804035,"1020258130697":1464448510787,"1021767053593":1478686417052,"1021806247796":1478686416987,"1020294174380":1465470268296,"1022395880289":1478686417070,"1021741497440":1509788624841,"1000094155429":1478686804029,"1023537010542":1509788624459,"1022278311030":1478686417197,"1025295753368":1509788624945,"1413958744":1444487341719,"1025736559207":1508316495865,"1026232412413":1514456869770,"1026232412414":1514456869769,"1024936098356":1509788624437,"1021982534183":1509788624614,"1021741497428":1509788624863,"1021741497429":1509788624863,"1021741497430":1509788624825,"1021741497431":1509788624848,"1022848876113":1509788624326,"1021741497427":1509788624863,"1018923525190":1509788624282,"1021741497436":1509788624842,"1021741497437":1509788624841,"1021741497438":1509788624841,"1021741497439":1509788624841,"1021741497432":1509788624842,"1021741497433":1509788624842,"1021741497434":1509788624842,"1022247115281":1478686417195,"1021074580594":1478686417093,"1004730185259":1444487341756,"1024919976271":1509788624987,"1020940495946":1478686417084,"1017808020105":1478686804026,"1021545922673":1478686417113,"1021608444937":1478686417116,"1021713840776":1509788624400,"1024481140663":1509788624298,"1021245644441":1478686417100,"1016779351221":1478686804065,"1020258128976":1464448510786,"1020811392339":1478686416998,"1021871387676":1509788624394,"1021715675819":1478686417123,"1021715675817":1478686417123,"1025295753264":1509788624945,"1025839448291":1509788667844,"1021629810115":1509788624396,"1001015150874":1478686417022,"1022052790062":1478686804068,"1020881381745":1478686417079,"1086806045":1491634246517,"1023319825064":1509788624183,"1022454994713":1478686417072,"1022454994703":1478686417216,"1025647039815":1509788624342,"1022341353563":1509788624290,"1005848176940":1509788624381,"1023021754679":1509788624992,"1023021754675":1509788624992,"1025711261900":1509788624306,"1022018710766":1478686417161,"1023021754681":1509788624992,"1023373827115":1509788625040,"1022296267872":1478686417199,"1021271986553":1478686804046,"1021273821530":1478686417040,"1021792091713":1478686417052,"1021741497669":1509788624214,"1021741497665":1509788624227,"1021741497666":1509788624200,"1022120026835":1478686417276,"1021741497677":1509788624209,"1021750541524":1509788624400,"1021741497679":1509788624209,"1021741497672":1509788624209,"4935859997":1509788624163,"1021741497684":1509788624210,"1025459084224":1509788624351,"1021741497686":1509788624210,"1021741497687":1509788624211,"1021741497680":1509788624209,"1021741497681":1509788624209,"1021741497682":1509788624209,"1017808020430":1478686804026,"1021741497689":1509788624228,"1021741497690":1509788624230,"4935860091":1509788624163,"1021984369316":1478686417263,"1021984369317":1478686417264,"1020898421737":1478686417032,"1022848614183":1509788624393,"1019386610063":1509788624320,"1047078713":1478686417024,"1019386610068":1509788624315,"1019599748437":1465470268274,"1021741497661":1509788624227,"1024463052658":1509788625070,"1021741497659":1509788624227,"1020258129303":1464448510786,"1025569575217":1509788624349,"1025569575216":1509788624348,"1016931015774":1478686804019,"1023485761005":1509788625148,"1023485761004":1509788625148,"1023485761003":1509788625148,"1023485761001":1509788625148,"1021338178826":1478686417005,"1021685921865":1478686417249,"1023485761009":1509788625148,"1021925521139":1478686417054,"1019809982491":1509788624353,"1021863391883":1478686417053,"1021863391884":1478686417053,"1010601514444":1509788625017,"1013364025442":1478686804064,"1021014941805":1478686417090,"1021967067307":1509788625068,"1021014941801":1478686417090,"4910824715":1509788624156,"1021987252739":1478686417154,"1018762308573":1509788624378,"1022052789813":1478686804066,"1023946358472":1491634246531,"1026232412417":1514456869770,"1026232412419":1514456869770,"1022491953271":1478943089315,"1023946358470":1491634246531,"1026232412420":1514456869769,"1023946358469":1491634246531,"1025629869736":1509788624178,"1025880605149":1509788667784,"1022471113444":1478686417219,"1019820468459":1509788625079,"1018490075200":1478686804056,"1022293516173":1478686417068,"1025591726327":1509788625019,"1025626855123":1509788624441,"1021432547542":1478686804067,"1025626855124":1509788624437,"1004385059015":1478686804048,"1016071686216":1465470268265,"1025626855108":1509788624565,"1023453384776":1509788624870,"1022052789708":1478686804066,"1023485761071":1509788624555,"1025626855088":1509788624437,"1023485761070":1509788624555,"1025626855091":1509788624551,"1023485761069":1509788624555,"1023485761064":1509788624555,"1023485761084":1509788624555,"1022081360497":1478686417012,"1025626855081":1509788624511,"1025626855057":1509788625007,"1017808019615":1478686804026,"1025626855068":1509788624436,"1018490075199":1478686804056,"1020469543460":1509788624283,"1020469543461":1509788624283,"1020469543462":1509788624283,"1020469543463":1509788624284,"1020469543459":1509788624283,"1459309702":1444487341729,"1023485761263":1509788624854,"1843754852":1444487341720,"1023485761262":1509788624854,"1021514468718":1478686417112,"1023485761261":1509788624854,"1021514468712":1478686417112,"1023485761259":1509788624854,"1020258129527":1464448510786,"1843754861":1444487341735,"1020294173729":1465470268296,"1843754863":1444487341744,"1843754856":1444487341731,"1025626855038":1509788624511,"1020620946375":1478686416989,"1843754866":1444487341719,"1459309667":1444487341747,"1023485761268":1509788624854,"1022326021395":1478686417068,"1020780589327":1478686416991,"1025758316984":1509788624343,"1020891868075":1509788624930,"1022299021197":1478686417287,"1008833788256":1480585069066,"1018636611891":1509788624971,"1021339490007":1509788624437,"1021917525318":1478686417054,"1025906296454":1509788667448,"1025508106068":1509788624340,"1024134572400":1509788625016,"1022066552242":1478686417175,"1025508106072":1509788624339,"1017808019505":1478686804026,"1008667837291":1478686804026,"1024362912502":1509788667460,"1021025821657":1478686417035,"1024362912507":1509788667820,"1022156203848":1509788624959,"1020294042696":1465470268284,"1025608241413":1509788624837,"1023485761183":1509788624218,"1021982533882":1509788624271,"1016760213945":1478686804016,"1022244231322":1478686417195,"1023485761176":1509788624218,"1023485761175":1509788624218,"1025428675161":1509788625109,"1023485761173":1509788624218,"1025428675162":1509788625117,"1023485761171":1509788624218,"1025608241427":1509788624837,"1020469543764":1509788624284,"1020469543760":1509788624284,"1020469543761":1509788624284,"1020469543762":1509788624284,"1020469543763":1509788624284,"1022052789491":1478686804066,"1025608241407":1509788624837,"1021729306676":1509788624986,"115416571":1444487341705,"1017808019930":1478686804026,"1021512502570":1478686416974,"1021736517628":1509788624195,"1018907402308":1509788624313,"1025788464665":1509788624406,"1025788464664":1509788624425,"1025788464663":1509788624431,"1022242003336":1478686417195,"1025788464662":1509788624428,"1022242003338":1478686417195,"1007798959785":1478686804025,"1021013762693":1478686417231,"1021982533966":1509788624271,"1021327167612":1465470268215,"1022483303266":1509788624853,"1021934693251":1509788624849,"1022620271462":1509788625062,"1018546699674":1480585069063,"1025628952507":1509788624233,"1021124256803":1478686417002,"1022483303260":1509788624853,"1022483303259":1509788624853,"1022483303258":1509788624852,"1021934693271":1509788624869,"1019596603169":1509788624933,"1020258129777":1464448510787,"1022233221808":1478686417282,"1018044420941":1509788624372,"1024797147613":1509788625020,"1022138902345":1478686417184,"1021627057912":1478686417247,"1023485761485":1509788624446,"1023485761484":1509788624446,"1023485761483":1509788624446,"1023485761482":1509788624446,"1022315797901":1478686417068,"1023485761481":1509788624446,"1021918049355":1509788624864,"1022315797913":1478686417068,"1018850911072":1509788625079,"1021918049361":1509788624849,"1025702480892":1509788667778,"1025702480891":1509788667779,"1022315797918":1478686417068,"1021747527606":1478686417254,"1024929544609":1509788624426,"1021211434965":1478686804033,"1022235712220":1478686417193,"1015868267860":1465470268314,"1459702994":1444487341733,"1022848875961":1509788624326,"1016845818763":1509788624367,"1022227847863":1478686417282,"4564126698":1465469681390,"1520910662":1478686804029,"1021982534114":1509788624614,"1021303443817":1509788624171,"1022456566827":1478686417216,"1025784139388":1509788624351,"1025221699832":1509788625007,"1020882037328":1478686417227,"1023861684725":1491634246533,"1021029490944":1478686416980,"1017808019727":1478686804026,"1021980174803":1478686417151,"1021980174800":1478686417151,"1024187788616":1509788625168,"1022400337697":1478686804067,"1021692345716":1509788624920,"1022883214458":1509788624381,"1025702480970":1509788667416,"1025530649226":1509788624867,"1022052789235":1478686804066,"1025702480965":1509788667415,"1025702480962":1509788667417,"1022701273439":1509788624972,"1025702480961":1509788667413,"1021791173507":1478686417129,"1025702480990":1509788667422,"1025702480987":1509788667416,"1014261955139":1480585069073,"1021791173509":1478686417129,"1025702480984":1509788667416,"1021581576183":1478686804066,"1023846350131":1491634246537,"1021771643547":1480585069071,"1018490076790":1478686804059,"1018490076791":1478686804059,"1023021755419":1509788624992,"1024008877933":1509788667493,"1021768366817":1478686417052,"4997854667":1509788667392,"1025702481023":1509788667575,"1025530649276":1509788624865,"1025702481022":1509788667575,"1021709647485":1509788624814,"1025530649278":1509788624864,"1023444080351":1509788624960,"1025530649272":1509788624916,"1025530649269":1509788624916,"1023878725438":1491634246530,"1025530649292":1509788624841,"1025702480910":1509788667679,"1025530649289":1509788624848,"1025702480906":1509788667679,"1025702480905":1509788667691,"1025702480903":1509788667668,"1025530649287":1509788624848,"1009380171547":1509788624353,"1025702480926":1509788667719,"1025702480925":1509788667678,"1009120700664":1478686804025,"1025702480920":1509788667679,"1025530649297":1509788624841,"1025702480912":1509788667679,"1025530649325":1509788624826,"1025530649324":1509788624868,"1025530649327":1509788624822,"1025530649326":1509788624867,"1025530649321":1509788624841,"1025530649319":1509788624841,"1025530649312":1509788624841,"1021709647392":1509788624193,"1025702480957":1509788667435,"1025702480956":1509788667436,"1024597398101":1509788624939,"1013235447064":1478686804034,"1025530649329":1509788624836,"1018908583743":1509788625019,"1014873020233":1509788625127,"1025530649100":1509788624565,"1012721636992":1478686417074,"1025508366690":1509788624177,"1025530649097":1509788624611,"1021253114630":1465469681395,"1014873020225":1509788625127,"1025530649091":1509788624611,"1025530649117":1509788624552,"1022441493055":1478686417295,"1012615076080":1478686804049,"1014873020254":1509788625127,"1021259406267":1478686417101,"1014873020242":1509788625127,"1025593562705":1509788624833,"1022775737948":1509788624825,"1025593562704":1509788624829,"1021610541256":1478686417116,"1025593562707":1509788624800,"1025593562706":1509788624824,"1025530649132":1509788624547,"1014873020264":1509788625242,"1014873020267":1509788625171,"1025530649130":1509788624547,"1025593562725":1509788624198,"1025593562724":1509788624204,"1025593562727":1509788624186,"1018656534766":1509788624321,"1025593562726":1509788624201,"1014873020258":1509788625127,"1014873020260":1509788625127,"1025530649123":1509788624547,"1020878499162":1509788624934,"1025530649149":1509788624539,"1022400337814":1478686804067,"1025530649142":1509788624547,"1025344251669":1509788624183,"1022341354521":1509788624290,"1025572983995":1509788624304,"1025530649136":1509788624547,"1021928797152":1509788624974,"1019916282861":1478686804057,"1025609815860":1509788624341,"1020258127920":1464448510786,"1025702481035":1509788667523,"1025702481031":1509788667523,"1025702481030":1509788667523,"1022115702512":1478686416973,"1025702481028":1509788667517,"1025530649153":1509788624536,"1025530649152":1509788624566,"1026232151059":1514456869770,"1025702481024":1509788667534,"1008568749914":1478686804030,"1021242104570":1478686417100,"1021242104572":1478686417100,"1025702481048":1509788667540,"1020469544076":1509788624283,"1021495593429":1478686417111,"1020469544077":1509788624283,"1025009236858":1509788624332,"1020220118507":1478686804018,"1020469544073":1509788624283,"1020649652038":1478686417028,"1020469544074":1509788624283,"1025702481041":1509788667523,"1020469544075":1509788624283,"1014873020201":1509788625128,"1025530649199":1509788624848,"1022179533482":1509788624920,"1025530649188":1509788624916,"1014873020192":1509788625245,"1025530649191":1509788624865,"1014873020195":1509788625244,"1025530649185":1509788624916,"1021559948712":1478686417113,"1021581575966":1478686804066,"1025530649214":1509788624841,"1025530649208":1509788624841,"1019835412214":1509788625077,"1025530649210":1509788624841,"1014873020222":1509788625110,"1021981748942":1509788624456,"1020878499086":1509788624934,"1022296398216":1478686417068,"1014873020213":1509788625128,"1021514468113":1478686417047,"1021354299750":1465470268230,"1021453782667":1509788624399,"1025593563077":1509788624425,"1025593563076":1509788624431,"1025593563078":1509788624407,"1025593563075":1509788624428,"1020469544260":1509788624285,"1020006588636":1509788625076,"1024187788196":1509788624229,"1020469544256":1509788624285,"1022883214701":1509788624385,"1020469544257":1509788624285,"1022883214700":1509788624385,"1020469544258":1509788624285,"1020469544259":1509788624285,"1025400087406":1509788624293,"148575687":1444487341703,"1022270183875":1480585069091,"1022270183874":1480585069091,"1022270183873":1480585069091,"1022270183879":1480585069092,"1023670569551":1509788625001,"1022270183878":1480585069091,"1022270183877":1480585069091,"1022270183876":1480585069091,"1022270183882":1480585069092,"1022270183881":1480585069092,"1022270183887":1480585069092,"1022270183886":1480585069092,"1022270183885":1480585069092,"1019164972842":1465470268273,"1024519935999":1509788624854,"1020615048368":1478686417027,"1025507187026":1509788624344,"1025507187025":1509788624338,"1025702481163":1509788667993,"1021194264128":1478686416987,"1025507187028":1509788624337,"1025702481157":1509788667994,"1025702481182":1509788667922,"1025702481179":1509788667922,"1025702481178":1509788667922,"1025702481176":1509788667931,"1025702481173":1509788667912,"1025702481171":1509788667948,"1021290468394":1478686416982,"1021503458260":1478686417046,"1022367831123":1478686417289,"1021981749076":1509788624198,"1024767264111":1509788667499,"1025702481190":1509788667951,"1022044924696":1478686417171,"1021626400823":1509788624396,"1021950553451":1478686417056,"1016530448506":1478686804020,"1017124080839":1478686804024,"1021950553455":1478686417056,"1024767264112":1509788667499,"1019287523115":1509788624312,"1021137640942":1478686417096,"1004787330204":1480585069067,"1020087868548":1509788624389,"1019953505419":1509788624323,"1025593562964":1509788624524,"1025593562961":1509788624540,"1025593562963":1509788624537,"1025593562962":1509788624543,"1022466921099":1478686417299,"1025530649391":1509788624865,"1020258128215":1464448510786,"1025530649384":1509788624916,"1025530649387":1509788624865,"1025530649382":1509788624916,"1024193162229":1509788625034,"1025530649406":1509788624841,"1025530649395":1509788624848,"1022780456742":1509788624462,"1023572135048":1509788624974,"1025530649417":1509788624841,"1018246793503":1509788625020,"1023201584802":1509788624406,"1024108620944":1509788624427,"1000603116948":1478686804023,"1024136408651":1509788667499,"1024136408650":1509788667499,"1022254194177":1509788624363,"1025810090514":1509788667447,"1012615076451":1478686804049,"1025530648704":1509788625129,"1025608504825":1509788624540,"1022085556215":1478686417062,"1025608504827":1509788624537,"1012165621565":1478686417025,"1025608504826":1509788624542,"1025608504828":1509788624523,"1017038623426":1478686804040,"1025876280332":1509788667406,"1025530648751":1509788624611,"1022327724478":1478686417288,"275713627":1478686804024,"1025530648759":1509788624565,"1025530648753":1509788624611,"1012165621523":1478686417025,"1019419378826":1465470268273,"1025608504751":1509788624204,"1025608504750":1509788624200,"1025530648774":1509788624552,"1021441723414":1478686417241,"1021441723415":1478686417241,"1021441723412":1478686417241,"1021441723413":1478686417241,"1021441723411":1478686417241,"1020294172912":1465470268295,"1025608504752":1509788624198,"1021441723420":1478686417241,"1025608504755":1509788624186,"1025530648790":1509788624547,"1021441723418":1478686417241,"1021441723419":1478686417241,"1021441723416":1478686417241,"1021441723417":1478686417241,"1025530648813":1509788624548,"1021703617736":1478686417050,"1025530648809":1509788624548,"1025530648808":1509788624548,"1025530648804":1509788624547,"1025530648800":1509788624547,"492766001":1478686804029,"1025530648829":1509788624566,"1025911407498":1509788667466,"1025530648831":1509788624539,"844573731":1491634246511,"1025762118329":1509788667888,"1022104822951":1478686417182,"1022314747942":1478686417287,"1024778668026":1509788625166,"1025788464038":1509788624745,"1025788464036":1509788624822,"1021889475386":1478686417258,"1025788464035":1509788624831,"1025530648577":1509788625244,"1025788464034":1509788624827,"1023329787209":1509788625040,"1025530648607":1509788625134,"1025530648603":1509788625134,"1025530648602":1509788625134,"278859271":1478686804054,"1020258128488":1464448510786,"1024196831379":1509788624273,"1022775999612":1509788624439,"1025530648623":1509788625129,"1025530648622":1509788625105,"1021653926169":1478686417050,"1025530648619":1509788625169,"1012615076558":1478686804049,"1025530648614":1509788625135,"1023308292015":1509788624193,"1025530648611":1509788625134,"1024735414433":1509788667507,"1021709647096":1509788624419,"1024735414436":1509788667507,"1018948034653":1509788624313,"1012968966128":1478686417224,"1025530648653":1509788625244,"1025530648652":1509788625243,"1025530648654":1509788625166,"1022453682389":1478686417297,"1021963792364":1478686417148,"1025788464101":1509788625087,"1017168252372":1478686804040,"1002079604412":1478686804033,"1025788464099":1509788625106,"1017876832270":1478686804017,"1025788464098":1509788625122,"1025788464097":1509788625114,"1025530648669":1509788625134,"1024031028028":1509788624467,"1025530648667":1509788625134,"1025530648661":1509788625143,"1021323629974":1465470268210,"1021323629975":1465470268211,"1025530648656":1509788625166,"1025530648659":1509788625144,"1025530648658":1509788625164,"1025530648685":1509788625112,"1025530648684":1509788625169,"1021301740636":1480585069071,"1025530648687":1509788625167,"1024132476167":1509788624327,"1025530648680":1509788625134,"1022238858279":1509788624946,"1022238858281":1509788624930,"1025530648677":1509788625134,"1021445917932":1478686417107,"1022238858283":1509788624930,"1022238858282":1509788624930,"1025530648673":1509788625134,"1022144537228":1478686417277,"1021730618877":1478686417051,"1022363899832":1478686417203,"1021681598191":1509788624404,"1022144537237":1478686417277,"1022179532977":1509788624920,"1022453682414":1478686417297,"1025530648688":1509788625105,"1500071528":1444487341741,"1018974249078":1509788624313,"1025645335262":1509788624431,"1022067992606":1478686804035,"1021398339572":1509788624399,"1022067992607":1478686804035,"1025530648991":1509788624510,"1025530648987":1509788624509,"1023791939891":1509788624960,"1021514074379":1509788624398,"1025530649006":1509788624440,"1025530649001":1509788624451,"1022238727655":1509788624947,"1021662052357":1478686417120,"1022238727658":1509788624931,"1025169796901":1509788624393,"1022238727657":1509788624931,"1022238727660":1509788624941,"1022067992610":1478686804072,"1025530649021":1509788624436,"1022447915386":1480585069095,"4818403331":1509788624156,"1022067992608":1478686804035,"1024187787652":1509788624867,"1022447915391":1480585069095,"1022447915390":1480585069095,"1022447915389":1480585069095,"1022447915388":1480585069095,"1025645335264":1509788624406,"1021015991965":1478686417090,"1022447915376":1480585069095,"1022447915383":1480585069095,"1022447915381":1480585069095,"1012615076699":1478686804049,"1022447915380":1480585069095,"1025530649010":1509788624436,"1025530649037":1509788624427,"1025530649036":1509788624455,"1025530649039":1509788624454,"1021237516762":1478686417099,"1025530649028":1509788624436,"1016299503501":1480585069062,"1025530649030":1509788624436,"1025530649025":1509788624436,"1021559293455":1478686417008,"1021303182802":1465470268202,"1025907737445":1509788667460,"1025907737444":1509788667464,"1025596839393":1509788624929,"1025596839392":1509788624929,"1025530649040":1509788624424,"1022042302917":1478686417170,"1020258128787":1464448510786,"1023419832089":1509788625039,"1020997511087":1478686417088,"1025788463703":1509788624523,"1025788463702":1509788624537,"1025788463701":1509788624542,"1025788463700":1509788624540,"1023716312401":1491634246528,"1025628951376":1509788624232,"1024283337572":1509788624326,"1021301740860":1480585069071,"1025530648840":1509788624544,"1025010677772":1509788624506,"1025530648836":1509788624566,"1025530648838":1509788624536,"1022204518208":1478686417190,"1015391679858":1509788625083,"1025628951362":1509788624232,"1025628951364":1509788624232,"1022052788332":1478686804065,"1025628951367":1509788624232,"1025628951368":1509788624232,"1025628951372":1509788624232,"1021741497284":1509788624840,"1025530648876":1509788624509,"1021741497281":1509788624840,"1021741497292":1509788624841,"1021741497293":1509788624842,"1021741497294":1509788624843,"1021741497289":1509788624840,"1021741497290":1509788624840,"1025109635604":1509788624308,"1025278715907":1509788624461,"1021741497303":1509788624868,"1025530648888":1509788624452,"1025048819443":1509788624276,"1021741497299":1509788624866,"693319400":1444487341708,"1020971166158":1478686417086,"1025109635609":1509788624308,"1025530648881":1509788624510,"1020971166157":1478686417086,"1025109635610":1509788624308,"1022447915403":1480585069095,"1022447915402":1480585069095,"1022447915401":1480585069095,"1022447915400":1480585069095,"1022447915407":1480585069095,"1018468712031":1478686804034,"1022447915404":1480585069095,"1021208288228":1478686804027,"1025714802299":1509788624469,"1022447915393":1480585069095,"139663256":1444487341736,"1025530648902":1509788624440,"1022447915399":1480585069095,"1025530648897":1509788624451,"1022447915396":1480585069095,"1021741497270":1509788624863,"1025530648926":1509788624436,"1021741497271":1509788624863,"1025530648920":1509788624436,"1012165621494":1478686417025,"1022447915408":1480585069095,"1021741497279":1509788624840,"1021741497272":1509788624863,"1000927466713":1478686804028,"1021741497273":1509788624825,"1021741497274":1509788624848,"1021741497275":1509788624840,"1021976767872":1478686417263,"1022359049813":1478686417289,"1025530648942":1509788624455,"1025628951349":1509788624233,"1025628951353":1509788624233,"1025628951352":1509788624233,"1025530648932":1509788624436,"1025628951354":1509788624232,"1025628951356":1509788624232,"1015969584002":1480585069071,"1025628951358":1509788624232,"1025530648930":1509788624436,"1025530648952":1509788624434,"1025530648949":1509788624424,"1021325202605":1478686417238,"1021325202606":1478686417238,"1021778983380":1478686417052,"1021325202602":1478686417238,"1021088865610":1478686417094,"1025709568487":1509788667888,"1025709568486":1509788667888,"1018085452405":1480585069073,"1024186996403":1509788624470,"1024781171023":1509788624452,"1024292904047":1509788667902,"1021445272124":1478686417107,"1023958141047":1509788667535,"1021221135707":1478686417235,"1021741089883":1478686417125,"1022241743500":1478686417066,"1025003193892":1509788624462,"1022241743502":1478686417066,"1021340281906":1478686417103,"1021340281915":1478686417103,"1021340281913":1478686417103,"1021376458337":1478686417105,"1021340281918":1478686417103,"1021340281916":1478686417103,"1021745677419":1478686417126,"1363112301":1478686417020,"1016301584624":1480585069066,"1020294049524":1465470268284,"1025891236693":1509788667458,"1021340281901":1478686417103,"1021429674305":1509788624399,"1024579054874":1509788624925,"1363112282":1478686417020,"1023062381506":1509788624533,"1025607199348":1509788624915,"1022143225062":1478686417184,"1021589060582":1509788624397,"1025607199328":1509788624836,"1025627122765":1509788624553,"360265208":1478686417018,"1025627122764":1509788624441,"1024879476732":1509788624478,"1025627122767":1509788624553,"1024879476734":1509788624478,"1025627122766":1509788624553,"1024879476729":1509788624478,"1024879476728":1509788624478,"1021389828088":1478686417105,"1025627122763":1509788624553,"1024879476725":1509788624478,"1024879476727":1509788624478,"1022235320732":1478686417193,"1024073879533":1491634246514,"1025880750883":1509788667811,"1021165036110":1478686417003,"1025407164263":1509788624461,"1021934030975":1478686804039,"1025627122777":1509788624553,"1025627122778":1509788624441,"1025627122769":1509788624441,"1025881537343":1509788667466,"1025627122771":1509788624441,"1020258135149":1464448510787,"1025627122770":1509788624441,"1024687060053":1509788624448,"1024687060048":1509788624448,"1024687060051":1509788624448,"1024687060050":1509788624448,"1013150630945":1478686804032,"1025908931763":1509788667465,"1024687060047":1509788624448,"1022060124073":1509788624958,"1019448490998":1478686804020,"1021944123575":1478686417144,"1021121634225":1478686417233,"1024412984293":1509788624430,"1021709238945":1478686417122,"1021121634223":1478686417233,"1710048570":1478686417024,"1020007505183":1478686804050,"1020007505184":1478686804050,"1025881537345":1509788667443,"1017064058293":1478686804019,"1021300828737":1478686417004,"1015868270198":1465470268314,"1363112402":1478686417020,"1020801682566":1478686417031,"1024528460472":1509788624237,"1023932057345":1491634246530,"1023932057344":1491634246530,"1021813180629":1478686417052,"1024528460470":1509788624237,"1025018267191":1509788624474,"1025018267189":1509788624473,"1025018267188":1509788624473,"1023561658605":1509788624530,"1025018267186":1509788624474,"1025018267185":1509788624474,"1023561658607":1509788624530,"1025018267184":1509788624474,"1025018267199":1509788624473,"1023932057340":1491634246529,"1025018267198":1509788624474,"1022423411915":1478686417210,"1025018267197":1509788624473,"1025018267196":1509788624474,"1022304397301":1478686417287,"1025018267195":1509788624474,"1025018267194":1509788624474,"1022021850332":1509788624463,"1025018267192":1509788624473,"1023561658598":1509788624530,"1024687453663":1509788624563,"1024687453662":1509788624563,"1025018267173":1509788624474,"1024687453661":1509788624563,"1025018267172":1509788624474,"1024687453660":1509788624563,"1025018267171":1509788624474,"1025018267170":1509788624474,"1024687453658":1509788624563,"1024460302191":1509788625070,"1022633654350":1480585069131,"1025018267183":1509788624473,"1023561658609":1509788624530,"1025018267181":1509788624473,"1025018267180":1509788624473,"147794387":1444487341749,"1025018267179":1509788624473,"1025018267178":1509788624474,"1025018267176":1509788624474,"1017876832225":1478686804018,"1022966041675":1509788625073,"1009848499809":1491634246513,"1018346552293":1478686804026,"1025018267167":1509788624473,"1018346552297":1478686804020,"1025896611318":1509788667443,"1022342539678":1509788625018,"1025018267143":1509788624479,"1025018267142":1509788624479,"1020907852550":1478686417080,"1025018267140":1509788624479,"1024547990027":1509788625070,"1025702490490":1509788624864,"1025018267137":1509788624479,"1025702490488":1509788624864,"1025702490487":1509788624916,"1023251390301":1509788625083,"1017876832248":1478686804015,"1025702490483":1509788624916,"1020907852553":1478686417080,"1017990030652":1478686804031,"1025018267145":1509788624479,"1025018267144":1509788624479,"1025018267255":1509788624474,"1024688108933":1509788624503,"1025018267254":1509788624474,"1024687453582":1509788625160,"1022458015379":1478686417072,"1022633654298":1480585069131,"1025018267251":1509788624474,"1025018267250":1509788624474,"1024687453578":1509788625160,"1025018267249":1509788624474,"1024687453577":1509788625160,"1025018267248":1509788624474,"1024687453576":1509788625160,"1025018267263":1509788624474,"1024687453575":1509788625160,"1025018267262":1509788624474,"1025018267261":1509788624474,"1024597667683":1509788624938,"1021275793766":1478686417004,"1025018267259":1509788624474,"1025018267258":1509788624474,"1025018267257":1509788624474,"1025018267256":1509788624474,"1022633654280":1480585069117,"1023308292176":1509788624814,"1025018267247":1509788624474,"1024215307849":1509788624587,"1022633654274":1480585069149,"1022270317953":1480585069092,"1022270317955":1480585069092,"1022270317957":1480585069092,"1022270317956":1480585069092,"1022633654332":1480585069131,"1022633654321":1480585069117,"1021248792236":1478686417236,"1009931715866":1478686804025,"1022633654313":1480585069131,"1022453428069":1478686417296,"1022633654319":1480585069131,"1025018267200":1509788624474,"1019935152458":1509788624393,"1590919087":1478686804029,"1020258135410":1464448510787,"360264953":1478686417044,"1022010709497":1478686417159,"1024895713764":1509788624303,"1024895713766":1509788624303,"1024895713761":1509788624303,"1025810101856":1509788667449,"1024895713763":1509788624303,"1022939957917":1509788624992,"1025702490590":1509788624269,"1025702490589":1509788624270,"1022010709483":1478686417159,"1022474531137":1478943089536,"1023109699439":1509788625046,"1020554362045":1478686416995,"1022270317947":1480585069092,"1022270317948":1480585069092,"870257279":1478686417020,"1021248792164":1478686417236,"1025702490605":1509788624215,"1024688108903":1509788624503,"1025906048399":1509788667444,"1025018267283":1509788624474,"1025018267282":1509788624474,"1026318652432":1514456869766,"1012160366648":1478686416994,"1025018267281":1509788624474,"1024895713741":1509788624303,"1024688108908":1509788624503,"1025702490595":1509788624227,"1024895713737":1509788624303,"1025018267271":1509788624474,"1025702490622":1509788624207,"1025018267270":1509788624474,"1025018267269":1509788624474,"1024688108912":1509788624503,"1024895713746":1509788624303,"870257254":1478686417020,"1025702490614":1509788624207,"1025018267278":1509788624474,"1024895713758":1509788624303,"1025018267274":1509788624474,"1025018267273":1509788624474,"1025018267272":1509788624474,"1020870889869":1465469681399,"1020615557190":1478686417027,"1023308292293":1509788624419,"1021817374763":1478686417132,"1021603609964":1478686417008,"1025702490524":1509788624838,"1024363176442":1509788624278,"1025782576208":1509788624294,"1025702490518":1509788624838,"1025702490516":1509788624838,"1021568744246":1478686417114,"1022040856420":1478686417170,"1025702490533":1509788624868,"1022040856419":1478686417170,"1025702490528":1509788624838,"1016758770323":1465470268315,"1025042384979":1509788625204,"1022196309694":1478686417280,"1025702490700":1509788625165,"1025702490698":1509788625244,"1025702490697":1509788625245,"1000526173921":1444487341714,"1025784018843":1509788624350,"1025018266943":1509788625188,"1022455393776":1478686417016,"1023855378542":1491634246537,"1025018266941":1509788625188,"4786306884":1509788624162,"1025018266939":1509788625187,"1025784018845":1509788624350,"1012335350045":1509788625017,"1022455393774":1478686417016,"1021493114742":1478686417111,"1025018266903":1509788625179,"1025018266901":1509788625178,"1012126287267":1478686417073,"1025018266898":1509788625179,"1021974270124":1509788624994,"1025702490727":1509788625130,"1021743973995":1478686417126,"1025702490723":1509788625130,"1021974270121":1509788624994,"1021743973997":1478686417126,"1021974270123":1509788624994,"1022876257011":1509788625079,"1020907196435":1478686417032,"1025018266886":1509788625178,"1020907196433":1478686417032,"1022159478701":1478686417278,"1021137379934":1478686417095,"1024781171565":1509788624452,"1025018266883":1509788625180,"1025784018852":1509788624350,"1025018266894":1509788625178,"1025018266892":1509788625179,"1022370064594":1478686417069,"1025018266890":1509788625179,"1021716578782":1509788624396,"1025018266889":1509788625179,"1009849285985":1509788624986,"1025018266998":1509788625187,"1013781440699":1478686804019,"1025702490637":1509788624230,"1012134544709":1478686417223,"4998761399":1509788667393,"1025018266993":1509788625187,"1024363176548":1509788624278,"1025018267007":1509788625188,"1025018267006":1509788625187,"1025018267005":1509788625188,"1025018267004":1509788625188,"1025702490627":1509788624207,"1025018267003":1509788625188,"1025018267002":1509788625187,"1025018267001":1509788625188,"1025018266982":1509788625187,"1022338476707":1478686417202,"1020258135713":1464448510787,"1022517784690":1509788624827,"1025018266976":1509788625187,"1016399627415":1480585069069,"1025018266990":1509788625188,"1025018266989":1509788625188,"1025880750581":1509788667811,"1025018266966":1509788625187,"1010024515759":1491634246521,"1025018266964":1509788625187,"1025018266963":1509788625188,"1025018266960":1509788625188,"1025018266975":1509788625187,"1011579724867":1478950494939,"1025018266950":1509788625188,"1025018266945":1509788625188,"117384323":1444487341703,"1010024515761":1491634246521,"1025018267063":1509788625189,"1025018267061":1509788625189,"1025323276394":1509788624304,"1025018267060":1509788625189,"1025018267059":1509788625188,"1016957363467":1478686804031,"1025018267057":1509788625189,"1022723702140":1509788624394,"1025018267071":1509788625188,"1025018267069":1509788625189,"1019527774961":1509788624317,"1025018267068":1509788625190,"1025018267067":1509788625190,"1025018267065":1509788625188,"1025018267064":1509788625190,"1024363176627":1509788624278,"1025018267047":1509788625190,"360265706":1478686417018,"1025018267044":1509788625190,"1022020409168":1478686417266,"1019527774956":1509788624313,"1025018267041":1509788625190,"1021927476709":1478686417142,"1025018267054":1509788625189,"1025018267053":1509788625189,"1025792276361":1509788624349,"1025018267049":1509788625189,"1690781272":1444487341744,"1012160367361":1478686416994,"1025018267048":1509788625188,"1022849123520":1509788624325,"1021774775498":1478686416983,"1021974269996":1509788624983,"1025018267039":1509788625190,"1020542697297":1509788624321,"1021974269997":1509788624983,"1025018267038":1509788625190,"1025018267037":1509788625190,"1021974269999":1509788624983,"444938280":1444487341745,"1022414106337":1478686417070,"1022594856231":1509788624383,"1021974269995":1509788624983,"1025018267032":1509788625188,"1022226408238":1478686416981,"1021974270005":1509788624983,"1021974270007":1509788624983,"1021974270001":1509788624983,"1021974270002":1509788624983,"1025018267009":1509788625188,"1021974270003":1509788624983,"1025018267008":1509788625187,"1024215307691":1509788624587,"1022226408226":1478686416981,"1021974270011":1509788624983,"1025018267127":1509788624479,"1021974270020":1509788624983,"1025018267126":1509788624479,"1025018267125":1509788624479,"1021974270022":1509788624983,"1025018267123":1509788624479,"1021974270017":1509788624983,"1025018267121":1509788624479,"1025018267134":1509788624480,"1008666016524":1478686804034,"1025018267132":1509788624479,"1021974270024":1509788624983,"1016779087584":1478686804017,"1025018267129":1509788624480,"1022849123502":1509788624325,"1025018267111":1509788624479,"1025018267109":1509788624479,"1023431109379":1509788625084,"1022849123506":1509788624326,"1025018267108":1509788624479,"1025018267106":1509788624479,"1025018267105":1509788624479,"1025018267104":1509788624479,"1022457752844":1480585069117,"1025018267115":1509788624479,"1022849123516":1509788624329,"1021719855372":1478686417123,"1025018267103":1509788624479,"1025018267102":1509788624480,"1025018267101":1509788624480,"1025018267100":1509788624479,"1024299851527":1509788624295,"4564136677":1465469681387,"1025018267076":1509788625189,"1025018267075":1509788625188,"1003492181719":1478686417220,"1025018267074":1509788625189,"1025018266679":1509788624245,"1022457752788":1480585069117,"1025018266678":1509788624245,"1025018266677":1509788624245,"4998761206":1509788667393,"1025018266673":1509788624245,"1025627123659":1509788624433,"1025018266687":1509788624245,"1025018266686":1509788624245,"1025018266682":1509788624246,"1025018266680":1509788624246,"1021259408438":1465470268199,"1025018266657":1509788624246,"1025627123674":1509788624433,"1021259408440":1465470268199,"1021934425084":1509788624464,"1025018266670":1509788624245,"1020917944510":1478686417081,"1025018266644":1509788624246,"1025018266642":1509788624246,"1025018266640":1509788624246,"1363112471":1478686417020,"1025018266655":1509788624246,"1019761085883":1509788624315,"1022426558111":1478686417294,"1010024516093":1491634246526,"678628166":1444487341748,"1024897942388":1509788625023,"1023995103499":1491634246532,"1025018266639":1509788624246,"1025018266638":1509788624245,"1025018266743":1509788624247,"1024274815015":1509788624281,"1008672176673":1509788624361,"1025018266741":1509788624247,"1025018266737":1509788624247,"1021817375397":1478686417132,"1024528460033":1509788624237,"1025018266751":1509788624246,"1019073095385":1465470268236,"1025018266750":1509788624246,"1022393264327":1478686417206,"1024528460035":1509788624237,"1025018266748":1509788624246,"1023453391153":1509788625170,"1024528460036":1509788624237,"1025018266746":1509788624246,"1025018266744":1509788624247,"1021122026528":1478686417233,"1022723833004":1509788624399,"1020580838638":1478686417027,"1025018266735":1509788624247,"1025018266734":1509788624247,"1020580838637":1478686417027,"1025018266730":1509788624246,"1020258135952":1464448510787,"1025322359411":1509788624306,"1025018266706":1509788624246,"1025628958646":1509788624460,"1481079592":1491634246533,"1025018266695":1509788624245,"1025018266694":1509788624246,"1025018266693":1509788624246,"1025018266692":1509788624246,"1021331238796":1478686417103,"1025018266690":1509788624245,"1025018266689":1509788624246,"1023958141744":1509788667535,"1025018266703":1509788624245,"1022155284133":1478686417063,"1025018266700":1509788624246,"1014617020559":1465470268319,"1001962433268":1478686417024,"360265464":1478686417018,"1025018266802":1509788624246,"1021309741478":1478686417041,"1025018266801":1509788624246,"1024991921444":1509788625023,"1024273242127":1509788624277,"1025018266790":1509788624247,"1022437043846":1478686417213,"1025018266798":1509788624247,"1025018266797":1509788624246,"1025018266796":1509788624246,"1025018266795":1509788624247,"1025018266794":1509788624247,"1025018266792":1509788624246,"1023567426065":1509788624381,"1023567426064":1509788624381,"1025018266773":1509788624246,"1023567426067":1509788624381,"1023567426066":1509788624381,"1023567426068":1509788624381,"1025018266769":1509788624246,"1023567426071":1509788624381,"1023567426070":1509788624381,"1025018266783":1509788624246,"1023567426073":1509788624381,"1010848856075":1478686804061,"1025627123556":1509788624335,"1023567426072":1509788624381,"1021934424909":1509788624465,"1023567426075":1509788624381,"1023567426074":1509788624381,"1010848856079":1478686804061,"1025628958590":1509788624460,"1010848856090":1478686804061,"1025018266763":1509788624246,"1023567426061":1509788624381,"1023567426060":1509788624381,"1025018266761":1509788624246,"1023567426063":1509788624381,"1023567426062":1509788624381,"1021086637742":1478686417094,"1025018266868":1509788625179,"1025018266879":1509788625179,"1025018266874":1509788625179,"1025018266855":1509788625179,"1025018266854":1509788625179,"1025018266853":1509788625179,"1025018266851":1509788625179,"1025018266848":1509788625178,"1025018266858":1509788625179,"1025018266837":1509788625179,"1024588098872":1509788624168,"1023630472746":1509788667538,"1025018266832":1509788625179,"1024687453989":1509788624448,"1024687453988":1509788624448,"1024687453987":1509788624448,"1025018266843":1509788625179,"1022188706865":1478686417279,"1024687453986":1509788624448,"1025018266842":1509788625179,"1021990654049":1478686417057,"1021949760497":1478686417145,"1024687453984":1509788624448,"1025018266821":1509788625180,"1025018266820":1509788625178,"1021974794596":1509788624484,"1017720330189":1509788624367,"1025018266827":1509788625180,"1025018266423":1509788624885,"1016539089566":1478686804017,"1025018266422":1509788624885,"1016539089565":1478686804018,"1025627121871":1509788624215,"1025018266421":1509788624885,"1025018266420":1509788624885,"1025679158231":1509788624350,"1025679158230":1509788624351,"1025679158229":1509788624352,"1025018266416":1509788624885,"1019315975955":1509788624302,"1025679158233":1509788624350,"1019315975953":1509788624282,"1025018266428":1509788624885,"1025018266425":1509788624885,"1025018266407":1509788624885,"1022459456430":1478686417016,"1012517542465":1478686417074,"1025018266402":1509788624884,"1835878779":1491634246515,"1835878778":1491634246515,"1835878773":1491634246515,"1025627121877":1509788624215,"1023408169751":1509788625040,"1025627121876":1509788624216,"1025018266414":1509788624885,"1025018266413":1509788624885,"1835878774":1491634246515,"1025018266412":1509788624885,"1000928653067":1444487341754,"1025627121872":1509788624216,"1025018266410":1509788624885,"1024145708836":1509788625035,"1025018266409":1509788624885,"1025627121874":1509788624216,"1025018266408":1509788624885,"1010024648424":1491634246521,"1022081358858":1478686417012,"1021211435058":1478686804033,"4559678441":1465469681386,"1015969589314":1480585069071,"1021881600060":1509788624436,"1025018266369":1509788624884,"1025469310575":1509788624362,"1025018266487":1509788624886,"1004334871469":1444487341756,"1025018266485":1509788624886,"1025018266483":1509788624885,"1025018266495":1509788624886,"1025018266493":1509788624886,"1025018266492":1509788624886,"1025569451024":1509788624308,"1025018266488":1509788624886,"1017808019112":1478686804026,"1021250233343":1478686417100,"1025710093729":1509788624294,"1023537015613":1509788624870,"1020501671443":1480585069077,"1023949884582":1509788667501,"1021680665698":1478686804032,"1018908581668":1509788624315,"1025018266449":1509788624885,"1023949884589":1509788667501,"1025153403744":1509788625007,"1023949884591":1509788667501,"1023949884584":1509788667502,"1023949884587":1509788667501,"1023949884586":1509788667501,"1016847918151":1478686804018,"1025018266439":1509788624885,"1020258134147":1464448510787,"1021928131381":1478686416979,"1025018266437":1509788624885,"1025018266435":1509788624885,"1023949884593":1509788667502,"1023949884592":1509788667501,"1021309742678":1478686417005,"1025018266433":1509788624885,"1023949884595":1509788667501,"1023949884594":1509788667502,"1021614356576":1478686417049,"1022674679999":1480585069070,"1025018266447":1509788624884,"1025018266446":1509788624885,"1025018266445":1509788624884,"1025018266444":1509788624885,"1021600594099":1478686417048,"1025018266442":1509788624885,"1023949884602":1509788667501,"1025018266559":1509788624245,"1523547718":1478950494924,"1025018266557":1509788624245,"1025018266554":1509788624244,"1009310620643":1478686804055,"1025018266533":1509788624886,"1025018266532":1509788624885,"1025018266531":1509788624886,"1025018266530":1509788624885,"1025018266529":1509788624886,"1025018266528":1509788624886,"1023062382387":1509788625100,"1025018266518":1509788624886,"1020962247257":1478686417001,"1025018266515":1509788624885,"1012131529715":1478686416994,"1021211435193":1478686804033,"1025018266513":1509788624886,"1025018266526":1509788624886,"1025018266524":1509788624885,"1025018266522":1509788624886,"1025018266520":1509788624886,"1022397853687":1478686417291,"1025018266501":1509788624886,"1017092238130":1478686804019,"1025018266498":1509788624885,"1021359679900":1509788624467,"1025018266510":1509788624886,"1020911916865":1478686417227,"368259400":1478686804029,"1025018266507":1509788624886,"1020911916868":1478686417227,"1007886110436":1509788624390,"1025018266504":1509788624886,"1022270316577":1480585069091,"1022270316576":1480585069091,"1022270316578":1480585069091,"1021971387924":1478686417149,"1021938750560":1478686417143,"1025018266598":1509788624245,"1025018266595":1509788624244,"1025018266604":1509788624245,"1025018266601":1509788624244,"1019237722944":1509788624314,"1021564026361":1478686417114,"1022480954514":1478943089254,"1025018266581":1509788624245,"1025018266580":1509788624245,"1025018266578":1509788624245,"1021564026366":1478686417114,"1025018266577":1509788624245,"1025018266576":1509788624245,"1025018266591":1509788624245,"1025018266590":1509788624245,"1025018266589":1509788624245,"1025018266588":1509788624244,"1021600593954":1478686417048,"1025018266587":1509788624245,"1025018266585":1509788624245,"1025018266584":1509788624245,"1835878815":1491634246515,"1025018266565":1509788624245,"1835878814":1491634246515,"1025018266564":1509788624245,"1025018266562":1509788624245,"1025018266575":1509788624245,"1020878230784":1509788624960,"1025018266574":1509788624245,"1025796338221":1509788624274,"1025018266571":1509788624245,"1022270316575":1480585069091,"1022270316574":1480585069091,"1025018266164":1509788624572,"1025010270907":1509788624567,"1021729556018":1478686417051,"163261611":1478686804029,"1835878527":1491634246515,"1021387729549":1478686416979,"1025018266148":1509788624571,"1025018266147":1509788624572,"1025018266145":1509788624572,"1025018266144":1509788624572,"1025018266158":1509788624571,"1021955003571":1478686417261,"1025018266154":1509788624572,"219883579":1478686804029,"1021668738553":1478686417248,"1025018266128":1509788624571,"1025018266143":1509788624571,"1010000661881":1491634246516,"1025018266140":1509788624572,"1025018266136":1509788624571,"1024096425254":1509788624970,"1025018266117":1509788624571,"1025593831419":1509788624846,"1022074150275":1509788625019,"1022338346439":1478686417069,"1024687059393":1509788624563,"1025593831421":1509788625000,"1021337659823":1478686417041,"1024687059392":1509788624563,"1025018266114":1509788624571,"1025593831420":1509788624846,"1025018266113":1509788624571,"1025593831423":1509788624846,"1025593831422":1509788624846,"1025811018444":1509788667791,"1025018266123":1509788624572,"1020787527293":1478686417029,"1024779730034":1509788625024,"1025018266121":1509788624572,"1025018266120":1509788624571,"1025018266231":1509788624572,"1025018266228":1509788624572,"1025018266227":1509788624572,"1021759045693":1478686417009,"1025018266225":1509788624572,"1025018266224":1509788624572,"1022285652319":1478686417286,"1025018266239":1509788624572,"1024687059388":1509788624563,"1025018266238":1509788624572,"1024687059391":1509788624563,"1024687059390":1509788624563,"1025018266236":1509788624572,"1025018266232":1509788624572,"1025018266213":1509788624572,"1025018266210":1509788624573,"1025018266209":1509788624573,"1025882980058":1509788667463,"1025018266223":1509788624572,"1025018266222":1509788624572,"1025882980052":1509788667461,"1017808019362":1478686804026,"1025882980054":1509788667447,"1022474139014":1478943089486,"1025882980051":1509788667465,"1025018266216":1509788624572,"1025018266207":1509788624572,"1021925902849":1478686417055,"1018927585609":1509788624312,"1021080475831":1478686417232,"1021885532297":1478686417044,"1018927585603":1509788624312,"1025018266293":1509788624577,"1025018266292":1509788624577,"1025018266291":1509788624577,"1025018266289":1509788624577,"1000526172526":1444487341724,"1025018266288":1509788624577,"1025018266301":1509788624884,"1000526172517":1444487341739,"1012184223622":1478686417025,"1020258134396":1464448510787,"1706377253":1444487341737,"1025018266279":1509788624577,"1025018266277":1509788624577,"1025018266275":1509788624577,"1025018266274":1509788624577,"1025018266273":1509788624577,"1025018266272":1509788624577,"1000526172529":1444487341715,"1008818964281":1509788624372,"1025018266287":1509788624578,"1021436884757":1509788624438,"1025018266285":1509788624578,"1025018266283":1509788624577,"1025018266282":1509788624578,"1025018266280":1509788624577,"1016399627119":1480585069069,"1025018266263":1509788624576,"1025018266271":1509788624577,"1017050163628":1478686804021,"1025018266270":1509788624577,"1025018266269":1509788624578,"1022474138992":1478943089486,"1025018266268":1509788624578,"1025018266267":1509788624577,"1025018266266":1509788624577,"1025018266265":1509788624578,"1025018266264":1509788624578,"1025018266247":1509788624572,"1025018266246":1509788624572,"1025018266244":1509788624572,"1025018266241":1509788624572,"1025018266240":1509788624572,"1022269138602":1478686417197,"1025018266253":1509788624572,"1515290602":1478950494924,"1025018266252":1509788624572,"1025018266249":1509788624572,"1025018266248":1509788624572,"1023535442470":1509788625221,"1025018266359":1509788624884,"1025018266356":1509788624884,"1024687059248":1509788625156,"1017808019248":1478686804026,"1025018266366":1509788624884,"1025018266363":1509788624884,"1025018266360":1509788624884,"1025018266343":1509788624884,"1025018266340":1509788624884,"1025018266336":1509788624884,"1024687059245":1509788625156,"1025018266350":1509788624884,"1024687059244":1509788625156,"1024687059247":1509788625156,"1024687059246":1509788625156,"1025018266346":1509788624884,"1025018266325":1509788624884,"1025018266324":1509788624884,"1025018266323":1509788624884,"1021923936866":1478686417141,"1025018266320":1509788624884,"1835878529":1491634246515,"1025018266331":1509788624884,"1025018266330":1509788624884,"1835878531":1491634246515,"1025018266329":1509788624884,"1025018266328":1509788624884,"1021685777449":1509788624400,"1025018266308":1509788624884,"1025018266305":1509788624884,"1025896085811":1509788667463,"1025018266304":1509788624884,"1025018266316":1509788624884,"1025018266313":1509788624884,"1021221135209":1478686417235,"1018994320935":1509788624282,"1018469091227":1509788624199,"1020806662693":1478686416991,"1025879965120":1509788667405,"1021221135221":1478686417235,"1006617852397":1509788624386,"1023062381963":1509788624419,"1017808018648":1478686804026,"1023958142564":1509788667535,"1025607724083":1509788625084,"1025607724082":1509788625084,"1025902639692":1509788667460,"409681499":1491634246510,"1021730604340":1478686417124,"1021730604341":1478686417124,"1021730604338":1478686417124,"1020852799804":1478686417078,"1024529247261":1509788624905,"1024142693639":1509788667499,"1024529247260":1509788624904,"1022270317219":1480585069092,"1024529247263":1509788624905,"1022270317218":1480585069092,"1024529247262":1509788624904,"1022270317221":1480585069092,"1024529247257":1509788624904,"1022270317220":1480585069092,"1024529247256":1509788624904,"1022270317223":1480585069092,"1024529247259":1509788624904,"1022270317225":1480585069092,"1024529247252":1509788624904,"1024529247255":1509788624904,"1024529247254":1509788624904,"1024529247249":1509788624904,"1024529247248":1509788624904,"1013389710367":1444487341759,"1024529247250":1509788624904,"1024529247246":1509788624904,"1024142693652":1509788667499,"1024529247241":1509788624904,"1024529247237":1509788624905,"1024529247239":1509788624905,"1024529247238":1509788624904,"1018513654421":1509788624825,"1024529247232":1509788624904,"1022943890054":1509788625104,"1024529247235":1509788624905,"1023535442426":1509788625221,"1000307802224":1478686417018,"1025770910251":1509788624521,"1021892610836":1478686417138,"1021600594618":1478686417048,"1022299677526":1478686417015,"1021001309948":1478686417230,"1024529247264":1509788624904,"1020258134668":1464448510787,"1020007504828":1478686804050,"409681428":1491634246510,"1024529247266":1509788624904,"1022306754644":1478686417015,"1022188181829":1478686417187,"4563613330":1465469681386,"1025909848707":1509788667443,"1060051390":1444487341718,"228272901":1444487341728,"1021809512154":1509788624399,"1022506513519":1509788667538,"1021120584140":1478686417037,"1008044315218":1478686804030,"1021283921668":1465469681396,"1020819377104":1509788624311,"1016444194454":1478686804023,"1022306754665":1478686417015,"4994830089":1509788667394,"1025018266101":1509788624572,"1021644241042":1509788624815,"1025018266110":1509788624571,"1025018266109":1509788624572,"1026232407571":1514456869770,"1025018266108":1509788624572,"1026232407573":1514456869770,"1026232407572":1514456869769,"1026232407575":1514456869769,"1026232407574":1514456869768,"1025018266087":1509788624572,"1025018266084":1509788624571,"1835879349":1491634246515,"1025018266095":1509788624572,"1023537015224":1509788624233,"1025531830338":1509788624346,"1022237549614":1478686417065,"1835879350":1491634246515,"1023453392038":1509788625170,"1025018266090":1509788624572,"1835879346":1491634246515,"1019827541112":1509788624322,"1021926164871":1509788624465,"1021221135233":1478686417235,"1022033777653":1478686417267,"1002453942510":1491634246518,"1022033777655":1478686417267,"1022352895716":1478686417203,"1023453392011":1509788625170,"1021398743031":1478686417043,"1020007504579":1478686804050,"1020007504580":1478686804050,"1020667593568":1478686417075,"1024597666087":1509788624939,"1020570089806":1509788624386,"1020570089807":1509788624386,"1022021849804":1509788624180,"1021920790778":1509788625019,"1025629612937":1509788625021,"1020294048158":1465470268284,"1022080311143":1509788624416,"1024273243308":1509788624277,"1025507451611":1509788624339,"1025507451609":1509788624339,"1025507451608":1509788624341,"1022280934175":1478686417285,"1025494475652":1509788624337,"1021743579926":1478686417125,"1022141258726":1478686417277,"1020966834666":1478686417086,"1021986854042":1509788624509,"1020074632871":1465470268315,"1024783400529":1509788625019,"1020258134939":1464448510787,"1021817376400":1478686417132,"1024993100225":1509788624904,"1023152824113":1509788625045,"1020904052210":1478686417032,"1024687059829":1509788624223,"1024687059828":1509788624859,"1024687059831":1509788624859,"1024687059825":1509788624223,"1022106787111":1478686417182,"1024687059824":1509788624223,"1024687059827":1509788624859,"1024687059826":1509788624859,"1021654071350":1509788624818,"1023535441933":1509788625221,"1020904052203":1478686417032,"1024687059820":1509788624223,"1024687059823":1509788624223,"1024687059822":1509788624859,"1022111505892":1509788624944,"135606198":1478686417023,"1022629068340":1509788624434,"1024142693622":1509788667499,"1024142693621":1509788667500,"1024142693618":1509788667500,"1024142693631":1509788667499,"1025569451933":1509788624350,"1025569451931":1509788624351,"1025508106796":1509788624338,"1021348670014":1478686417041,"1025508106793":1509788624341,"1025879964694":1509788667405,"1025508106795":1509788624342,"1025508106794":1509788624337,"340472729":1444487341753,"1015810204725":1478686804016,"1022073495399":1509788624280,"1018546553130":1480585069070,"1024362915834":1509788667509,"1024362915832":1509788667508,"1022038102331":1478686417168,"340472749":1444487341752,"1024145708243":1509788625035,"1024804371480":1509788624426,"1021342510047":1478686417103,"1023821170530":1509788624960,"1025880620071":1509788667811,"1016244714487":1480585069063,"1020007504445":1478686804050,"1025569451938":1509788624351,"1002069387030":1478686804059,"1024303257046":1509788624177,"1015969588328":1480585069071,"1021301744312":1480585069071,"1021955529132":1509788624464,"1024303257049":1509788624177,"1024303257048":1509788624176,"1021741223032":1478686417125,"1017092237203":1478686804019,"1176596021":1478686804033,"1024304698794":1509788624277,"1024304698791":1509788624277,"1025497492635":1509788624367,"1024362915852":1509788667508,"1024362915851":1509788667508,"1024362915850":1509788667509,"1022020017632":1478686417161,"1024444706153":1509788625030,"1024362915849":1509788667508,"1021839000197":1478686417135,"1024362915862":1509788667508,"1024183852736":1509788624517,"1016217842581":1480585069069,"1024183852741":1509788624517,"1024362915857":1509788667508,"1024566469693":1509788624520,"1024566469695":1509788624520,"1024566469691":1509788624520,"423047432":1491634246508,"1024183852723":1509788624516,"1024566469701":1509788624520,"1024518365856":1509788624563,"1025296666843":1509788624507,"1024566469697":1509788624520,"1024183852726":1509788624517,"1024566469696":1509788624520,"1025296666841":1509788624507,"1024566469699":1509788624520,"1020878231998":1509788624945,"1024566469709":1509788624520,"1024183852730":1509788624517,"1024566469708":1509788624520,"1024566469710":1509788624520,"1024566469707":1509788624520,"1022517394025":1509788625064,"1024566469717":1509788624520,"1006074140170":1478686804025,"1024183852704":1509788624517,"1022192244702":1478686417279,"1024566469714":1509788624520,"1024566469721":1509788624520,"1022081486974":1478686417178,"1024183852717":1509788624516,"1024183852690":1509788624516,"1019963855388":1478686804021,"1025507191907":1509788624344,"1025507191906":1509788624335,"1024183852674":1509788624517,"1025507191905":1509788624341,"1025507191910":1509788624339,"1020025591512":1509788624300,"1025507191908":1509788624339,"1016571730161":1480585069075,"1024518365850":1509788624563,"1024183852687":1509788624517,"1024518365855":1509788624563,"1024518365854":1509788624563,"1020258133132":1464448510787,"1021740174566":1478686417124,"1024518365853":1509788624563,"1024183852663":1509788624516,"1022238861895":1509788624946,"1024183852660":1509788624516,"1022238861897":1509788624933,"1025532882662":1509788624336,"1025629479992":1509788625022,"1021051376409":1478686417036,"1023389560510":1509788624273,"1016771351615":1465470268255,"1024183852651":1509788624517,"1016771351614":1465470268255,"1016771351612":1465470268255,"1023947784313":1491634246532,"1016771351608":1465470268255,"199041919":1444487341719,"1024183852624":1509788624517,"1020477813118":1465470268302,"1021300302453":1478686417102,"1024183852633":1509788624517,"1022479644887":1478943089487,"1022024342846":1509788624466,"1024183852621":1509788624516,"1021300302447":1478686417102,"270481630":1444487341746,"1022921605838":1509788624294,"1023617105018":1509788624970,"1023389560553":1509788624273,"1021517627161":1509788624815,"1021427972594":1478686804026,"1020982697834":1478686417001,"1023389560547":1509788624273,"1023389560546":1509788624273,"1021839000190":1478686417134,"1026232277009":1514456869769,"1023389560551":1509788624273,"1026232277013":1514456869769,"1023389560548":1509788624273,"1014765284493":1478686804024,"1023389560562":1509788624273,"1023389560561":1509788624273,"1021688662355":1509788624404,"1023389560523":1509788624273,"1023389560522":1509788624273,"1024687455277":1509788624223,"1016771351620":1465470268256,"1021984103153":1478686417152,"1024687455276":1509788624223,"1023389560520":1509788624273,"1016771351619":1465470268256,"1024687455275":1509788624223,"1023389560527":1509788624273,"1024687455274":1509788624223,"1016771351617":1465470268255,"1024687455273":1509788624223,"1023389560525":1509788624273,"606014708":1491634246506,"1023389560512":1509788624273,"1023389560518":1509788624273,"1023389560539":1509788624273,"1025590419949":1509788624344,"1022907712023":1509788624298,"1023389560542":1509788624273,"1021944125575":1478686416992,"1021722086267":1509788624403,"1026232277027":1514456869769,"1019248994285":1509788624313,"1026232277031":1514456869769,"1023389560534":1509788624273,"1000037678837":1478686417021,"270481632":1444487341743,"1023389560532":1509788624273,"2006146709":1491634246533,"1015242115267":1480585069068,"1020999864757":1478686417230,"1021969030137":1509788624194,"1019264989458":1478686804023,"1022305972185":1478686417287,"1022073491876":1509788624300,"1022111765357":1478686417013,"1025373869305":1509788624307,"1025593435114":1509788624566,"1022909285348":1509788624999,"1020852930127":1478686416976,"1002079353162":1478686804033,"1021985020631":1478686417152,"1021985413830":1478686417153,"1005987762269":1478686804033,"1024672250603":1509788624801,"1024672250602":1509788624801,"1025627121030":1509788624850,"1025627121024":1509788624850,"1012413600040":1478686417223,"1000037678941":1478686417021,"1021502160895":1478686417244,"1019384263045":1509788624933,"1020898155467":1478686417079,"1020898155468":1478686417080,"1024459124483":1509788625000,"1007146325786":1509788624375,"1024459124480":1509788625005,"1020898155461":1478686417079,"1020025591745":1509788624300,"1007886107435":1509788624373,"1020258133376":1464448510787,"1021311050612":1465470268203,"1021311050614":1465470268203,"1021311050615":1465470268204,"1023444083606":1509788624969,"1007910356406":1478686804023,"1025068467131":1509788625221,"1025068467133":1509788625223,"1025068467132":1509788625223,"1022450411426":1478686417296,"1024520463178":1509788625028,"1021654070828":1509788624195,"1024481144483":1509788624298,"1025593434982":1509788625167,"4998365253":1509788667393,"1025627121021":1509788624850,"1017974697305":1509788624363,"1025627121023":1509788624850,"1017857692756":1465470268241,"1025627121022":1509788624850,"1020900383549":1465470268303,"1024518365987":1509788625161,"1024518365986":1509788625161,"1024518365985":1509788625161,"1024518365984":1509788625160,"1024669760057":1509788625150,"1020900383564":1465470268303,"1024669760059":1509788625150,"1024518365988":1509788625161,"1024669760053":1509788625150,"1024669760055":1509788625150,"1024669760054":1509788625150,"1017092236883":1478686804019,"1017260798030":1465470268269,"1025068467169":1509788625221,"1025068467171":1509788625221,"1025068467170":1509788625222,"1025068467174":1509788625221,"1016522572923":1478686804046,"1025068467160":1509788625222,"1025068467162":1509788625222,"1025068467165":1509788625222,"1025068467164":1509788625222,"1025068467167":1509788625223,"1025068467153":1509788625222,"1025068467152":1509788625222,"1022170093331":1478686417063,"4821038774":1509788624157,"1025068467157":1509788625222,"1025068467156":1509788625222,"1023453389714":1509788624569,"1025068467158":1509788625222,"1000037679099":1478686417021,"1020821603498":1478686417078,"1025068467147":1509788625222,"1025068467146":1509788625222,"1025068467150":1509788625222,"1025068467140":1509788625222,"1022073491776":1509788624300,"1023774521179":1491634246535,"1022292995979":1478686417068,"1022082667071":1478686417272,"4808979637":1509788624157,"1021654070694":1509788624534,"1024115431678":1509788667538,"1025910896577":1509788667579,"1024459123784":1509788624998,"1025910896576":1509788667579,"1009848497510":1491634246513,"1024459123778":1509788625005,"1020087348016":1509788625078,"1022077948503":1478686417272,"1020087348017":1509788624354,"1024459123781":1509788624999,"1020087348018":1509788625078,"1022482397810":1478943089488,"1020087348012":1509788625077,"1020087348013":1509788625078,"1020850701737":1478686804057,"1021377111050":1478686416980,"1020087348006":1509788625076,"1020087348007":1509788625078,"1024566470221":1509788667536,"1025609163190":1509788625242,"1024566470229":1509788667536,"1024579053335":1509788624932,"1024566470231":1509788667536,"1024566470224":1509788667536,"1023033547573":1509788625073,"1024566470227":1509788667536,"5000724552":1509788667393,"1024566470237":1509788667536,"1024566470238":1509788667536,"1025910896574":1509788667579,"1024566470235":1509788667536,"1024566470244":1509788667536,"1024566470247":1509788667536,"1022460372457":1480585069075,"1024566470253":1509788667536,"1021138823706":1478686417002,"1024566470261":1509788667536,"1024566470260":1509788667536,"1024566470263":1509788667536,"1024566470257":1509788667536,"1020258133636":1464448510787,"1024566470265":1509788667536,"1020874562224":1478686416999,"1024225530612":1509788624969,"1024183852158":1509788624516,"1022411482649":1478686417208,"1020923189693":1478686417081,"1022361412363":1478686417203,"1022361412360":1478686417203,"1023958139611":1509788667535,"4998366066":1509788667393,"1022262323678":1478686417067,"1025593434215":1509788624866,"1024241783762":1509788624473,"1270309145":1444487341731,"1021724051745":1478686417051,"1025090750077":1509788624292,"1020923189648":1478686417081,"1001886150463":1478686804032,"1024459123875":1509788624259,"1021233589348":1478686417099,"1024459123873":1509788624426,"1025050903535":1509788624457,"1024459123876":1509788624259,"1025823604197":1509788667449,"1025823604196":1509788667447,"1025823604194":1509788667441,"1025394054153":1509788667826,"1020923189706":1478686417081,"1024459123865":1509788624456,"1023862327534":1491634246520,"1024459123870":1509788624438,"1020973915357":1478686417034,"1024782218195":1509788625069,"1020978240738":1478686417230,"4562298107":1465469681388,"1024991923633":1509788624939,"1023795098886":1509788624373,"1023062382775":1509788624194,"1022068118466":1478686417060,"1024528458111":1509788624237,"1025627121549":1509788625145,"1025627121548":1509788625145,"1025627121551":1509788625145,"1025627121550":1509788625145,"1021613176651":1478686417247,"1023018212104":1509788624439,"1022201287771":1478686417190,"1022460765376":1480585069077,"1025295750086":1509788624946,"1022068118463":1478686417060,"1024241783339":1509788624883,"1020961070525":1478686417085,"1025796341135":1509788624274,"1025627121556":1509788625145,"1023062382792":1509788624815,"1022188704954":1478686417278,"1022188704955":1478686417278,"1021600593844":1478686417048,"1020258133878":1464448510787,"1022483839906":1478943089231,"1023821827041":1491634246536,"1022483839904":1478943089231,"1021011530336":1478686417231,"1024161701812":1509788667562,"1022078342121":1478686417177,"1000527486813":1444487341710,"1024798339571":1509788624211,"1022483839878":1478943089231,"1025907750802":1509788667464,"1020294046988":1465470268284,"1021540168643":1478686417047,"1022483839888":1478943089231,"1022483839900":1478943089231,"1022483839897":1478943089231,"1610052681":1509788624380,"1025907750796":1509788667461,"1025070170583":1509788624293,"1025269669353":1509788624359,"1020799453015":1478686417029,"1021161368315":1478686417097,"1304782374":1491634246508,"1024528458146":1509788625175,"1021439506838":1478686417107,"1022931173473":1509788624461,"1025911289344":1509788667463,"1024528458167":1509788624237,"1025671946785":1509788624942,"1615285318":1478686804029,"1021011793376":1478686417231,"1021767305973":1509788624533,"1023018212440":1509788624565,"1021937835206":1478686804072,"1024983927099":1509788624924,"1024983927103":1509788624924,"1021311051308":1465470268204,"1021311051309":1465470268204,"1022488559070":1478943089254,"1021311051304":1465470268204,"1021311051305":1465470268204,"1021311051306":1465470268204,"1021311051307":1465470268204,"1022526570379":1509788625083,"1020967492281":1478686417229,"1019778646865":1509788624366,"1022526570371":1509788624393,"1009158969948":1478686804040,"1022526570374":1509788624393,"1021880418425":1478686417053,"4625088485":1478686416965,"1025529998078":1509788624337,"1025608902570":1509788624929,"1010848856046":1478686804061,"1032393169":1444487341716,"1021772679889":1478686417128,"1032393171":1444487341754,"1017229998867":1509788624941,"1017229998866":1509788624941,"1024983927106":1509788624924,"1020793290890":1478686416976,"1020793290891":1478686416976,"1024687454378":1509788624859,"1024687454377":1509788624859,"1024687454376":1509788624859,"1024983927108":1509788624924,"1021937835192":1478686804072,"1024687454375":1509788624859,"1024687454374":1509788624859,"1022868785978":1509788625054,"1012149486676":1478686417025,"1025050903901":1509788624457,"1021195579243":1478881022015,"1023021751478":1509788624992,"1020258132087":1464448510787,"1013127958351":1478686804058,"1024973310272":1509788624288,"1021006025947":1509788624920,"1017229999051":1509788624941,"1020244502309":1465470268316,"1008997875862":1478686804030,"1025283038147":1509788624363,"1018989341727":1509788624312,"4560593733":1465469681388,"1022618580138":1509788625062,"1025906307213":1509788667463,"1025906307214":1509788667461,"1022417248404":1478686417209,"1022417248403":1478686417209,"1021743712498":1478686416972,"1008828927666":1509788624372,"1022526570367":1509788624393,"1021088731530":1478686417002,"1016897466341":1478686804053,"1020057332738":1509788624369,"1023958140044":1509788667535,"1018121232611":1478686804018,"1021827597719":1509788624590,"1021630476757":1478686417049,"1024096427226":1509788624972,"1024945000269":1509788624406,"1021827597726":1509788624591,"1021827597727":1509788624590,"1021827597724":1509788624591,"1021827597725":1509788624591,"1021827597722":1509788624591,"1021827597723":1509788624591,"1021827597720":1509788624592,"1025295750227":1509788624946,"1021827597721":1509788624592,"1000527878161":1444487341713,"1021827597733":1509788624591,"1021827597730":1509788624591,"1022270187526":1480585069092,"1021827597731":1509788624591,"1022270187525":1480585069092,"1021827597728":1509788624591,"1021827597729":1509788624591,"1022270187531":1480585069092,"1022608487473":1509788624994,"1022270187530":1480585069092,"1021827597743":1509788624591,"1022270187529":1480585069092,"1022270187535":1480585069092,"1021827597738":1509788624590,"1021840705139":1509788624394,"1021827597736":1509788624590,"1022270187532":1480585069092,"1022270187539":1480585069092,"1022270187538":1480585069092,"1022454604560":1478686417072,"1013127958335":1478686804058,"1022270187541":1480585069092,"1021827597744":1509788624592,"1000527878148":1444487341715,"1022270187546":1480585069092,"1022270187544":1480585069092,"1012994405":1444487341726,"1021120582254":1478686417037,"803537632":1509788625081,"1006898594359":1509788624388,"1021120582246":1478686417037,"1013020881241":1478686804024,"1021926949480":1478686417141,"1011857078936":1478686804024,"1009382141475":1478686804046,"1022667077196":1509788625060,"1021628248126":1478686417008,"1021885530348":1478686417044,"1022269140530":1478686417197,"1021005370727":1478686417231,"1019527515479":1509788624375,"1022417903903":1478686417302,"803537611":1509788625081,"1021120582236":1478686417037,"559615084":1478686804033,"1022053833469":1509788625075,"803537618":1509788625081,"1021133188496":1465470268251,"1021257181817":1495284743408,"1010024515465":1491634246521,"1021743712522":1478686416972,"1021476600070":1478686417109,"1022414758160":1478686417208,"1023791821576":1509788624177,"1021767306151":1509788624817,"1025067812728":1509788624304,"1021628248135":1478686417008,"1000087483478":1478686804024,"1017119112323":1465470268241,"139273510":1491634246512,"2006145788":1491634246533,"803537552":1509788625081,"1021122941502":1478686417095,"1022436778093":1478686417213,"1022436778094":1478686417213,"1021551703208":1509788624865,"803537562":1509788625081,"1009106017807":1478686804054,"1025142260305":1509788624424,"1009106017806":1478686804054,"1008055720367":1480585069062,"1022398244555":1478686417070,"1025042383926":1509788624495,"803537527":1509788625081,"1021353517079":1478686417006,"1002080009698":1478686804029,"1021767306086":1509788624194,"1020258132332":1464448510787,"1020911918692":1478686417032,"1017176389920":1478686804070,"1021236603699":1478686417003,"1021633622855":1509788624404,"1022202204838":1480585069084,"1021551703138":1509788624865,"1000307805102":1478686417018,"1006332633934":1478686417018,"1019963856817":1478686804021,"1024672251420":1509788624801,"1018168025783":1509788625017,"1018168025778":1509788625017,"1017949663164":1478686804046,"1018168025786":1509788625080,"1012341905742":1478686417026,"1016779084241":1478686804017,"1024167861187":1509788625035,"1023021751857":1509788624992,"1023021751856":1509788624992,"1577414667":1491634246513,"1023958140489":1509788667535,"1023021751854":1509788624992,"1023021751853":1509788624992,"1023021751852":1509788624992,"1013389712460":1444487341759,"1021246958035":1478686417003,"1010000660071":1491634246516,"1025671946339":1509788624942,"1022081357413":1478686417012,"1021605704408":1478686417048,"1021605704406":1478686417048,"1017168264526":1478686804022,"1021042988121":1478686417001,"1017168264520":1478686804040,"1021969030313":1509788624816,"1007910355606":1478686804023,"1022491836367":1478943089315,"1409252764":1444487341755,"1022067988849":1478686804035,"1585541351":1478686804033,"1023173662565":1509788625044,"1018673169215":1509788625019,"1021143281270":1465470268252,"1828012687":1491634246508,"1021865477498":1509788624394,"1021071299073":1478686417093,"1020258132622":1464448510787,"1025495919299":1509788624307,"1022067988847":1478686804035,"1024096034447":1509788624522,"1024096034444":1509788624522,"1024096034439":1509788624523,"1021841884411":1509788625003,"1021841884415":1509788625003,"1024096034455":1509788624522,"1024096034453":1509788624522,"1017176390172":1478686804070,"1024096034476":1509788624522,"1024096034475":1509788624522,"1024096034472":1509788624522,"1526297680":1444487341748,"1019723465221":1478686804021,"1021120582106":1478686417037,"1024096034495":1509788624522,"1021606490658":1509788624397,"1022336902750":1478686417201,"1025796339808":1509788624274,"1022336902739":1478686417201,"1024096034485":1509788624522,"1024096034481":1509788624522,"1019146102762":1509788624316,"1024688110101":1509788624503,"1162308502":1478686804029,"1021969030177":1509788624533,"1024688110099":1509788624503,"1024167861017":1509788625035,"1021465852420":1478686417242,"1024840807249":1509788624174,"1022398506406":1478686417207,"1023626935035":1509788624553,"1020999473057":1509788624934,"1021484202713":1478686804039,"4667947305":1478686416965,"1023173006886":1509788624507,"1023173006890":1509788624507,"1025671946556":1509788624942,"1023310261752":1509788625041,"1021721562259":1478686417123,"1019730674550":1509788624960,"1025614800060":1509788624824,"1025218157588":1509788624922,"1021143281463":1465470268252,"1021734144944":1478686417124,"1022077949738":1478686417177,"1023319829795":1509788624182,"1023995102565":1491634246532,"1018905695287":1509788624282,"1304257254":1444487341738,"1021841884424":1509788625003,"1021138824979":1478686417233,"1021841884428":1509788625003,"1022077949727":1478686417177,"1020378201282":1465470268321,"1021841884419":1509788625003,"1021841884421":1509788625003,"1022383170888":1478686417205,"1021841884423":1509788625003,"1021841884436":1509788625003,"1406499923":1478686417024,"1025127973131":1509788624183,"1020258132842":1464448510787,"1538880541":1444487341703,"1023932188756":1491634246531,"1023932188762":1491634246531,"1022233357978":1509788624175,"1021514086821":1478686416973,"1021886579318":1478686417054,"1026232409965":1514456869769,"1026232409964":1514456869770,"1021279070114":1509788624940,"1010011670079":1491634246525,"1010011670092":1491634246526,"1024430812157":1509788667890,"1010011670084":1491634246526,"1024264852945":1509788624408,"1024264852944":1509788624426,"1024264852943":1509788624432,"1012173604101":1478686417025,"1024264852942":1509788624429,"1523414303":1478950494924,"1021842015676":1509788624394,"1022257736822":1478686417196,"1001813798856":1478686804054,"1021148917308":1478686417234,"1025172151814":1509788624226,"1022148727762":1478686417277,"1012399970465":1478686416994,"1022633260712":1509788625060,"1021969030414":1509788624419,"1025565910894":1509788624335,"1019416245986":1480585069074,"1019416245987":1480585069074,"1024587316933":1509788624248,"1024265112095":1509788624224,"1024587316931":1509788624248,"1024587316929":1509788624248,"1024587316928":1509788624248,"1021515655158":1478686417112,"1022904572216":1509788624250,"4994832825":1509788667394,"1020443338708":1478686417224,"1020243065804":1478686804049,"1022051206667":1478686417174,"1024528202348":1509788625027,"1024727819845":1509788624278,"1022836806936":1509788624535,"1024433829316":1509788624474,"1022836806935":1509788624535,"1021048753122":1478686417001,"1025643118025":1509788624365,"1025643118024":1509788624365,"1025643118027":1509788624365,"1025643118026":1509788624365,"1022051206694":1478686417174,"1025643118028":1509788624365,"1024265112099":1509788624224,"1024265112098":1509788624224,"1024265112097":1509788624224,"1022051206697":1478686417174,"1024265112096":1509788624224,"1020740868171":1478686417028,"1021997466478":1478686417156,"1024587316879":1509788624248,"1024495564823":1509788624935,"1024587316878":1509788624248,"1024587316877":1509788624248,"1024495564819":1509788624935,"1024495564817":1509788624935,"1024495564816":1509788624935,"1024495564812":1509788624935,"1024985503071":1509788624279,"1024587316882":1509788624248,"1024495564809":1509788624935,"1024587316880":1509788624248,"1024587316895":1509788624248,"1020900639453":1478686417080,"1024587316892":1509788624248,"1024587316888":1509788624248,"1024495564800":1509788624935,"1024495564863":1509788624935,"1024495564862":1509788624935,"1024195118661":1509788624184,"1024495564861":1509788624935,"1024587316898":1509788624248,"1016968247436":1478686804024,"1024195118656":1509788624184,"1024587316911":1509788624248,"1022904572251":1509788624250,"1024587316909":1509788624248,"1024967939165":1509788624342,"1024587316908":1509788624248,"1025901980679":1509788667450,"1024495564850":1509788624935,"1198487297":1444487341746,"1024495564849":1509788624935,"1024587316904":1509788624248,"1023328351134":1509788624589,"1021481706896":1478686417110,"1024195118678":1509788624184,"1024587316918":1509788624248,"1024587316917":1509788624248,"1021951328661":1478686417261,"1022228246807":1478686417065,"1024587316915":1509788624248,"1021141446749":1478686417096,"1024195118674":1509788624184,"1024495564842":1509788624935,"1024195118687":1509788624185,"1019386489023":1509788624316,"1024587316924":1509788624248,"1024587316923":1509788624248,"1024587316922":1509788624248,"1024495564834":1509788624935,"1021935206534":1509788624464,"1025372687507":1509788625110,"1025372687506":1509788625126,"1020241099632":1478686804039,"1025372687505":1509788625117,"1024587316814":1509788624244,"1024587316813":1509788624244,"1024587316812":1509788624243,"1025372687514":1509788625089,"1024587316820":1509788624244,"1024587316819":1509788624244,"1024587316818":1509788624244,"1024587316817":1509788624244,"1024587316830":1509788624244,"1024587316826":1509788624244,"1024587316824":1509788624244,"1024587316839":1509788624244,"1025407029067":1509788624546,"1024587316837":1509788624244,"1024587316835":1509788624244,"1025407029070":1509788624546,"1023612249152":1509788624955,"1024587316832":1509788624244,"1025407029068":1509788624546,"1024587316846":1509788624244,"1003408699282":1478686804054,"1018967297896":1509788624453,"1024587316844":1509788624244,"1024587316842":1509788624244,"1025407029061":1509788624539,"1024587316840":1509788624244,"1024587316854":1509788624243,"1017558326126":1509788624372,"1024587316853":1509788624244,"1001519652708":1478686417022,"1024587316850":1509788624243,"1024587316848":1509788624244,"1020558814815":1478686416995,"1000968371720":1478686804028,"1023529942897":1509788624424,"1024444315120":1509788624440,"1024587316857":1509788624243,"1003408699271":1478686804054,"1025407029076":1509788624546,"1022078339248":1478686417177,"1025643117883":1509788624365,"1025643117882":1509788624365,"1025643117885":1509788624365,"1021981344508":1509788624466,"1025643117884":1509788624365,"1025643117887":1509788624365,"1023612249123":1509788624955,"1022674152456":1480585069077,"1025643117886":1509788624365,"1024444315018":1509788624435,"1024587316751":1509788625194,"1024587316750":1509788625194,"1024587316749":1509788625194,"1024587316748":1509788625194,"1024535280429":1509788625027,"115684904":1444487341751,"1021797849029":1509788624269,"1024587316746":1509788625192,"1023612249130":1509788624955,"1024587316759":1509788625194,"1023612249140":1509788624955,"1024587316758":1509788625194,"1025407029048":1509788624611,"1023612249142":1509788624955,"1024587316755":1509788625194,"1023612249136":1509788624955,"1826053121":1444487341704,"1021537413220":1509788624397,"1023612249138":1509788624955,"1020956214670":1478686417085,"1023612249149":1509788624955,"1024587316767":1509788625193,"1023612249148":1509788624955,"1024587316765":1509788625193,"1025407029046":1509788624612,"1024587316762":1509788625193,"1024587316775":1509788625193,"1024587316772":1509788625193,"1024587316782":1509788625193,"1024587316781":1509788625194,"1024587316780":1509788625194,"1024587316779":1509788625192,"1021742797982":1509788624395,"1024587316777":1509788625192,"1024587316776":1509788625193,"1024587316791":1509788625192,"1020294053468":1465470268285,"1023612249110":1509788624955,"1024587316786":1509788625193,"1024587316784":1509788625192,"1024587316799":1509788625192,"1023612249119":1509788624955,"1023612249118":1509788624955,"1023612249114":1509788624955,"1023877927437":1491634246506,"1022836806713":1509788624820,"1022836806715":1509788624820,"1015241199863":1480585069068,"1022090528948":1478686417180,"1052708785":1478950494920,"1023306723380":1509788625157,"1024002710191":1491634246532,"1024002710190":1491634246532,"1023306723370":1509788625157,"1023306723368":1509788625157,"1826053581":1444487341701,"1023306723367":1509788625157,"1023306723365":1509788625157,"1023626667300":1509788624552,"1016952125139":1444487341759,"1013855502241":1478686804027,"1020443338483":1478686417224,"1024587317244":1509788624876,"1024964138317":1509788624915,"1025407028907":1509788625144,"1022857909945":1509788625074,"1025407028905":1509788625113,"1024529513242":1509788624236,"1025407028911":1509788625131,"1021024634980":1478686417091,"1025407028909":1509788625131,"1025407028908":1509788625132,"1024587317135":1509788624239,"1021926956592":1478686417141,"1024587317132":1509788624239,"1012233510006":1478686417073,"1024587317130":1509788624238,"1025407028902":1509788625165,"1023924721419":1509788624970,"1008082454464":1478686804023,"1024587317143":1509788624239,"1024587317142":1509788624239,"1024587317141":1509788624239,"1024587317140":1509788624239,"1025407028920":1509788625169,"1024587317137":1509788624239,"1024587317150":1509788624239,"4994832623":1509788667394,"1024587317149":1509788624239,"1025407028913":1509788625132,"1024587317148":1509788624239,"1024587317147":1509788624239,"1022032069739":1478686417165,"1001519652494":1478686417022,"1021332159888":1478686417103,"1024587317145":1509788624239,"1024587317159":1509788624239,"1024587317157":1509788624239,"1024587317156":1509788624239,"1024587317155":1509788624239,"1024587317154":1509788624239,"1024587317153":1509788624239,"1024587317152":1509788624239,"1016677500727":1480585069076,"1022423022765":1478686417210,"1024587317163":1509788624239,"1024587317162":1509788624238,"1024587317160":1509788624239,"1021962862630":1478686417148,"1025407028891":1509788625244,"1021949100407":1509788624354,"1025407028893":1509788625165,"1022416207187":1478686804069,"1025407028887":1509788625246,"1021324294712":1478686416984,"1022415683037":1478686417070,"1024597409722":1509788624939,"1017504061060":1478686804053,"1025798563605":1509788624200,"1024291327435":1509788624517,"1008057288109":1478686804030,"1025798563607":1509788624197,"1025798563606":1509788624203,"1021794047726":1509788624394,"1024291327426":1509788624516,"1024291327431":1509788624517,"1000526037670":1444487341703,"1022836806789":1509788624535,"1016952124996":1444487341759,"1022836806790":1509788624535,"1022159473746":1478686417186,"811532689":1478686804029,"1024291327418":1509788624516,"1022055400964":1478686417173,"1022480294308":1478943089254,"1022836806877":1509788624535,"1022836806876":1509788624535,"1024195119055":1509788624184,"1023821828493":1491634246536,"1024195119052":1509788624184,"1024195119062":1509788624184,"1021917912594":1509788624916,"1024195119059":1509788624185,"1024195119057":1509788624184,"1024195119068":1509788624183,"1022265602772":1509788625083,"1024265111579":1509788624450,"1024265111576":1509788624450,"1024459125864":1509788624998,"1024265111582":1509788624450,"1024265111581":1509788624450,"1024265111580":1509788624450,"1021949100552":1509788624354,"1022077291125":1478686417061,"1022078339685":1478686417177,"1025557263667":1509788624343,"1025636957808":1509788624339,"1001519652348":1478686417022,"1024304697230":1509788624923,"1024304697229":1509788624923,"1018967297524":1509788624453,"1332051237":1478686804024,"1024195118181":1509788624185,"1024195118180":1509788624184,"1024195118178":1509788624184,"1016952124853":1444487341759,"1024587316367":1509788625192,"1024587316366":1509788625191,"1024587316375":1509788625192,"1024587316374":1509788625192,"1022825666453":1509788624375,"1024587316373":1509788625192,"1023364921334":1509788624534,"1024587316370":1509788625192,"1023105369965":1509788624462,"1019931347487":1509788624386,"1024587316368":1509788625192,"1024587316383":1509788625191,"1024587316382":1509788625192,"1024587316381":1509788625192,"1024587316376":1509788625192,"1024587316391":1509788625191,"1024587316390":1509788625191,"1018546558101":1480585069070,"1024587316384":1509788625191,"1024587316399":1509788625192,"1021239620635":1478686417099,"1024587316398":1509788625192,"1022067590526":1478686417175,"1024587316397":1509788625192,"1022067590527":1478686417175,"1021679096407":1509788624400,"1024587316396":1509788625191,"1024587316395":1509788625191,"1024195118166":1509788624184,"1022200368508":1478686417064,"1024195118164":1509788624184,"1024587316404":1509788625191,"1024587316403":1509788625191,"1024587316402":1509788625192,"1024587316401":1509788625191,"1025792010080":1509788624814,"1019247033676":1509788624316,"4994833356":1509788667394,"1019340089332":1509788624390,"1022553564769":1509788624937,"1022067590545":1478686417175,"1021343170217":1478686416982,"1013735961916":1478686804033,"1024587316310":1509788624472,"1021508707542":1478686417244,"1022067590535":1478686417175,"1024587316307":1509788624472,"1024587316306":1509788624472,"1022067590530":1478686417175,"1024587316319":1509788624472,"1023364921147":1509788625100,"5056307193":1517735696201,"1021814364822":1478686417052,"1024587316317":1509788624472,"1024587316315":1509788624472,"1024587316312":1509788624472,"1024587316326":1509788624472,"1024587316323":1509788624472,"1024587316321":1509788624472,"1024587316335":1509788624472,"1024587316334":1509788624472,"1024587316333":1509788624472,"1024241781717":1509788624473,"1024241781716":1509788624473,"1024459388107":1509788625070,"1020917154087":1478686417081,"1024587316330":1509788624472,"4994833179":1509788667394,"1024587316329":1509788624472,"1024241781712":1509788624473,"1017170355791":1478686804035,"1024587316343":1509788624472,"1017170355790":1478686804035,"1024587316342":1509788624472,"1024241781710":1509788624473,"1017170355789":1478686804035,"1024587316341":1509788624472,"1017170355788":1478686804035,"1024241781708":1509788624473,"1017170355787":1478686804035,"1024587316339":1509788624472,"1024241781707":1509788624473,"1017170355786":1478686804035,"1024587316338":1509788624472,"1017170355785":1478686804035,"1017170355784":1478686804035,"1024587316336":1509788624472,"1022123297054":1478686417183,"1017170355783":1478686804035,"1017170355782":1478686804035,"1024587316346":1509788624472,"1021800864323":1509788625078,"1024587316344":1509788624472,"1023660352711":1509788624198,"1018707910033":1465470268320,"1024241781690":1509788624473,"1021756299073":1509788624919,"1024587316239":1509788624471,"1025607727324":1509788625084,"1000970206299":1478686804039,"1024587316236":1509788624472,"1024587316233":1509788624471,"1025607727322":1509788625084,"1021307648144":1478686417238,"1019340089178":1509788624391,"1019340089179":1509788624391,"1025792010187":1509788624814,"1019340089177":1509788624391,"1025791485909":1509788624428,"1024587316243":1509788624471,"1024587316242":1509788624471,"1019340089180":1509788624391,"1025791485911":1509788624425,"1019340089181":1509788624391,"1025791485910":1509788624431,"1024587316240":1509788624471,"1024587316255":1509788624471,"1025791485912":1509788624406,"1024587316252":1509788624471,"1021236212826":1478686417003,"1024587316249":1509788624471,"1025627520537":1509788625022,"1024587316260":1509788624471,"1024587316258":1509788624471,"1024587316257":1509788624471,"1008546078730":1478686804054,"1024587316271":1509788624471,"1024587316268":1509788624471,"1024587316265":1509788624471,"1018707910052":1465470268320,"1024587316277":1509788624471,"1024587316275":1509788624471,"1024869379299":1509788624949,"1023062245721":1509788625048,"1024587316272":1509788624471,"1024587316285":1509788624471,"1012415040179":1478686417074,"1024587316284":1509788624471,"1024587316282":1509788624471,"1024587316281":1509788624471,"1024587316280":1509788624471,"1021360864821":1478686417042,"1025407028458":1509788624208,"1024272713860":1509788624949,"1025407028451":1509788624208,"1022443208124":1478686417295,"1023605825621":1509788624229,"1025407028472":1509788624208,"1023444089290":1509788624970,"1025407028425":1509788624228,"1025407028431":1509788624208,"1022599701625":1480585069131,"1012133368853":1478686417073,"1021964435993":1478686417148,"1025407028418":1509788624270,"1025407028417":1509788624270,"1021325604990":1478686417103,"1025407028423":1509788624228,"1024983930381":1509788624924,"1025407028420":1509788624228,"1025407028445":1509788624208,"1022599701603":1480585069131,"1020957394461":1478686417085,"1014007145560":1478686804022,"1013189039379":1478686804062,"1025407028436":1509788624208,"1024490453965":1509788624990,"1021353524935":1478686417006,"1013735961844":1478686804033,"1024444315140":1509788624426,"1006773033983":1491634246510,"1023324418397":1509788624925,"1023736768712":1509788625019,"1023253351704":1509788625042,"1022394710211":1478686417070,"1018182968279":1465470268237,"1024490453976":1509788624990,"1025643118241":1509788624365,"1025643118240":1509788624365,"1024241781283":1509788624882,"1024241781280":1509788624882,"1024241781278":1509788624882,"1021668742077":1478686417248,"1020614775528":1478686416995,"1025643118237":1509788624365,"1024241781275":1509788624882,"1025643118236":1509788624365,"1025643118239":1509788624365,"1025875896703":1509788667404,"1025643118238":1509788624365,"1024241781272":1509788624882,"1023617624027":1509788624325,"1024241781271":1509788624882,"1024490453985":1509788624990,"1022482391856":1478943089488,"1024241781266":1509788624882,"1024265111915":1509788624860,"1022443208128":1478686417295,"873269118":1478686804024,"1024265111919":1509788624861,"1024265111918":1509788624861,"1016897466453":1478686804053,"1024265111917":1509788624861,"1024265111916":1509788624861,"359081706":1478686417023,"1021881081765":1478686417137,"1020782155809":1478686416997,"1021464668030":1478686417108,"1021129388923":1478686417233,"1021881081770":1478686417137,"1025593702741":1509788624566,"1020977710153":1478686417087,"1000456314007":1478686804064,"1023427705423":1509788624516,"1016847922055":1478686804018,"1021926956238":1478686417141,"1025791485627":1509788624827,"1022302828202":1478686417199,"1025791485629":1509788624822,"1025791485628":1509788624832,"1025791485630":1509788624616,"1025169654769":1509788624333,"1025169654768":1509788624333,"1025643118136":1509788624365,"1021325605008":1478686417103,"1025169654771":1509788624333,"1025169654770":1509788624333,"1025169654773":1509788624333,"1025169654772":1509788624333,"1020203088892":1465470268277,"1025169654775":1509788624333,"1025169654774":1509788624333,"1025169654777":1509788624333,"1025169654776":1509788624333,"1025169654779":1509788624333,"1025643118131":1509788624365,"1025169654778":1509788624333,"1025169654781":1509788624333,"1025643118133":1509788624365,"1025169654780":1509788624333,"1025643118132":1509788624365,"1024869379546":1509788624949,"1025169654783":1509788624333,"1025643118135":1509788624365,"1025169654782":1509788624333,"1025643118134":1509788624365,"1022081616880":1478686417012,"1025169654761":1509788624333,"1025626079012":1509788624364,"1025169654763":1509788624333,"1025169654762":1509788624333,"1025169654765":1509788624333,"1025626079009":1509788624364,"1025169654764":1509788624333,"1025626079008":1509788624364,"1025169654767":1509788624333,"1025626079011":1509788624364,"1025169654766":1509788624333,"1025626079010":1509788624364,"1025626079005":1509788624364,"1025626079004":1509788624364,"1025626079007":1509788624364,"1025626079006":1509788624364,"1025626079001":1509788624364,"1020102554065":1509788624361,"1025626079002":1509788624364,"4818414810":1509788624158,"1024670015505":1509788625069,"1022430494366":1478686417294,"1008546079007":1478686804054,"1019001795106":1480585069070,"1021988290593":1478686417154,"1022534033629":1480585069076,"1019001795111":1480585069070,"1019001795115":1480585069070,"4994832970":1509788667394,"1024985503477":1509788624169,"1024362918949":1509788667509,"1022029316447":1478686417267,"1021639518878":1478686417119,"1024362918945":1509788667509,"1022491305436":1478943089315,"1022646103697":1509788625061,"1022192503691":1478686417188,"1022491305432":1478943089315,"1023612248310":1509788624949,"1024362918964":1509788667508,"1023612248317":1509788624949,"1023612248319":1509788624949,"1024362918973":1509788667508,"1022836805920":1509788624421,"1023612248312":1509788624949,"1022836805923":1509788624421,"1024587315942":1509788624478,"1023612248260":1509788624949,"1024587315941":1509788624477,"1023612248263":1509788624949,"1023612248262":1509788624949,"1021964436762":1478686417148,"1023612248257":1509788624949,"1024587315950":1509788624477,"1019963330123":1478686804026,"1023612248270":1509788624949,"1024587315947":1509788624477,"1024587315946":1509788624478,"1023612248264":1509788624949,"1025169654785":1509788624333,"1024587315959":1509788624477,"1025169654784":1509788624333,"1024587315958":1509788624477,"1025169654787":1509788624333,"1021437535925":1478686417241,"1025169654786":1509788624333,"1025169654789":1509788624333,"1024587315955":1509788624477,"1023612248273":1509788624949,"1022491305440":1478943089315,"1025169654788":1509788624333,"1023612248275":1509788624949,"1024587315967":1509788624477,"1023612248285":1509788624949,"1024362918942":1509788667509,"1024587315962":1509788624477,"1024587315961":1509788624477,"1023612248283":1509788624949,"1022204523762":1478686417190,"1024195117670":1509788624183,"1022231917934":1478686417193,"1024195117678":1509788624183,"1022544388290":1509788625075,"1024195117673":1509788624183,"1009561582132":1491634246511,"1023612248246":1509788624949,"1022231917951":1478686417193,"1023612248243":1509788624949,"1020917942213":1478686417032,"573904488":1478950494911,"1023612248251":1509788624949,"573904490":1478950494911,"1024195117639":1509788624184,"1022836805980":1509788624421,"573904471":1478950494911,"865535988":1478950494917,"1024362918978":1509788667508,"1024195117633":1509788624184,"1022836805978":1509788624421,"1020802471957":1478686417030,"1025407028098":1509788624838,"1024195117643":1509788624184,"1025407028103":1509788624838,"1024195117642":1509788624184,"1018242344827":1509788624363,"1025407028100":1509788624838,"1024195117649":1509788624184,"1024136529874":1509788624972,"1021595873102":1478686417115,"1021595873101":1478686417115,"1021595873099":1478686417115,"1025407028075":1509788624917,"1024749446077":1509788625020,"1021700462201":1478686804046,"1025407028078":1509788624865,"1025407028076":1509788624916,"1019811153183":1509788625077,"1025407028091":1509788624838,"1025601699553":1509788625019,"1025407028089":1509788624838,"1025407028095":1509788624838,"1025407028083":1509788624826,"1025407028080":1509788624865,"1021981476511":1478686417263,"133116738":1491634246510,"1022231917957":1478686417193,"1022458805013":1478686417217,"1022836806027":1509788625103,"1022836806026":1509788625103,"1001519651692":1478686417022,"1022084631726":1509788624530,"1022292472143":1478686804029,"1012348453005":1478686417074,"1022238864920":1509788624947,"1022836806116":1509788625103,"1022238864923":1509788624941,"1022238864922":1509788624932,"1024512867724":1509788625028,"1022836806118":1509788625103,"1022238864925":1509788624931,"1022238864924":1509788624931,"1022238864926":1509788624931,"1025068474075":1509788624598,"1020933275738":1478686417000,"1023330318137":1509788625040,"1016851068189":1509788624376,"1000526038557":1444487341706,"1025295748483":1509788624945,"1020444254922":1478686804033,"1021147215077":1478686417096,"1026232403395":1514456869769,"1009652803124":1478686804051,"1009652803126":1478686804051,"1023612248518":1509788624949,"1009652803122":1478686804051,"1023612248515":1509788624949,"1394828804":1478686804033,"1009652803123":1478686804051,"1009652803128":1478686804051,"1021740175798":1478686417253,"1023612248522":1509788624949,"1009652803117":1478686804051,"1009652803119":1478686804051,"1020339922223":1465470268236,"1009652803115":1478686804051,"1826052503":1444487341700,"1826052506":1444487341704,"1023612248488":1509788624949,"1826052504":1444487341701,"1022200891987":1478686417190,"1023612248499":1509788624949,"1024445100054":1509788625070,"1025792008263":1509788624419,"1021568479156":1478686804040,"1444504440":1444487341721,"1021568479157":1478686804040,"1023612248452":1509788624950,"1021568479158":1478686804040,"1021568479159":1478686804040,"1023612248449":1509788624950,"1022639550362":1509788624388,"1021662194247":1509788624534,"1021568479154":1478686804040,"1021568479155":1478686804040,"1023076925866":1509788625047,"1021568479164":1478686804040,"1021568479165":1478686804040,"1021568479166":1478686804040,"1826052540":1444487341700,"1826052539":1444487341704,"1021568479160":1478686804040,"1023612248457":1509788624950,"1826052538":1444487341701,"1021568479161":1478686804040,"1826052537":1444487341699,"1021568479162":1478686804040,"1021568479163":1478686804040,"1023612248471":1509788624950,"1021849100139":1509788624533,"1023612248464":1509788624950,"1022639550345":1509788624388,"1023612248478":1509788624949,"1023612248475":1509788624949,"1826052439":1444487341703,"1826052438":1444487341699,"1021500580673":1478686804034,"1826052437":1444487341700,"1020504813500":1478686804031,"1021500580674":1478686804031,"1020504813501":1478686804031,"1024735028124":1509788667494,"1024735028127":1509788667494,"710614998":1478686804064,"1024529514452":1509788625175,"1022050288530":1478686417172,"1021849100175":1509788624194,"1022836805806":1509788624421,"1025607860096":1509788624539,"1025607860103":1509788624539,"1022449892280":1478686417302,"1022836805802":1509788624421,"1025607860107":1509788624547,"1023612248446":1509788624949,"1001519651448":1478686417022,"1023572141304":1509788624974,"1025784012838":1509788624352,"1025784012842":1509788624350,"1025792008357":1509788624419,"1018085457869":1480585069073,"1024587315975":1509788624477,"1024587315974":1509788624478,"1021841629102":1509788624394,"1024587315973":1509788624478,"1024587315972":1509788624477,"1015058227975":1478686804062,"1025607860183":1509788624826,"1024587315970":1509788624477,"1024587315969":1509788624477,"1024587315968":1509788624477,"1024587315980":1509788624477,"1826052379":1444487341700,"1024587315979":1509788624477,"1023042324272":1509788625048,"1024587315977":1509788624477,"1024587315976":1509788624477,"1024887985451":1509788624439,"1018741720197":1478686804056,"1018741720198":1478686804056,"1018741720199":1478686804056,"1018741720200":1478686804056,"1025607860171":1509788624864,"4998765610":1509788667394,"1018741720201":1478686804056,"1022071655680":1478686417177,"1018741720202":1478686804056,"1018741720203":1478686804056,"1025607860168":1509788624864,"1018741720204":1478686804056,"1018741720205":1478686804056,"1021667955991":1509788624352,"1018741720206":1478686804056,"1023612248325":1509788624949,"1023612248324":1509788624949,"1023612248327":1509788624949,"1023612248326":1509788624949,"1021849100278":1509788624817,"1023612248333":1509788624949,"1021165041452":1478686417003,"1023612248329":1509788624949,"1023612248331":1509788624949,"1020352636124":1509788624467,"1826052390":1444487341701,"1024708288576":1509788624512,"1826052389":1444487341699,"1021500580659":1478686804026,"1020574411745":1478686417026,"1021047967275":1478686417092,"1023612248336":1509788624949,"1024190006115":1509788667888,"1021500580663":1478686804032,"1023612248338":1509788624949,"1826052396":1444487341700,"1023095930960":1509788624996,"1021561662657":1478686804041,"1025607860206":1509788624866,"1025911285760":1509788667462,"1020504813505":1478686804031,"1025142266323":1509788624461,"1023612248805":1509788624956,"1023612248807":1509788624956,"1022449891371":1478686417302,"1023612248809":1509788624956,"1021027520281":1478686417035,"1023612248810":1509788624956,"1023612248821":1509788624956,"1023612248823":1509788624956,"1023612248817":1509788624956,"1023612248816":1509788624956,"1021986981343":1478686417057,"1023612248830":1509788624956,"1008903508386":1478686804068,"1023612248824":1509788624956,"1001519651278":1478686417022,"1024195117112":1509788624184,"1021700986073":1478686804065,"209664587":1444487341736,"1021208293908":1478686804027,"1024265112611":1509788624563,"1024265112610":1509788624563,"1023612248796":1509788624956,"1021302144141":1509788625019,"709565553":1478686804064,"1024265112609":1509788624563,"1023453920335":1509788625072,"1024265112608":1509788624563,"1023612248798":1509788624956,"1024265112613":1509788624563,"1020391826106":1478686804033,"1024954569378":1509788624923,"1020784647470":1478686417076,"1021886978973":1478686804027,"1022241486079":1478686417066,"1013058103381":1444487341758,"1024730570757":1509788624923,"1024730570756":1509788624924,"1021734146734":1478686416973,"1024730570759":1509788624924,"1024730570758":1509788624924,"1022043471928":1478686417011,"1024730570753":1509788624924,"1021679097442":1509788624400,"1024730570755":1509788624924,"1024730570754":1509788624923,"1023612248709":1509788624956,"1022399561039":1509788624454,"1024195117124":1509788624184,"1022836806489":1509788624820,"1024195117122":1509788624184,"1023612248704":1509788624956,"1023612248706":1509788624956,"1024195117134":1509788624184,"1023612248716":1509788624956,"1022836806487":1509788624820,"1024195117131":1509788624185,"1023612248713":1509788624956,"1023612248712":1509788624956,"1023612248714":1509788624956,"1023612248725":1509788624956,"1023612248727":1509788624956,"1023612248726":1509788624956,"1023612248723":1509788624956,"1023612248722":1509788624956,"1020922529065":1478686417081,"1009848625602":1491634246513,"1021673461265":1478686417248,"1009848625607":1491634246513,"1024637642574":1509788667502,"1021426657213":1478686417241,"1023931928928":1491634246517,"1021673461262":1478686417248,"1024926782483":1509788624510,"1447518430":1444487341704,"1447518429":1444487341700,"1447518428":1444487341701,"481896997":1444487341737,"1024926782487":1509788624511,"1023612248698":1509788624956,"1017554656439":1478686804063,"1025032429311":1509788624976,"1017554656438":1478686804063,"1024761900766":1509788624459,"1023612248644":1509788624956,"1017554656437":1478686804063,"1009848625634":1491634246513,"1017554656436":1478686804063,"1017554656435":1478686804063,"1020309256547":1465470268300,"1017554656434":1478686804063,"1017554656433":1478686804063,"1017554656432":1478686804063,"1021746205332":1478686417126,"1017554656447":1478686804064,"1017554656446":1478686804064,"1017554656445":1478686804064,"1017554656444":1478686804064,"1023612248654":1509788624956,"1017554656443":1478686804064,"1017554656442":1478686804064,"1017554656441":1478686804063,"1023612248651":1509788624956,"1017554656440":1478686804063,"1017554656430":1478686804063,"1017554656429":1478686804063,"1017554656428":1478686804063,"1017554656427":1478686804063,"1017554656426":1478686804063,"1021662194076":1509788624195,"1843747620":1444487341720,"1023306725370":1509788624858,"1023612248612":1509788624956,"1021885537073":1478686417044,"1023306725375":1509788624858,"1020895921163":1478686417079,"1023306725374":1509788624858,"1023306725373":1509788624858,"1023306725363":1509788624221,"1023612248621":1509788624956,"1023306725362":1509788624562,"1017408640102":1509788624286,"1024265112790":1509788625164,"1023612248618":1509788624956,"1013058103500":1444487341758,"1023306725355":1509788624221,"1022836806637":1509788624820,"1024265112779":1509788625164,"1023306725354":1509788624221,"1023612248628":1509788624956,"1024265112778":1509788625164,"1020869314226":1478686416999,"1025295748697":1509788624945,"1017554656450":1478686804064,"1023306725357":1509788624221,"1017554656448":1478686804064,"1023306725356":1509788624221,"1024265112780":1509788625164,"1023306725347":1509788624562,"1023306725345":1509788624562,"1022836806630":1509788624820,"1023612248638":1509788624956,"1023612248633":1509788624956,"1024265112775":1509788625164,"1023306725349":1509788624562,"1026222709139":1514456869775,"1023306725348":1509788624562,"1021281304341":1478686417004,"1001388183918":1480585069061,"1020802210441":1478686417225,"1020908242140":1478686417032,"1023612248597":1509788624956,"1023612248596":1509788624956,"1023612248599":1509788624956,"1023612248604":1509788624956,"1021949101822":1509788624357,"1022516077728":1509788624392,"1018901630120":1509788624301,"1023961947918":1509788625004,"1020897756630":1478686417032,"1022291817150":1478686417198,"1023612249058":1509788624957,"1023612249068":1509788624957,"1023612249071":1509788624957,"1023612249070":1509788624957,"1023612249064":1509788624957,"1023612249067":1509788624957,"1022071787457":1478686417060,"1023961947930":1509788625005,"1023961947925":1509788625004,"1023961947927":1509788625005,"1023961947920":1509788625004,"1022836806176":1509788625103,"1023961947923":1509788625004,"1022836806179":1509788625103,"1021406078841":1478686417006,"1017318075177":1465470268237,"1023961947944":1509788625004,"1023961947947":1509788625004,"1023612249037":1509788624957,"1023612249038":1509788624957,"1023961947937":1509788625005,"1023961947936":1509788625005,"1023612249045":1509788624957,"1023612249047":1509788624957,"1023612249043":1509788624957,"1023961947962":1509788625004,"1018268951130":1478686804020,"1023612249053":1509788624957,"1023961947959":1509788625005,"1023961947953":1509788625004,"1023612249050":1509788624957,"1017554656599":1478686804064,"1017554656598":1478686804064,"1826053013":1444487341705,"1017554656597":1478686804064,"1025032429341":1509788624976,"1017554656596":1478686804064,"1017554656595":1478686804064,"1017554656594":1478686804064,"1001519650967":1478686417022,"1017554656607":1478686804064,"1017554656606":1478686804064,"1017554656605":1478686804064,"1017554656604":1478686804064,"1017554656603":1478686804064,"1017554656602":1478686804064,"1017554656601":1478686804064,"1023961947971":1509788625005,"1023961947970":1509788625005,"1006923892461":1478686804054,"1022836806252":1509788624196,"1022339792777":1478686417288,"1022836806251":1509788624196,"578753826":1478686417023,"1025032429314":1509788624976,"1023612248964":1509788624957,"1023612248966":1509788624957,"1023612248961":1509788624957,"1022897889020":1509788624814,"1023612248960":1509788624957,"1023612248973":1509788624957,"1023612248972":1509788624957,"1023612248969":1509788624957,"1023612248968":1509788624957,"1023612248970":1509788624957,"1023612248982":1509788624957,"1023612248977":1509788624957,"1023612248976":1509788624957,"1021561663050":1478686804042,"1023612248979":1509788624957,"1017554656608":1478686804064,"1019949567535":1509788624386,"1025032429350":1509788624976,"1022836806209":1509788624196,"1022836806208":1509788624196,"1025032429345":1509788624976,"1021647382921":1509788624400,"1022836806323":1509788624196,"1022836806319":1509788624196,"1021068937997":1478686417093,"1021468730162":1478686417007,"1020362990892":1478686804057,"1024985502356":1509788624169,"1021381703768":1478686417042,"1024462533107":1509788624989,"1024462533106":1509788624989,"1024462533105":1509788624989,"1023572141806":1509788624974,"1024462533104":1509788624989,"1020850706486":1478686804057,"1022836806295":1509788624196,"1023612248910":1509788624956,"1022836806289":1509788624196,"1022067982525":1509788624937,"1023612248916":1509788624956,"1023612248913":1509788624956,"1023612248912":1509788624956,"1024462533103":1509788624989,"1024462533102":1509788624989,"1024462533101":1509788624989,"1024462533099":1509788624989,"1022067982508":1509788624291,"1016012585021":1480585069078,"1023612248869":1509788624956,"1025284604055":1509788624971,"1025284604054":1509788624945,"1023612248868":1509788624956,"1025284604053":1509788624940,"1023612248871":1509788624956,"1021561663224":1478686804045,"1025284604050":1509788624946,"1025284604063":1509788624932,"1023612248876":1509788624956,"1021795225754":1509788624403,"1025284604059":1509788624946,"1025284604058":1509788624945,"1023612248874":1509788624956,"1023612248884":1509788624956,"1020782681181":1478686417076,"1023612248881":1509788624956,"1022231787256":1478686417282,"1023572141713":1509788624974,"1022385405400":1478686417205,"1023612248888":1509788624956,"1023612248891":1509788624956,"1025284604086":1509788624946,"1020797229902":1478686417077,"1025284604082":1509788624945,"1023612248832":1509788624956,"1025284604081":1509788624945,"1020797229895":1478686417077,"1025284604070":1509788624946,"1025284604069":1509788624945,"1012454231521":1478686417074,"1023737687199":1491634246512,"1025284604066":1509788624940,"1025284604064":1509788624946,"1025284604079":1509788624971,"1025284604078":1509788624930,"1025284604077":1509788624946,"1025284604076":1509788624940,"1025284604075":1509788624945,"1025284604072":1509788624946,"1023066311535":1509788625181,"1018468833693":1478686804031,"1018178250947":1509788624453,"1021949102088":1509788624357,"1021906114233":1509788624465,"1023066311551":1509788625182,"2015051791":1478686804029,"1023066311547":1509788625182,"1023066311544":1509788625182,"1023066311540":1509788625183,"1025593701076":1509788624455,"1023066311536":1509788625183,"725816161":1444487341728,"1025322352944":1509788624305,"1021802172641":1509788625082,"1022426822050":1478686417211,"725816178":1444487341718,"1024146361150":1509788625102,"1021291131236":1478686417102,"1023939665752":1509788624970,"1008047328409":1478686804022,"1020935507152":1465470268182,"1023995630157":1491634246532,"1021385242601":1478686417105,"1020935507139":1465470268182,"1015583559111":1465470268313,"1021571621585":1478686417114,"1020935507146":1465470268182,"1022451594856":1478686417296,"1021623264752":1478686417049,"1024313214301":1509788624926,"1002430356747":1478686804059,"1025322353011":1509788624309,"1024557692140":1509788624453,"1022028139806":1478686416976,"1020962246280":1478686417001,"1025792011628":1509788624193,"1019022899944":1480585069072,"1021235691008":1465469681394,"1025817308935":1509788667793,"1019995177993":1509788624287,"1020917943046":1478686417032,"1012124852004":1478686417223,"1016952127332":1444487341760,"1025458043459":1509788624361,"1022758689126":1509788624426,"1023066311621":1509788625181,"1023066311619":1509788625181,"1024134957937":1509788667499,"1023066311617":1509788625182,"1023066311616":1509788625181,"1022238603893":1509788624946,"1024134957933":1509788667498,"1022238603895":1509788624941,"1024134957935":1509788667499,"1022238603894":1509788624932,"1024134957934":1509788667499,"1024134957930":1509788667499,"1024134957927":1509788667499,"1022238603897":1509788624941,"1022238603896":1509788624933,"1024134957920":1509788667499,"1021440551604":1478686417107,"1023066311598":1509788625183,"1024255935044":1509788667496,"1023066311595":1509788625182,"1020068083936":1509788625076,"1020068083937":1509788625078,"1024255935040":1509788667829,"1024313214453":1509788624927,"349645855":1517734758204,"1024313214452":1509788624927,"1016944918144":1478686804015,"1023066311614":1509788625182,"1024529773184":1509788624467,"1023066311609":1509788625183,"1023066311567":1509788625181,"1023066311566":1509788625181,"4994830676":1509788667394,"1024687057949":1509788624818,"1021037478551":1465470268183,"1023066311557":1509788625181,"1022473480238":1478943089486,"1023066311554":1509788625182,"1024624404572":1509788667890,"1023066311553":1509788625182,"1023066311582":1509788625181,"1021992881050":1478686417011,"1021992881052":1478686417011,"1022473480241":1478943089486,"1021992881053":1478686417011,"1021992881054":1478686417011,"1025458043415":1509788624361,"1023066311577":1509788625181,"1025458043417":1509788624361,"1025792011744":1509788624193,"1025458043416":1509788624361,"1025458043418":1509788624361,"1025322353130":1509788624307,"1023066311570":1509788625181,"1023066311569":1509788625181,"1021888812220":1478686804044,"1021888812221":1478686804044,"1021888812222":1478686804044,"1021469126051":1478686417007,"1021888812223":1478686804044,"1024785883154":1509788624481,"1021888812217":1478686804044,"1021888812218":1478686804044,"1021888812219":1478686804044,"1025322352665":1509788624306,"1025245285534":1509788624937,"1025245285532":1509788624937,"1021888812200":1478686804044,"1025245285531":1509788624937,"1021888812201":1478686804044,"1025245285530":1509788624937,"1025245285528":1509788624937,"1021888812196":1478686804044,"1021888812197":1478686804044,"1021888812198":1478686804044,"1021888812199":1478686804044,"599988952":1478950494912,"1021888812192":1478686804044,"1024412465743":1509788625070,"1021888812193":1478686804044,"1021888812194":1478686804044,"1021888812195":1478686804044,"1021888812188":1478686804044,"1025245285551":1509788624937,"1021888812189":1478686804044,"1025245285550":1509788624937,"1021888812190":1478686804044,"1021888812191":1478686804044,"1021888812184":1478686804044,"1025245285547":1509788624937,"1021888812185":1478686804044,"1021888812186":1478686804044,"1021888812187":1478686804044,"1009744421046":1491634246512,"1022291819664":1478686417198,"1022291819667":1478686417198,"1021888812182":1478686804044,"1021888812183":1478686804044,"1025245285540":1509788624937,"725815918":1444487341726,"1025245285562":1509788624937,"1024936352556":1509788624997,"1009561581394":1491634246511,"1025245285561":1509788624937,"1023306725379":1509788624858,"1024517714901":1509788625028,"1025245285558":1509788624937,"1025245285556":1509788624937,"1025245285553":1509788624937,"1021888812280":1478686804044,"1021888812276":1478686804044,"1025896080781":1509788667450,"1021888812277":1478686804044,"1024743943896":1509788624958,"1022193551068":1478686417189,"1021888812278":1478686804044,"1021888812279":1478686804044,"1021888812272":1478686804044,"1021888812273":1478686804044,"1021888812274":1478686804044,"1021888812275":1478686804044,"1024136530666":1509788624972,"1021888812268":1478686804044,"1021888812269":1478686804044,"1021888812270":1478686804044,"1021888812271":1478686804044,"1013058103112":1444487341758,"1021888812264":1478686804044,"1021888812265":1478686804044,"1025322352706":1509788624307,"1021888812266":1478686804044,"1021888812260":1478686804044,"1021888812261":1478686804044,"1016952127143":1444487341760,"1021888812262":1478686804044,"1021888812263":1478686804044,"1019320167814":1509788624315,"1012160368890":1478686416994,"1021531251072":1509788624397,"1025284607547":1509788624945,"1020823704661":1478686417226,"1017885738806":1478686804015,"1025284607545":1509788624945,"1021888812236":1478686804044,"1025284607526":1509788624945,"1024639609050":1509788667503,"1021888812232":1478686804044,"1021888812233":1478686804044,"1021888812234":1478686804044,"1021888812235":1478686804044,"1021888812228":1478686804044,"1025284607535":1509788624945,"1021888812229":1478686804044,"1025284607534":1509788624945,"1021888812230":1478686804044,"1021888812231":1478686804044,"1021888812224":1478686804044,"1021888812225":1478686804044,"1021888812226":1478686804044,"1022292737269":1509788624317,"1021888812227":1478686804044,"1022251842459":1478686416991,"1021088859330":1478686417094,"1002430356734":1478686804059,"1026504997122":1515854751199,"1019074673891":1480585069084,"1022096687352":1478686417274,"1021396907705":1509788624433,"725816044":1444487341732,"1022096687351":1478686417274,"1021947267472":1478686417144,"1019074804938":1509788624314,"1025269927814":1509788625008,"1019578505923":1465470268274,"1020975878076":1478686417087,"1024370129007":1509788624927,"1021914371981":1509788624989,"1022051209131":1478686417172,"1022454085206":1478686417216,"1000526171437":1444487341739,"1020832094070":1478686417031,"1021888812140":1478686804044,"1019477976227":1478686804021,"1021888812141":1478686804044,"1020919122619":1478686804034,"1021888812136":1478686804044,"1022274125170":1478686417197,"1021888812137":1478686804044,"1021888812138":1478686804044,"1022364954763":1509788624958,"1021888812139":1478686804044,"1022364954762":1509788624957,"1013058103236":1444487341758,"1021888812132":1478686804044,"1021888812133":1478686804044,"725815961":1444487341716,"1021888812134":1478686804044,"1021888812131":1478686804044,"1025792011517":1509788624193,"1012124851802":1478686417223,"4994830416":1509788667394,"1020858832617":1478686417079,"1021789462116":1478686416991,"1022327471724":1478686417200,"1021396907751":1509788624433,"1024360823216":1509788667843,"1022199711438":1478686417190,"1024797156287":1509788625024,"1023066311022":1509788624474,"1025017486625":1509788624433,"1021621692303":1478686417117,"1023066311015":1509788624475,"1023066311014":1509788624475,"1023066311013":1509788624475,"1016952126961":1444487341760,"1023066311009":1509788624475,"1022074012345":1509788624439,"1023066311039":1509788624475,"1023066311038":1509788624475,"1023066311033":1509788624475,"1017436952833":1478686804031,"1023066311028":1509788624474,"1023066311024":1509788624474,"1023066311005":1509788624475,"1023066311004":1509788624475,"1023066311003":1509788624475,"1023066311000":1509788624475,"1024637643773":1509788667503,"1023066310995":1509788624475,"1023066310993":1509788624474,"1017250701936":1465470268235,"1024313214837":1509788624926,"1026504997588":1515854751198,"1024313214828":1509788624927,"167719849":1444487341746,"1021949102675":1509788624357,"1012160369605":1478686416994,"1012126031332":1478686417073,"1010091889841":1491634246527,"1021049536990":1478686417036,"1022601014610":1509788624430,"1022088168352":1478686417180,"1010024517709":1491634246526,"1010024517705":1491634246526,"1600349668":1478686804024,"1010024517707":1491634246526,"1021938747956":1478686417144,"123289035":1507213829619,"1022234147741":1478686417065,"1021793918418":1478686804071,"1010024517717":1491634246521,"1021777665216":1478686417128,"1020596558395":1478686804022,"1010024517713":1491634246526,"1023250859213":1509788625042,"1025284607472":1509788624945,"1024567523005":1509788624283,"1025607200948":1509788624837,"1024567523007":1509788624283,"1021235559484":1478686417236,"1021835202626":1509788624394,"1025017486737":1509788624432,"1025607200937":1509788624837,"1025607200938":1509788624837,"1025607200934":1509788624836,"1025907091198":1509788667461,"1025372686035":1509788624524,"1025372686033":1509788624537,"1025372686032":1509788624543,"1014836720349":1478686804028,"1019991508509":1509788624335,"1025593831426":1509788625000,"1025593831430":1509788625000,"1024529510537":1509788624476,"1025372686031":1509788624541,"1024567523016":1509788624283,"1024567523018":1509788624283,"1023066311053":1509788624474,"1023066311051":1509788624475,"1023066311050":1509788624475,"1016952126740":1444487341760,"1018797035277":1465470268180,"1023066311043":1509788624475,"1021841756291":1509788624394,"1021335041616":1478686417041,"1011876995726":1478686804034,"1021407652535":1478686417043,"1023066311062":1509788624474,"1025270713584":1509788625243,"1018624676051":1478686804023,"1023066311058":1509788624474,"1023066311056":1509788624475,"1022091707029":1478686417062,"1025458043331":1509788624361,"1025458043333":1509788624361,"1025458043332":1509788624361,"1025458043334":1509788624361,"1013855499704":1478686804046,"1021793918072":1478686804071,"1019174547547":1509788624320,"1021016769279":1478686417231,"1021832843846":1478686417134,"1021700463022":1478686804046,"1020860402622":1478686417031,"1021793917977":1478686804071,"1021832843849":1478686417134,"1021576339768":1509788624401,"1023666515150":1509788624419,"1021016769227":1478686417231,"1020942061437":1478686417000,"1000928653408":1444487341755,"1025906698069":1509788667464,"1021016769229":1478686417231,"1025906698068":1509788667462,"1025792011873":1509788624193,"1000527875981":1444487341713,"1021016769221":1478686417231,"1021955787299":1478686417146,"1024313214655":1509788624927,"1022459982902":1478686417298,"1003242106498":1478686804054,"1023869147196":1509788625082,"1003242106500":1478686804054,"1025458043249":1509788624360,"1023141806974":1509788624454,"1024265634178":1509788625032,"1025458043251":1509788624360,"1025458043250":1509788624360,"1000527875943":1444487341739,"1025458043252":1509788624361,"4994830881":1509788667394,"1016952126564":1444487341760,"1021793918181":1478686804071,"1021793918182":1478686804071,"530261049":1478950494910,"1025792011944":1509788624193,"1018922207019":1509788624309,"1025712974446":1509788624304,"1021920662559":1478686417259,"519906614":1444487341753,"1021885666817":1478686417137,"1021932066008":1478686417259,"1019362766332":1509788624315,"315435294":1444487341706,"1009595263913":1478686804030,"1020935114560":1478686417083,"352137003":1444487341732,"1022334549210":1478686417015,"1022334549203":1478686417015,"1022201808114":1478686417190,"1022201808115":1478686417190,"1021848965618":1509788624493,"1022083056632":1478686417272,"1025458043161":1509788624360,"1010057418511":1491634246535,"1025458043160":1509788624360,"1025458043162":1509788624360,"1021854470227":1509788624402,"1024313214656":1509788624927,"1022083056630":1478686417272,"1021646201399":1509788624974,"1022123165606":1478686417183,"1023949100276":1509788667493,"1023949100278":1509788667493,"1022233361725":1509788624177,"1022149378104":1478686417185,"1023949100285":1509788667493,"1022149378106":1478686417185,"1023949100287":1509788667493,"1021308434011":1478686417041,"1008243965175":1478686804032,"1025879959491":1509788667405,"1016335933090":1478686804017,"1020258136302":1464448510787,"1016952126430":1444487341760,"1023567424919":1509788624392,"1023567424918":1509788624392,"1025270712876":1509788625243,"1023567424920":1509788624392,"4818412400":1509788624159,"4818412401":1509788624159,"1022190404591":1478686417279,"1024983931240":1509788624924,"1023066312481":1509788624881,"1023066312480":1509788624880,"1020622773625":1509788625080,"1025269926499":1509788625008,"1024793880259":1509788625021,"1000216321332":1444487341710,"4818412399":1509788624159,"1013720496895":1478686804068,"1023066312463":1509788624881,"1010091889314":1491634246522,"1013720496892":1478686804068,"1023066312459":1509788624881,"1023066312456":1509788624881,"1021308433981":1478686417041,"1023066312453":1509788624881,"1010091889325":1491634246522,"1023066312450":1509788624881,"1023066312479":1509788624881,"1023066312478":1509788624880,"1022677557450":1509788625146,"1023066312477":1509788624881,"1022677557449":1509788625146,"1023066312476":1509788624881,"1022677557448":1509788625146,"1019159344697":1509788624312,"1023066312474":1509788624881,"1022389598131":1478686417290,"1023066312472":1509788624881,"1022677557452":1509788625145,"1023066312471":1509788624881,"1023066312470":1509788624881,"1023066312469":1509788624881,"1023066312467":1509788624881,"1022677557446":1509788625145,"1020892646809":1478686417079,"1020622773683":1509788625080,"1023099078941":1509788624178,"1023066312675":1509788624573,"1023066312674":1509788624573,"1025817307929":1509788667793,"1020856079294":1478686417079,"1025593701977":1509788624454,"1020856079287":1478686417079,"1022928164661":1509788624300,"1021909258948":1478686417140,"1023066312655":1509788624574,"1025270713003":1509788625243,"1023066312654":1509788624574,"1024983931265":1509788624924,"1006011483835":1478686804046,"1021552616719":1478686417113,"1021909258945":1478686417140,"1023066312649":1509788624574,"1021909258947":1478686417140,"1023066312645":1509788624574,"1011876996305":1478686804034,"1023066312644":1509788624574,"1024292896984":1509788667830,"1016952126289":1444487341759,"1023066312643":1509788624574,"1023066312642":1509788624573,"1023066312670":1509788624574,"1023066312669":1509788624573,"1023066312668":1509788624574,"1023066312667":1509788624574,"1023066312666":1509788624574,"1023066312665":1509788624574,"1023066312664":1509788624574,"1023066312663":1509788624574,"1021552616723":1478686417113,"1023066312662":1509788624574,"1023066312661":1509788624573,"1021552616721":1478686417113,"1023066312660":1509788624573,"1023066312659":1509788624573,"1024292896975":1509788667509,"1023066312658":1509788624573,"1021552616724":1478686417113,"1023066312657":1509788624574,"1025593832969":1509788625000,"1025593832968":1509788625000,"1025593832970":1509788625000,"1025593832975":1509788624438,"1021988294427":1478686417154,"1021242112738":1478686417003,"1021344477433":1478686804067,"1025593832967":1509788625000,"1021909258932":1478686417140,"1016662559219":1478686804018,"1024782476789":1509788625020,"1023926426354":1491634246530,"1023926426353":1491634246530,"1025593832978":1509788625000,"1025593832981":1509788624438,"1021888811363":1478686804050,"1011826796952":1509788624945,"1021456674688":1478686417242,"1011826796956":1509788624944,"1011826796957":1509788624944,"1016600301084":1509788624274,"1025910890762":1509788667579,"1020622773725":1509788625080,"1025910890766":1509788667579,"1025910890764":1509788667579,"1025910890770":1509788667579,"1025910890768":1509788667579,"1020856079316":1478686417079,"1025910890776":1509788667579,"1023329926950":1509788624491,"1022149640500":1478686417185,"1019714557520":1478686804053,"1017518347576":1478686804031,"1019714557521":1478686804053,"1020855554641":1478686417226,"1017518347575":1478686804031,"1024186993583":1509788624470,"1024186993585":1509788624470,"1024186993590":1509788624470,"1024186993589":1509788624470,"1024186993593":1509788624470,"1019714557519":1478686804053,"1024186993592":1509788624470,"1024186993596":1509788624470,"1025792010301":1509788624814,"1025322353712":1509788624294,"1025322353711":1509788624294,"1025322353710":1509788624294,"1025322353706":1509788624294,"1021427969143":1478686804026,"1016952126137":1444487341759,"1025715072199":1509788624822,"1025508505782":1509788624339,"1025715072198":1509788624832,"1025508505780":1509788624342,"1025508505779":1509788624346,"1025508505778":1509788624340,"1025572861277":1509788624309,"1023929965389":1509788624287,"1023929965388":1509788624287,"1023929965391":1509788624287,"1023929965390":1509788624287,"1000977281873":1444487341753,"1021629423723":1509788624401,"1538877145":1444487341702,"1017518347614":1478686804018,"1017518347610":1478686804016,"1022165368905":1478686417186,"1017518347601":1478686804034,"1017518347600":1478686804020,"1023364921554":1509788624420,"1017518347598":1478686804016,"1023196464857":1509788624511,"1024687057293":1509788625102,"1017518347585":1478686804031,"1022608614825":1509788624994,"1013720496927":1478686804068,"1013720496925":1478686804068,"1025032426972":1509788624976,"4994831413":1509788667394,"1021948317110":1478686417145,"1023066312425":1509788624881,"1409117819":1509788625020,"1021948317111":1478686417145,"1021721304624":1478686804047,"1023066312421":1509788624881,"1022233361598":1509788624178,"1023066312420":1509788624882,"1023066312419":1509788624880,"1025792010388":1509788624814,"1013720496912":1478686804068,"1024461355993":1509788625029,"1025901978106":1509788667457,"1025901978104":1509788667460,"1023066312443":1509788624881,"1000526170492":1444487341712,"1023946349198":1491634246531,"1023946349196":1491634246531,"1000526170480":1444487341714,"1021888811045":1478686804065,"1025156287847":1509788624512,"1025528691504":1509788624345,"1010091889503":1491634246527,"1023066312432":1509788624881,"1023364921346":1509788624195,"1025032427006":1509788624976,"1025270713258":1509788625243,"1025032427001":1509788624976,"1025500379612":1509788625020,"1025032426999":1509788624976,"1025032426996":1509788624976,"1025032426993":1509788624976,"1021688273920":1478686417050,"1013720496942":1478686804068,"1025032426990":1509788624976,"1013720496940":1478686804068,"1025032426988":1509788624976,"1013720496939":1478686804068,"1009848492788":1491634246513,"1013720496936":1478686804068,"1024597406611":1509788624939,"1023995500466":1491634246532,"1012596997714":1458304307281,"1021729300198":1509788624993,"1021700464434":1478686804046,"1024983931119":1509788624924,"1021102228301":1478686417002,"1021616840740":1478686417117,"1021616840738":1478686417117,"1024688105745":1509788624503,"1024164972998":1509788624972,"1023364921461":1509788624819,"1023910566114":1509788624175,"1022455394843":1478686417016,"1012268765924":1478686416994,"1024725068638":1509788624290,"1020739032534":1478686417028,"1023949100291":1509788667493,"1025792010474":1509788624814,"1016952125963":1444487341759,"1021369906034":1480585069064,"1023195940308":1509788625043,"1025864885408":1509788667831,"1025864885410":1509788667829,"1025864885415":1509788667465,"4984215321":1509788624158,"1021602030276":1478686416984,"1025864885424":1509788667463,"1021678968369":1509788624396,"1009595919974":1465470268262,"1024334709219":1509788624423,"1020881375157":1478686417031,"1022228643676":1478686417282,"1023354698366":1509788625040,"1024264979516":1509788625102,"135345717":1444487341728,"1024264979515":1509788624195,"1019991638774":1509788624959,"1023877930277":1491634246506,"1025864885389":1509788667836,"1022108877999":1478686417182,"1024687057627":1509788624534,"1025864885390":1509788667836,"1025864885394":1509788667465,"1025864885396":1509788667459,"1003593503755":1480585069064,"1025864885404":1509788667836,"1025864885407":1509788667465,"1024264979544":1509788624534,"1017238251198":1465470268268,"1008593267315":1478686804040,"1025032427025":1509788624976,"1014724918514":1478686804022,"1025032427023":1509788624976,"1025032427022":1509788624976,"1025032427015":1509788624976,"1843745724":1444487341751,"1012415038994":1478686417074,"1025032427013":1509788624976,"1843745720":1444487341747,"1025864885441":1509788667463,"1021700463771":1478686804046,"1008593267295":1478686804040,"1025864885445":1509788667463,"1008593267288":1478686804040,"1016335932636":1478686804016,"1021938749134":1478686417143,"1022331402550":1478686417201,"1025864885453":1509788667830,"1008593267282":1478686804071,"1016070646815":1465470268246,"1021938749138":1478686417143,"1022134961511":1478686417184,"1020567199773":1478686417074,"1023066312175":1509788624241,"1023066312174":1509788624242,"1017064584107":1478686804022,"1023066312173":1509788624242,"1023066312172":1509788624242,"1021397560928":1509788624399,"1023066312170":1509788624242,"1023066312167":1509788624242,"1023066312166":1509788624242,"1023066312165":1509788624242,"1020741654156":1478686417028,"1025772612277":1509788625084,"1025772612276":1509788625003,"1021142892192":1478686417096,"1008593267364":1478686804049,"1020626050169":1478686804057,"1023268291071":1509788624839,"1023066312178":1509788624242,"1023066312143":1509788624242,"1022827633416":1509788624990,"1021719731571":1478686417123,"1020851228976":1478686417031,"1023066312135":1509788624242,"1024055660607":1509788624329,"1021719731577":1478686417123,"1021719731579":1478686417123,"1023066312132":1509788624242,"1016952125777":1444487341759,"1021719731580":1478686417123,"1023066312130":1509788624242,"1023066312128":1509788624241,"1025041078132":1509788625022,"1008593267342":1478686804040,"1023066312156":1509788624242,"1021852374397":1478686417135,"1023066312153":1509788624242,"1023066312151":1509788624242,"1023066312150":1509788624242,"1023066312149":1509788624242,"1023066312148":1509788624242,"1023066312147":1509788624242,"1023066312146":1509788624242,"1023066312145":1509788624242,"1025772612254":1509788624999,"1019931346570":1509788624385,"1019957036035":1509788625076,"1008593267433":1478686804048,"1022553565898":1509788624932,"1020626050102":1478686804057,"1001660811686":1478686804029,"1019812990869":1480585069061,"4994832206":1509788667394,"1023926556883":1491634246530,"1023926556884":1491634246530,"965281654":1444487341700,"4994832054":1509788667394,"1025864885665":1509788667829,"1012846292409":1478686417026,"1022193287327":1478686417064,"1025593832896":1509788624866,"1011943318372":1509788624821,"1024490452870":1509788624990,"1025864885677":1509788667829,"1024490452867":1509788624990,"1024490452866":1509788624990,"1025864885683":1509788667460,"1021885534950":1478686417044,"1022270323652":1480585069092,"1022154490604":1478686417063,"1008593267473":1478686804048,"1023996417331":1509788624503,"1021885928165":1478686417258,"1022756331224":1509788625057,"1025864885651":1509788667462,"1025864885650":1509788667832,"1020938783593":1509788624353,"1024264979752":1509788624819,"701568666":1478950494914,"1025817307356":1509788667793,"1002457225406":1491634246520,"1015159677848":1478686804029,"1020443338900":1478686417224,"1020443338901":1478686417224,"4972549939":1509788624158,"1020443338902":1478686417224,"1020443338903":1478686417224,"1024116477344":1509788625036,"1020443338908":1478686417224,"1020443338909":1478686417224,"1020443338910":1478686417224,"1020443338911":1478686417224,"1020443338904":1478686417224,"1020443338905":1478686417224,"1020443338906":1478686417224,"1020443338907":1478686417224,"1020443338912":1478686417224,"1020443338913":1478686417224,"1009561579778":1491634246511,"1025864885704":1509788667836,"1025864885708":1509788667457,"1012882205695":1478686417074,"1021739653889":1478686417124,"1024227493850":1509788625032,"1025864885541":1509788667833,"1025864885542":1509788667462,"1022907454827":1509788624298,"1025864885553":1509788667830,"1025864885554":1509788667830,"1025864885557":1509788667457,"1025864885556":1509788667830,"1025864885560":1509788667457,"1021649739879":1478686417248,"1024495564797":1509788624935,"1024687057750":1509788624420,"1024495564796":1509788624935,"1024687057758":1509788624195,"1025295746851":1509788624945,"1838633504":1444487341739,"1009893055747":1491634246533,"1016952125504":1444487341759,"1025864885606":1509788667462,"1021739129664":1478686417051,"1025864885612":1509788667836,"1024490452830":1509788624990,"1021511592416":1509788624869,"1835881101":1491634246516,"1835881100":1491634246516,"1835881102":1491634246516,"1018395304478":1465470268236,"1024490452841":1509788624990,"1021989080142":1478686417057,"1835881093":1491634246516,"1024490452837":1509788624990,"1021989080141":1478686417057,"1024490452838":1509788624990,"1025864885578":1509788667457,"1025593701670":1509788624229,"1024490452832":1509788624990,"1025864885582":1509788667829,"1025864885585":1509788667457,"1021734411010":1509788624400,"1024490452858":1509788624990,"1017914408823":1509788625080,"1008593267652":1478686804016,"1024490452855":1509788624990,"1012134942945":1478686417025,"1024490452849":1509788624990,"1835881104":1491634246516,"1835881106":1491634246516,"1020971447885":1478686417086,"1022224974270":1478686417192,"1022464315233":1478686417218,"1022511501970":1509788624990,"1018553656946":1478686804023,"1022000870158":1478686417265,"1024203765692":1509788625034,"1022196301674":1478686417280,"1025665633961":1509788624612,"1025314257337":1509788624329,"1022416473115":1478686417209,"1020241103814":1478686804065,"1025665633969":1509788624611,"1022031410447":1509788624463,"1025665633979":1509788624565,"1025665633984":1509788624565,"1021438431958":1509788624817,"1025665633990":1509788624538,"1025665633993":1509788624545,"1022848886316":1509788624328,"1021554432448":1509788624405,"1025665633999":1509788624545,"1006788749804":1478686804029,"1001790341091":1478686417023,"1007146319394":1509788624374,"1021957747154":1478686417147,"1025665634003":1509788624545,"121849626":1444487341754,"1022443343597":1478686417214,"1025665634012":1509788624545,"1022205182108":1478686417190,"1025665634018":1509788624545,"1025665634024":1509788624545,"1025056959155":1509788624999,"1012348220622":1478686417223,"1022370204270":1509788624300,"1021436989961":1509788624977,"1020006448510":1509788625076,"1020556860817":1478686417017,"1619206160":1478686417020,"1021793511385":1478686417255,"1021857999629":1478686417257,"1021793511376":1478686417255,"1022229430737":1478686417282,"1022229430740":1478686417282,"1018961034889":1478686804027,"1024936370866":1509788625006,"1020824907174":1478686416982,"1024685888585":1509788624346,"1021028596317":1478686416977,"1020294057491":1465470268285,"1022229430735":1478686417282,"1016858640685":1509788624976,"1024283327578":1509788624326,"1001264996398":1478686417024,"1021793511322":1478686417255,"1021793511321":1478686417255,"1025863424565":1509788667580,"1024097202424":1509788624969,"1025779537215":1509788625087,"1025779537213":1509788625106,"1025779537212":1509788625122,"1025779537211":1509788625114,"1021793511354":1478686417255,"1021793511353":1478686417255,"1021477229788":1478686417110,"1020966204995":1509788624369,"1022042027932":1478686417268,"1017923453208":1509788624311,"1022042027931":1478686417268,"1025610582732":1509788624521,"1025665634183":1509788624837,"1022042027929":1478686417268,"1025610582734":1509788624521,"1025665634182":1509788624838,"1018805449838":1509788624929,"1025610582722":1509788624521,"1025610582727":1509788624520,"1025610582726":1509788624520,"1025665634190":1509788624837,"1022450814767":1478686417072,"1025665634197":1509788624868,"1021385871023":1478686417042,"1021460582963":1478686417045,"1021619051717":1478686804046,"1013148001711":1478686804017,"1025610582736":1509788624520,"1021014964428":1478686417001,"1022042027908":1478686417268,"1021573700473":1509788624814,"1022042027904":1478686417268,"1021250340492":1478686417039,"1024471975553":1509788624170,"1025779537149":1509788624523,"1018919878042":1509788624361,"1020016802941":1509788624320,"1025779537146":1509788624537,"1025779537145":1509788624542,"1025779537144":1509788624540,"1025900256694":1509788667463,"1025665634233":1509788625246,"1021958008997":1478686417261,"1023932180170":1491634246531,"1023932180169":1491634246529,"1021958008999":1478686417261,"1023932180168":1491634246529,"1019884549130":1478686804065,"1025665634236":1509788625244,"1023161759969":1509788625044,"1025665634238":1509788625165,"4813447078":1509788624165,"1025665634240":1509788625165,"1025665634243":1509788625112,"1025665634251":1509788625131,"1025665634250":1509788625131,"1025665634257":1509788625131,"1025665634256":1509788625131,"1023877522018":1491634246512,"1021554825432":1478686417048,"1021801507247":1478686417130,"1019283313547":1509788624391,"1025610582701":1509788624521,"1025779537083":1509788624197,"1025779537081":1509788624200,"1025610582714":1509788624520,"1021227926645":1478686417003,"1025610582718":1509788624521,"1023144327603":1509788625045,"1022041634811":1478686417058,"1025610582706":1509788624521,"1022104681283":1478686417182,"1025050929312":1509788624458,"1023958133185":1509788667535,"1750542810":1444487341722,"1025665634071":1509788624270,"1025665634070":1509788624270,"1025665634073":1509788624227,"1025279653403":1509788624429,"1025665634074":1509788624227,"1025279653405":1509788624426,"1025279653404":1509788624432,"1025779537015":1509788624831,"1025779537014":1509788624828,"1025665634082":1509788624199,"1020776540748":1478686417076,"1025665634086":1509788624215,"1019852042926":1478686804043,"1025665634089":1509788624207,"1022015419801":1478686417160,"1025279653418":1509788624408,"1019852042924":1478686804043,"1025665634091":1509788624207,"1019852042925":1478686804043,"1025665634093":1509788624207,"1025779537017":1509788624745,"1025779537016":1509788624822,"1025665634099":1509788624207,"1025665634103":1509788624207,"1019745086685":1509788624312,"1750542827":1444487341720,"1025665634108":1509788624230,"1750542825":1444487341720,"1021738067206":1478686417251,"1022293656668":1478686416977,"1022238868227":1509788624946,"1025402077076":1509788624972,"1022238868229":1509788624932,"1022238868231":1509788624931,"1021175366625":1465470268188,"1022238868232":1509788624930,"1022238868235":1509788624941,"1000526165285":1444487341710,"1022238868236":1509788624931,"1024471975551":1509788624171,"1024471975550":1509788624171,"1024471975549":1509788624171,"1024471975548":1509788624170,"1024852614346":1509788624925,"1021764674791":1478686417009,"1022042027903":1478686417170,"1021680656870":1478686804029,"1022042027901":1478686417170,"1012901844143":1478686804020,"1022140595539":1478686417013,"1021258335911":1478686417040,"1025665634166":1509788624916,"1025665634169":1509788624916,"1211173320":1444487341750,"1025665634172":1509788624864,"1025665634175":1509788624826,"1025665634174":1509788624864,"1025011082629":1509788624997,"1021803997869":1509788624403,"1021292153636":1478686417102,"1025508083694":1509788624296,"1025540588568":1509788624303,"1025508083701":1509788624296,"1023088227889":1509788624439,"1025508083699":1509788624296,"1021235135649":1478686417039,"1024313212701":1509788624926,"1018961034240":1478686804040,"1019129039373":1509788624302,"1024375767901":1509788625070,"1021693895453":1478686804033,"1021663092084":1478686417050,"1021693895450":1478686804032,"1021693895448":1478686804032,"1021538573012":1478686417245,"1021439741997":1478686417007,"1021971902693":1478686417149,"1021531757237":1509788624397,"1023088227956":1509788624439,"1025042934762":1509788624498,"1023969274849":1509788624294,"1025902353920":1509788667448,"1023088227911":1509788624439,"1021310896218":1465469681397,"1021938873032":1478686417260,"1021938873044":1478686417260,"1018920009412":1509788624940,"1019608246267":1509788625076,"1025791596393":1509788624409,"1021938873052":1478686417260,"1022919403729":1509788624393,"1022919403732":1509788624393,"1019283312742":1509788624390,"4834419380":1509788624159,"1020556861347":1478686417017,"1021934940755":1509788624464,"1010954347471":1478686804030,"1024313212804":1509788624926,"1025540588718":1509788624303,"1022323017059":1478686417200,"1021328460238":1478686417005,"1021161210829":1478686417003,"1023626647272":1509788625144,"1013855505524":1478686804046,"1002086798086":1478686417024,"1020393281067":1480585069076,"1021611450064":1509788624397,"1021613547263":1478686417116,"1021541194379":1478686417047,"1024142422091":1509788667500,"1024142422090":1509788667499,"1025350301775":1509788624305,"1021608566643":1478686417008,"1017038606301":1478686804032,"1024142422082":1509788667499,"1024142422085":1509788667499,"1018920009663":1509788624940,"1022401267755":1478686417292,"1021668598727":1509788624396,"1021742131031":1478686417125,"1018310384581":1478686804023,"1021701366264":1478686417250,"1016930993682":1478686804019,"1010403181414":1478686804025,"1021967839696":1478686417149,"1023097140871":1509788625046,"1025100607342":1509788624181,"1024095499125":1509788624459,"1024095499123":1509788624459,"1408307380":1478686804024,"1024095499120":1509788624459,"1024095499135":1509788624459,"1024095499134":1509788624459,"1025353447540":1509788624514,"1024142422018":1509788667499,"1024095499132":1509788624459,"1024095499130":1509788624459,"1024095499128":1509788624459,"1024142422043":1509788667499,"1024095499107":1509788624459,"1025453818485":1509788624971,"1021338030022":1465470268222,"1025540588867":1509788624303,"1024095499105":1509788624459,"1024095499119":1509788624459,"1025453818488":1509788624933,"1022078335789":1478686417177,"1024095499112":1509788624459,"1024095499094":1509788624460,"1024095499090":1509788624459,"1024142422062":1509788667500,"1024095499100":1509788624459,"1024142422048":1509788667499,"1016298202007":1480585069065,"1019413076544":1509788624389,"1024142422077":1509788667499,"1021378923895":1478686417105,"1021378923896":1478686417105,"1024095499085":1509788624459,"1024142422065":1509788667499,"1024095499082":1509788624459,"1022021973550":1478686417266,"4997868135":1509788667395,"1022028134142":1478686417164,"1022102321515":1478686417181,"1022028134141":1478686417164,"1021881593755":1509788624433,"4834419643":1509788624159,"1025900257062":1509788667463,"1024095499153":1509788624459,"1022457760892":1478686417016,"1022001657674":1478686417011,"1023688383447":1509788625082,"1024095499162":1509788624459,"1021859702998":1478686416973,"1022193155127":1478686416992,"1024095499141":1509788624459,"1022437969233":1509788625079,"1021757990620":1478686417300,"1024095499138":1509788624459,"1024095499137":1509788624459,"1024095499150":1509788624459,"1021558889200":1478686417245,"1022456187917":1478686804045,"1022456187916":1478686804045,"1021873073999":1478686804032,"1022456187913":1478686804045,"1020284227205":1465470268317,"1022456187912":1478686804045,"1022456187915":1478686804045,"1022456187909":1478686804045,"1021512881614":1478686417047,"1022456187911":1478686804045,"1022456187910":1478686804045,"1025791596243":1509788624409,"1025700238144":1509788624933,"1025100607482":1509788624273,"1024313212641":1509788624926,"1227033340":1444487341732,"1020946675253":1478686417084,"1020946675261":1478686417084,"1023146425171":1509788624424,"1012482701376":1478686417074,"1021185591178":1478686417098,"1024134952927":1509788667499,"1025609535484":1509788625001,"1024134952920":1509788667499,"1024134952923":1509788667498,"1025609535486":1509788625001,"1024134952917":1509788667499,"1022491055575":1478943089490,"1024334707685":1509788624997,"1024134952909":1509788667499,"1021796655919":1478686417130,"1021185591192":1478686417098,"1024153039039":1509788667495,"1024134952906":1509788667499,"1024153039024":1509788667495,"1020946018799":1478686417084,"1024134952898":1509788667499,"1020447413162":1509788625076,"1020447413163":1509788625077,"1023958133867":1509788667535,"1024153038980":1509788667495,"1024134952944":1509788667499,"1021356771654":1478686417239,"1021757464994":1509788624403,"1024134952943":1509788667498,"1024134952942":1509788667499,"1024134952936":1509788667499,"1024134952939":1509788667498,"1024458736297":1509788625030,"1024134952932":1509788667498,"1024134952929":1509788667499,"1021356771659":1478686417239,"1020335608943":1465470268182,"1022246471282":1478686417195,"1022491055590":1478943089490,"1018889207338":1509788624366,"1020556859715":1478686417017,"1025791594838":1509788624409,"1025315962163":1509788624391,"1025628145809":1509788624931,"1006923888115":1478686804022,"1025791594828":1509788624409,"1025791594825":1509788624409,"1025791594823":1509788624409,"1021765067077":1478686417254,"1022460513258":1478686417016,"1024134952889":1509788667499,"1021681443965":1509788624400,"1024265109116":1509788624819,"1023537253137":1509788624446,"1023537253133":1509788624446,"1023537253132":1509788624446,"1569266171":1444487341730,"1025791594860":1509788624409,"1023537253134":1509788625151,"1023537253129":1509788625152,"1024265109102":1509788624420,"1023537253128":1509788625152,"1023537253131":1509788624446,"1023537253130":1509788625151,"1024134952868":1509788667498,"1023537253127":1509788624446,"1025791594852":1509788624409,"1023537253126":1509788625151,"1021846204074":1509788624455,"1009758199333":1491634246511,"1022111760127":1509788624959,"1009758199329":1491634246511,"1025043983646":1509788624192,"1001061177246":1478686417022,"1024557303842":1509788624414,"1022424598843":1478686417293,"1022111760086":1509788624928,"1024334707540":1509788624997,"1019611128259":1509788625076,"1022040322583":1478686417058,"1025043983660":1509788624191,"761620928":1444487341716,"1025043983657":1509788624191,"1019611128260":1509788625078,"1025043983653":1509788624191,"1025043983652":1509788624191,"209668307":1444487341724,"1025043983651":1509788624192,"1021588381483":1509788624818,"1022179523320":1509788624920,"1021873072185":1478686804033,"1025043983673":1509788624191,"1009758199316":1491634246511,"1025043983671":1509788624191,"1024362923166":1509788667509,"1022069554246":1478686417301,"1025727895050":1509788625083,"1021493481967":1478686804040,"234965706":1444487341742,"1024153038949":1509788667495,"1022756087075":1509788625074,"1024153038951":1509788667495,"1024153038973":1509788667495,"1021289663907":1478686417238,"1021341304986":1478686417103,"1022220387613":1478686417281,"1002037774868":1478686804029,"1022428399997":1478686417070,"1021713557211":1509788624396,"1019447943112":1509788624369,"1019447943113":1509788624369,"1022088166696":1478686417180,"1022214751398":1478686417013,"1021376301776":1478686417105,"1023366201716":1509788625164,"1021526381479":1478686417047,"1021350873425":1509788624513,"1002037774860":1478686804029,"1024799792955":1509788625207,"1024799792949":1509788625206,"1024799792950":1509788625207,"1024799792946":1509788625207,"1024799792941":1509788625207,"1024799792936":1509788625207,"1020752817248":1478686417028,"1023135150691":1509788624218,"1023135150690":1509788624218,"1024799792932":1509788625206,"1024799792934":1509788625206,"1021475918148":1478686417242,"1024799792928":1509788625206,"1024799792930":1509788625206,"1023262423806":1509788625042,"1021627701262":1478686417119,"1024799792927":1509788625206,"1024799792926":1509788625207,"1838753981":1478950494927,"1024799792921":1509788625207,"1020827134913":1478686417078,"1024799792923":1509788625207,"1024799792922":1509788625207,"1023135150685":1509788624218,"1024799792917":1509788625207,"1023135150687":1509788624218,"1012117267235":1478686417025,"1023135150686":1509788624218,"1024799792918":1509788625207,"1019583604278":1480585069074,"1024799792911":1509788625206,"1021421130921":1509788624405,"1016495206012":1509788624941,"1021680526686":1478686804026,"255019627":1444487341730,"1019723459060":1478686804021,"1025712952564":1509788624306,"1023096877280":1509788625162,"1023096877283":1509788625162,"1023096877279":1509788625162,"1023096877278":1509788625162,"1023096877275":1509788625162,"1014142425629":1465470268245,"1024244792376":1509788624317,"1022111760157":1509788624439,"465657517":1478686804023,"1020907485006":1478686417032,"483744165":1491634246533,"1021840568094":1509788624394,"1022048580540":1478686417059,"1022338747719":1478686417069,"1838753814":1478950494927,"1022375448365":1480585069075,"1000309105256":1478686417018,"483744068":1491634246533,"1017582168545":1478686804031,"1021246407289":1478686417003,"1023829812345":1509788624940,"255019686":1444487341741,"1021863636650":1478686417135,"1024283326835":1509788624326,"1023135150828":1509788624445,"1023135150831":1509788624445,"1023135150824":1509788624445,"1023135150827":1509788624445,"1023135150826":1509788624445,"756771006":1444487341716,"1017171382632":1478686804019,"1020941431170":1478686417084,"1022207935759":1478686417191,"1025540588450":1509788624303,"1012120674885":1478686416994,"1022059328084":1478686417173,"1021472379222":1478686417109,"1014876933725":1478686804032,"1022196693651":1478686417189,"1020988617380":1478686417230,"1022470605553":1478686804048,"1022470605552":1478686804048,"1022470605555":1478686804048,"1022470605554":1478686804048,"1022470605557":1478686804048,"1022470605556":1478686804048,"4997868545":1509788667395,"1022470605559":1478686804048,"1022470605558":1478686804048,"1022470605561":1478686804048,"1022470605560":1478686804048,"1024586402588":1509788625026,"1017168893691":1478686804025,"1022470605563":1478686804048,"1022470605562":1478686804048,"1024264847332":1509788624419,"1022470605549":1478686804048,"1021822610510":1509788624394,"1022470605551":1478686804048,"1022470605550":1478686804048,"1023773579448":1509788624970,"1021494137638":1509788624515,"1021334882979":1478686417239,"1021494137637":1509788624515,"1021494137632":1509788624515,"1024661509244":1509788625026,"1012652933170":1478686417224,"1021494137647":1509788624515,"1025626966726":1509788625002,"1021494137644":1509788624515,"1025902353006":1509788667449,"1025626966722":1509788624441,"1021494137653":1509788624515,"1021458879816":1478686417007,"1022407953081":1478686417292,"1021494137663":1509788624515,"1021494137660":1509788624515,"1021494137661":1509788624515,"1021494137658":1509788624515,"1021494137656":1509788624515,"1025626966736":1509788624440,"1021060578623":1478686416976,"1025626966762":1509788624433,"1009850472715":1491634246514,"1021858000317":1478686417135,"1021460583703":1478686417045,"1025626966775":1509788624454,"1025626966773":1509788624453,"1025626966769":1509788624433,"1019949563670":1509788624385,"1010924329322":1478686804052,"1021243261040":1478686417039,"1022898564901":1509788624402,"1022416996980":1478686417209,"1021494137671":1509788624515,"1018961033280":1478686804065,"1021494137666":1509788624515,"1021494137667":1509788624515,"1021494137664":1509788624515,"1021494137665":1509788624515,"1020267579947":1480585069076,"1012108878050":1478686417025,"1020267579944":1480585069076,"1020267579945":1480585069076,"1022871560544":1509788624381,"1025050931018":1509788624232,"1025779536806":1509788624406,"1014283464346":1478686804016,"1025626966712":1509788624433,"1025626966706":1509788624433,"1021493220305":1478686417111,"1021743571660":1478686417125,"1023537252845":1509788624219,"1015242106714":1480585069068,"1023537252841":1509788624219,"1022209115666":1478686417013,"1021493220293":1478686417111,"1023537252840":1509788624220,"1004353068644":1444487341707,"1021493220294":1478686417111,"1021493220295":1478686417111,"1023537252842":1509788624219,"1024462930118":1509788625083,"1022022366000":1478686417163,"1023845934989":1491634246537,"1023845934986":1491634246537,"1025698534934":1509788625082,"1023537252835":1509788624219,"1010541858484":1509788624277,"1022193547568":1478686417189,"1021873072676":1478686804026,"1025779536767":1509788624425,"1025779536766":1509788624431,"1025779536765":1509788624428,"1022220781402":1478686417281,"1021947262615":1478686417144,"1025711118192":1509788624295,"1019788211747":1478686804023,"1025896585738":1509788667442,"1022356180763":1478686804069,"1025700238920":1509788624940,"1018509485524":1509788624837,"1025482917252":1509788624515,"1021828771763":1478686417133,"1022124604753":1478686417277,"1025482917261":1509788624272,"1022022366017":1478686417163,"1025482917262":1509788624615,"1025482917259":1509788624919,"1017171382847":1478686804019,"1024638048050":1509788667463,"1025482917265":1509788625248,"1022479259285":1478943089487,"1024498454223":1509788625070,"1022283039548":1509788624945,"1022096686678":1478686417012,"1021881461533":1509788624508,"1021881461530":1509788624436,"1749888858":1444487341737,"1022019875542":1478686417058,"1001385189570":1480585069061,"325014592":1478686804033,"1022069555164":1478686417301,"1022360768180":1478686417203,"1024985260581":1509788667846,"1016971104243":1478686804067,"1022277010346":1478686417197,"1020243594392":1465470268312,"1022121983213":1478686417013,"1022332715024":1509788624292,"1019283314129":1509788624390,"1024527813961":1509788625027,"1021600439282":1478686417008,"1024265108824":1509788624195,"1013170676232":1478686804049,"1022381083921":1478686417290,"1021925370053":1478686417259,"1025900256229":1509788667463,"1022277010428":1478686417285,"1018721433350":1509788624287,"1749888824":1444487341738,"1022815986435":1509788625055,"1021350873639":1509788624917,"1023310366056":1509788625041,"1021878447049":1478686417136,"1022487778928":1478943089489,"1022428138043":1478686417294,"1019831596530":1509788624302,"1024265108919":1509788624534,"1020796726119":1478686417031,"1021652736100":1509788624815,"483744621":1491634246533,"1024265108896":1509788625102,"1020863969131":1478686417031,"1020900144458":1509788625220,"1017260777053":1465470268268,"1004353068836":1444487341707,"1023926411760":1491634246530,"1025628146435":1509788624931,"1019540743762":1509788624315,"4997869069":1509788667397,"1022516745658":1480585069090,"1021661255874":1478686804033,"1016971104039":1478686804058,"1024579062461":1509788624932,"1018923547527":1509788624301,"1021652736046":1509788624194,"1015710037473":1465470268246,"1017026675563":1509788624367,"1023926545966":1491634246528,"1022135612668":1478686417063,"1019930292321":1509788624385,"1016245638201":1458304307281,"1016245638200":1458304307281,"1022540733666":1509788625063,"1012321483718":1478686804062,"1016245638202":1458304307281,"1016245638204":1458304307281,"1021627700491":1478686417119,"1021829030155":1509788624394,"1001082281446":1478686417022,"1012321483725":1478686804062,"1025533775444":1509788624347,"1025533775447":1509788624347,"1022076760133":1509788624417,"1021730859812":1478686417251,"1025533775443":1509788624347,"1022076760134":1509788624417,"1021627700483":1478686417119,"1021659682677":1478686417050,"1025533775439":1509788624346,"1025784388958":1509788624348,"1021723388888":1509788624400,"1023431999974":1509788624519,"1570182609":1444487341721,"1024926411488":1509788624182,"1024926411491":1509788624182,"1019434308541":1509788624319,"1022331277065":1478686417288,"1016443691129":1478686804017,"1022375838447":1509788624945,"1018961032775":1478686804050,"1024926411479":1509788624182,"1020443746219":1478686804032,"1021932840822":1478686417301,"1024926411483":1509788624182,"1024926411485":1509788624182,"1024926411487":1509788624182,"1024926411460":1509788624182,"1088620693":1444487341701,"1022015421511":1509788624463,"1024926411467":1509788624182,"1024926411469":1509788624182,"1001082281395":1478686417022,"1025428785210":1509788625079,"1025749654293":1509788624350,"1025749654292":1509788624350,"1022055399262":1478686417173,"1021782634114":1509788624847,"1022121980738":1478686417013,"1020850333482":1478686417031,"1218773000":1480585069060,"1023773185530":1491634246535,"1007295516457":1478686804015,"1025732221494":1509788624942,"1021456653218":1478686417108,"1024556909686":1509788624408,"1024579061126":1509788624932,"1021955782978":1478686417146,"1021612102876":1478686417246,"1021955782983":1478686417146,"1021955782980":1478686417146,"1021955782981":1478686417146,"1021262139389":1478686804039,"1021686294837":1509788624396,"1021955782986":1478686417146,"1021955782984":1478686417146,"282155071":1478686417019,"1021612102864":1478686417246,"1022089474394":1478686417180,"1021456653211":1478686417108,"1838753120":1478950494927,"1022002707466":1478686804066,"1022454744814":1478686417072,"1022371120114":1509788624291,"1021981342506":1478686416986,"1022273605048":1478686417014,"1022056447672":1478686417012,"1021143124271":1478686417096,"1022209116568":1478686417013,"1025749654206":1509788624351,"1021258862090":1478686417101,"1025749654205":1509788624351,"1025033494794":1509788624402,"1019283315672":1509788624391,"1022297852955":1478686417199,"1012079521048":1478686804029,"1021857604292":1478686417053,"1021613151598":1478686417247,"1021613151596":1478686417247,"1024226308399":1509788624983,"1019238745813":1509788624312,"1021562294353":1509788624405,"1021894960168":1509788624465,"1021797445194":1478686417130,"1022134825582":1478686417276,"1017261428755":1509788625080,"1020365626344":1509788624362,"1020365626338":1509788624362,"1020551484671":1478686804035,"1020365626339":1509788624362,"1020365626336":1509788624362,"1020365626337":1509788624362,"1022418961801":1478686417016,"1020365626342":1509788624363,"1020365626343":1509788624362,"1022479129087":1478943089253,"1020945628256":1478686417229,"1022431806679":1478686417071,"1019272697875":1509788624315,"1021548269632":1478686417113,"1020945628255":1478686417229,"1020945628251":1478686417229,"1020365626335":1509788624362,"1002086799444":1478686417024,"1021652735592":1509788624533,"1025485933206":1509788624436,"1025485933204":1509788624436,"1025485933203":1509788624437,"1025485933202":1509788624437,"1021548269600":1478686417113,"1001082280964":1478686417022,"1021174057876":1465470268186,"1021627700478":1478686417119,"1021548269630":1478686417113,"1021627700469":1478686417119,"1019302844955":1509788624312,"1025628144902":1509788624929,"1021627700465":1478686417119,"1020767101766":1478686416996,"1022467458755":1478686417218,"1021939792213":1478686417143,"1021939792209":1478686417143,"1025652131003":1509788625019,"1021939792204":1478686417143,"1022128403086":1478686417184,"1021939792205":1478686417143,"1022052646370":1478686417270,"1025289092364":1509788624286,"1025679656328":1509788624349,"1022052646367":1478686417270,"1021968627919":1509788625246,"1022052646349":1478686417270,"1025270217734":1509788624508,"1021968627915":1509788625096,"1022292479921":1478686804029,"1021968627897":1509788625246,"1021582741940":1478686417114,"1025732221125":1509788624942,"1009744040905":1491634246510,"1023393992106":1509788625071,"1021968627891":1509788625090,"1021262138696":1478686804065,"1021968627885":1509788625089,"1021968627882":1509788625242,"1021968627880":1509788625242,"1021783158196":1478686417128,"1021968627875":1509788625096,"1021968627872":1509788625242,"1021968627870":1509788625242,"1021968627871":1509788625090,"1000309108127":1478686417018,"1021700843677":1478686804027,"1001673028314":1478686804029,"1529549147":1444487341707,"1529549146":1444487341706,"1529549145":1444487341706,"1021435287766":1478686417044,"1529549144":1444487341707,"1018922759697":1509788624282,"1025270217807":1509788624508,"1021953293124":1509788624355,"421876644":1478686417019,"1021953293125":1509788624355,"1021953293126":1509788624355,"1021953293127":1509788624354,"421876640":1478686417019,"1021979506908":1478686417010,"1021953293128":1509788624354,"209667819":1444487341730,"1022611771920":1509788625075,"1025270217898":1509788624508,"209667805":1444487341733,"1025485933045":1509788625135,"1020443745633":1478686804066,"1025485933044":1509788625135,"1025485933043":1509788625135,"421876630":1478686417019,"1021166192744":1478686417234,"1023408016779":1509788625040,"421876638":1478686417019,"1024528466057":1509788624471,"1024528466056":1509788624471,"1024528466059":1509788624471,"1024528466058":1509788624471,"1025386346478":1509788624521,"1024528466052":1509788624471,"1024528466055":1509788624471,"1024528466054":1509788624471,"1021624031163":1509788624396,"1832200146":1491634246517,"1022479784589":1478943089487,"1021102257259":1478686417095,"1024192625824":1509788625034,"1021776735392":1509788624395,"255018437":1444487341731,"1021753143083":1478686417126,"1022857014548":1509788624997,"1014687009309":1478686804015,"1019283314710":1509788624390,"1019283315173":1509788624390,"1021953293012":1509788624355,"1022490794696":1478943089490,"1021953293009":1509788624354,"1021953293010":1509788624355,"1020133887820":1509788625076,"1021953293011":1509788624355,"1019724375995":1509788624313,"1021797444654":1478686417130,"1666656329":1478686416993,"1021311942941":1465469681397,"1025270218004":1509788624508,"1016779110151":1478686804017,"1020086307361":1509788624383,"1022279896957":1478686417285,"1021966924320":1478686417148,"1021352707718":1465470268227,"1021352707720":1465470268227,"1021352707721":1465470268227,"1025188035107":1509788624288,"1022896464590":1509788624382,"4971914010":1509788624160,"1019865677599":1509788625077,"2051617052":1478686804051,"1021491256869":1478686417111,"1022868024351":1509788625074,"1022631039493":1509788624456,"1001732665448":1478686417023,"1021551809213":1509788624401,"1019739580066":1509788624173,"1013274222667":1509788625016,"1024501203568":1509788625070,"1015415250948":1480585069067,"1025607565751":1509788624564,"1021055987939":1478686416984,"1021218754088":1478686416991,"1009017529698":1478686804054,"1025607565758":1509788624539,"1025607565756":1509788624552,"1021727451378":1478686804046,"1025607565755":1509788624564,"1025607565754":1509788624564,"1009017529700":1478686804054,"1021491388154":1478686417111,"1022128402632":1478686417184,"1023220610974":1509788624251,"1019260771206":1509788624313,"1021619050007":1478686416979,"1023220610970":1509788624251,"1023220610964":1509788624251,"1023220610967":1509788624251,"1023220610962":1509788624251,"1025607565784":1509788624566,"1023220610957":1509788624251,"1023220610959":1509788624251,"1025607565765":1509788624547,"1023220610958":1509788624251,"1020925704407":1509788624937,"1023220610952":1509788624251,"1025607565761":1509788624539,"1023220610954":1509788624251,"1023220610948":1509788624251,"1024528466320":1509788624471,"1025607565774":1509788624547,"1023220610951":1509788624251,"1023220610950":1509788624251,"1023220610945":1509788624251,"1025607565771":1509788624547,"1023220610947":1509788624251,"1025732221282":1509788624942,"1023220610989":1509788624251,"1023220610984":1509788624251,"1023220610987":1509788624251,"1023220610986":1509788624251,"1008611598077":1478686804030,"1023220610980":1509788624251,"1024452316424":1509788667888,"866220124":1478950494918,"1023220610976":1509788624251,"1021330030830":1465470268219,"1024294465626":1509788624583,"1006734879484":1478686804032,"1021330030825":1465470268219,"1020789122849":1478686417076,"1024294465618":1509788624583,"1022611510428":1509788625062,"1024579060056":1509788624926,"1024294465605":1509788624582,"1024294465659":1509788624582,"1022536146731":1509788624383,"1018389418099":1465470268312,"1022536146730":1509788624383,"1021173796474":1478686417098,"1022536146733":1509788624383,"1024998894203":1509788624915,"1022536146732":1509788624383,"1022536146734":1509788624383,"1024294465660":1509788624582,"1024294465651":1509788624582,"1024294465643":1509788624582,"350443729":1444487341725,"1024294465640":1509788624582,"1025732222650":1509788624942,"1024192625278":1509788625071,"1024294465646":1509788624582,"1024294465644":1509788624582,"350443739":1444487341745,"1025791596839":1509788624409,"1024294465633":1509788624583,"1024587318012":1509788624434,"1024587318011":1509788624426,"1024294465639":1509788624583,"1024998894179":1509788624836,"1024294465638":1509788624583,"1024294465563":1509788624888,"1024294465560":1509788624888,"1022040718070":1478686417268,"1024294465567":1509788624888,"1024341390121":1509788625031,"1024294465555":1509788624888,"1024587317901":1509788624581,"1024587317900":1509788624580,"1024294465552":1509788624888,"1022473624718":1478943089253,"1024294465558":1509788624888,"1024587317911":1509788624581,"1024587317910":1509788624581,"1024294465546":1509788624888,"1024587317909":1509788624581,"1024294465545":1509788624888,"1024587317908":1509788624581,"1024294465544":1509788624888,"1024587317907":1509788624581,"1024587317906":1509788624581,"1024587317905":1509788624581,"1025642824106":1509788624745,"1025642824101":1509788624832,"1025642824100":1509788624828,"1024294465537":1509788624888,"1022040718057":1478686417268,"1025642824102":1509788624823,"1024546686728":1509788624959,"1024587317915":1509788624581,"1024587317927":1509788624581,"1024167459244":1509788625035,"1024587317924":1509788624581,"1021270000871":1478686804033,"1024587317922":1509788624581,"1024587317934":1509788624581,"1025628143793":1509788624929,"1024444188963":1509788625031,"1024587317930":1509788624581,"1024294465579":1509788624888,"1022389077948":1478686417069,"1024587317942":1509788624580,"1024294465578":1509788624888,"1024587317941":1509788624581,"1024294465577":1509788624888,"1024294465576":1509788624889,"1024587317939":1509788624581,"1024587317938":1509788624581,"1024587317937":1509788624581,"1024294465571":1509788624889,"1024587317949":1509788624580,"1024294465569":1509788624888,"1024587317947":1509788624580,"1024294465574":1509788624889,"1024587317945":1509788624581,"1025732222479":1509788624942,"1024587317839":1509788624580,"1022475983926":1478943089487,"1024587317838":1509788624580,"1024587317837":1509788624580,"1024587317836":1509788624580,"1022611379206":1509788625062,"1025784519143":1509788624349,"1024587317835":1509788624579,"1022413717752":1478686417208,"1022475983922":1478943089487,"1022536146841":1509788624386,"1022536146840":1509788624386,"1024587317846":1509788624580,"1022536146843":1509788624386,"1024587317845":1509788624580,"1022536146842":1509788624386,"1022536146844":1509788624386,"1024587317842":1509788624580,"1024587317841":1509788624580,"1016622612246":1478686804024,"1024587317840":1509788624580,"1024546686916":1509788624959,"1024587317855":1509788624579,"1024587317854":1509788624580,"1024587317852":1509788624580,"1022536146837":1509788624386,"1020865805351":1478686417031,"1022536146836":1509788624386,"1022021712205":1509788624463,"1024587317850":1509788624580,"1022536146839":1509788624386,"1023340384166":1509788624175,"1022536146838":1509788624386,"1024587317848":1509788624580,"1024587317861":1509788624580,"1023606333434":1509788624270,"1011397244853":1480585069074,"1024587317856":1509788624579,"1024587317869":1509788624579,"1024587317867":1509788624580,"1024587317864":1509788624580,"1024587317878":1509788624579,"1024587317874":1509788624580,"1018797848911":1478686804032,"1020805374187":1478686417030,"1024587317880":1509788624579,"1024587317766":1509788624579,"1024587317764":1509788624579,"1024294465688":1509788624583,"1024587317763":1509788624579,"1024294465695":1509788624582,"1024294465694":1509788624582,"1024587317761":1509788624579,"1024294465693":1509788624582,"1024294465683":1509788624583,"1025861195313":1509788667450,"1024587317774":1509788624579,"669739809":1478686804029,"1024587317773":1509788624579,"1024587317772":1509788624579,"1024294465680":1509788624583,"1021653390191":1509788624864,"1024998894228":1509788624871,"1024587317771":1509788624579,"1024587317769":1509788624579,"1024294465673":1509788624582,"1024587317778":1509788624579,"1024294465677":1509788624583,"1024294465664":1509788624582,"1024587317787":1509788624579,"1024294465671":1509788624582,"1006890197857":1478686804025,"1024587317784":1509788624579,"1024587317799":1509788624579,"1024587317798":1509788624579,"1023947514891":1491634246532,"1012108880491":1478686417025,"1024587317796":1509788624579,"1024587317795":1509788624579,"1024587317792":1509788624579,"1024587317805":1509788624579,"1024587317804":1509788624579,"1024587317803":1509788624579,"1021512358625":1478686417300,"1024587317802":1509788624579,"1024587317801":1509788624579,"1022438490638":1478686417213,"1024998894247":1509788624915,"1024998894243":1509788624842,"1023844232653":1509788625081,"1024998894242":1509788624835,"1022291298655":1478686417015,"1025063118485":1509788624292,"1021936516548":1509788624609,"1012404712940":1478686417026,"1021936516544":1509788624609,"1021936516545":1509788624609,"1021936516546":1509788624609,"1021936516547":1509788624609,"1021341696336":1509788624181,"1021341696337":1509788624180,"1022536146457":1509788624373,"1022536146456":1509788624373,"1022536146459":1509788624373,"1022536146458":1509788624373,"1022536146461":1509788624373,"1022536146460":1509788624373,"1021668077010":1478686417248,"1021341696335":1509788624180,"1022536146462":1509788624373,"1024780653654":1509788624487,"1022082004263":1478686417178,"1021686426763":1478686417121,"1025515817027":1509788624345,"1022111102802":1478686417012,"1001061178914":1478686417022,"1024961276338":1509788624330,"1021505149867":1478686417112,"1021610791269":1478686417116,"1020294054805":1465470268285,"1019113441844":1509788625079,"1022088164493":1478686417179,"1021944249641":1478686417260,"1021774637875":1509788624400,"1022941946265":1509788624935,"1022076106231":1478686417012,"1025508083841":1509788624295,"1022941946269":1509788624935,"1021936516524":1509788624609,"1021936516525":1509788624609,"1021936516526":1509788624609,"1024153041347":1509788667495,"1021936516527":1509788624609,"1021700845468":1478686804027,"1021936516522":1509788624608,"1022941946263":1509788624935,"1021603058123":1478686804022,"1009909984983":1478686804028,"1021936516523":1509788624609,"1022368367737":1478686417204,"1025270217539":1509788624508,"1021936516532":1509788624608,"1021936516533":1509788624609,"1021936516534":1509788624609,"1022941946251":1509788624935,"1021936516535":1509788624609,"1021936516528":1509788624609,"1021936516529":1509788624608,"1021936516530":1509788624608,"1021936516531":1509788624608,"1021468711379":1478686417007,"1022536146544":1509788624383,"1021936516541":1509788624608,"772236157":1444487341741,"1021936516542":1509788624609,"1021936516538":1509788624609,"1025299969481":1509788624294,"1025508083829":1509788624295,"1025423936893":1509788624293,"1000094144306":1478686804016,"1025508083834":1509788624295,"1025508083781":1509788624295,"1024668196790":1509788625025,"1021901906768":1509788624402,"1025270217627":1509788624508,"1025791596725":1509788624409,"1025508083790":1509788624295,"1025508083787":1509788624295,"1022536146619":1509788624377,"1006923889669":1478686804054,"1024847106295":1509788624970,"1021974265667":1509788624995,"1019957294864":1480585069076,"1021282976790":1478686417101,"1025609270834":1509788625000,"1023796515385":1509788625071,"1019957294862":1480585069076,"1019957294863":1480585069076,"777872265":1444487341723,"1024822464801":1509788624925,"1021686033461":1509788624396,"1021637792592":1478686417049,"1021063328030":1478686417036,"1021282976813":1478686417101,"1021983703021":1478686417152,"1018556147777":1509788624366,"1022073353919":1478686417176,"1022216326716":1480585069092,"1022216326711":1480585069092,"350444274":1444487341719,"1022073353903":1478686417176,"1023878442266":1491634246504,"1022073353870":1478686417176,"1024024060490":1509788624277,"1025732222138":1509788624942,"1023149176486":1509788624509,"1018850539246":1509788624320,"1024587317383":1509788624877,"1021852755332":1509788624394,"1024587317381":1509788624878,"1022073353983":1478686417176,"1024587317379":1509788624878,"1014142423344":1465470268245,"1022073353977":1478686417176,"1024587317378":1509788624878,"1024587317376":1509788624878,"1024587317389":1509788624878,"1024587317388":1509788624878,"1024587317386":1509788624877,"1024587317385":1509788624877,"1022073353966":1478686417176,"1024587317397":1509788624877,"1025759222458":1509788624304,"1024587317407":1509788624878,"1024587317405":1509788624877,"1024587317402":1509788624877,"1024587317415":1509788624877,"1024587317414":1509788624877,"1024587317413":1509788624878,"1022061558035":1478686417173,"1024587317412":1509788624877,"1024587317410":1509788624878,"1024587317409":1509788624878,"1021558888224":1478686417245,"1019739579306":1509788624173,"1021986061700":1478686417153,"1025042933700":1509788624498,"1016301612581":1480585069066,"1001082280793":1478686417022,"1024911994869":1509788624197,"1024911994868":1509788624203,"1021716442491":1478686417123,"1006825841958":1478686804023,"1024587317375":1509788624878,"1025876268202":1509788667405,"1024587317372":1509788624878,"1024587317371":1509788624878,"1023932049736":1491634246529,"1024947514866":1509788624993,"554528691":1491634246534,"1024587317369":1509788624877,"1024642637658":1509788624485,"1024587317253":1509788624877,"1024642637656":1509788624485,"1017715997361":1480585069072,"1024215823916":1509788624408,"1024215823907":1509788624429,"1024587317263":1509788624877,"1024642637650":1509788624485,"1024642637649":1509788624485,"1024587317261":1509788624877,"1024642637648":1509788624485,"1024587317260":1509788624876,"1989490776":1491634246510,"1021921698151":1509788624465,"1024642637654":1509788624485,"1024215823909":1509788624426,"1024587317257":1509788624877,"1024215823908":1509788624432,"1024642637652":1509788624485,"1024587317270":1509788624876,"1024587317269":1509788624876,"1024587317268":1509788624876,"1024642637646":1509788624485,"1024587317266":1509788624877,"1024587317264":1509788624877,"1017715997359":1480585069072,"1024587317277":1509788624876,"1024587317274":1509788624876,"1024587317273":1509788624876,"1007804738530":1478686804015,"1024587317272":1509788624876,"1024587317286":1509788624876,"1024587317285":1509788624877,"1024587317284":1509788624877,"1016971101753":1478686804058,"1024587317281":1509788624876,"1022073353813":1478686417176,"1024642637682":1509788624485,"1020017193922":1509788624389,"1024587317291":1509788624876,"1024587317290":1509788624876,"1024587317289":1509788624876,"1024587317288":1509788624876,"1024642637675":1509788624485,"1023846460446":1491634246537,"1024642637674":1509788624485,"1024642637673":1509788624485,"1024642637679":1509788624485,"1024642637676":1509788624485,"1024642637665":1509788624485,"1024642637664":1509788624485,"1024642637671":1509788624485,"1024248329753":1495284743423,"1022262725750":1509788624424,"1026231877570":1514456869774,"1019300093167":1509788624282,"1025642824428":1509788625124,"1025642824430":1509788625087,"1023897971432":1509788625019,"1021627830840":1478686417119,"1025642824427":1509788625106,"1025642824426":1509788625115,"1021627830839":1478686417119,"1010319062084":1478686804055,"1021687344831":1480585069077,"1025732222359":1509788624942,"1021222685272":1478686417099,"1024781702783":1509788624554,"1025642824402":1509788624406,"1021446298924":1478686417107,"1021502658966":1478686417046,"1025642824395":1509788624431,"1025642824394":1509788624428,"1022315940113":1478686417287,"1024587317757":1509788624578,"1016677267838":1465470268261,"1001082280691":1478686417022,"1022315940118":1478686417287,"1022436262489":1478686417213,"1024587317647":1509788624879,"1021662433399":1509788624396,"1021888799478":1478686417138,"1025791597141":1509788624409,"1024587317645":1509788624879,"1024587317644":1509788624879,"1024587317642":1509788624878,"1021974396360":1478686417262,"1024587317654":1509788624879,"1024587317653":1509788624879,"1024587317652":1509788624879,"1021638185432":1478686417008,"1024487966599":1509788624299,"1024587317650":1509788624879,"1024587317649":1509788624879,"1024587317662":1509788624879,"1024587317661":1509788624879,"1024587317660":1509788624879,"1024587317659":1509788624879,"1024587317658":1509788624879,"1024587317657":1509788624879,"1024587317656":1509788624879,"1020323422094":1509788625078,"1024587317670":1509788624879,"1021783419014":1509788624395,"1024587317669":1509788624878,"1024587317668":1509788624879,"1024737532048":1509788625021,"1024587317667":1509788624878,"1006923890392":1478686804054,"1024587317666":1509788624879,"1021756287712":1478686417126,"1024587317665":1509788624879,"1024587317664":1509788624879,"1052209630":1478686804033,"1021192277085":1478686417003,"1008896026999":1478686804061,"1020323422096":1509788625076,"220807849":1478686417019,"1022073354041":1478686417176,"1017063768787":1478686804069,"1021848167823":1509788624897,"1024587317581":1509788624888,"1007979069276":1478686804023,"1025642824304":1509788624523,"1024587317577":1509788624888,"1024587317576":1509788624888,"1025642824301":1509788624540,"1021851837537":1509788624402,"1024587317590":1509788624887,"1021848167833":1509788624897,"1025642824303":1509788624537,"1025642824302":1509788624542,"1024587317586":1509788624888,"1021848167838":1509788624897,"1024587317584":1509788624887,"1021848167825":1509788624897,"1019740103246":1509788625077,"1020378209335":1465470268302,"1024587317594":1509788624887,"1021059527824":1478686417232,"1020979574864":1478686417087,"1021848167850":1509788624897,"1025524075187":1509788625022,"1021848167854":1509788624897,"1021434895620":1478686417044,"1021848167843":1509788624897,"1021848167846":1509788624897,"1021848167867":1509788624897,"1021612233613":1478686417049,"1021848167869":1509788624897,"1021612233615":1478686417049,"1021848167871":1509788624897,"1022377674018":1509788624352,"1021848167857":1509788624897,"1020979574863":1478686417087,"1021848167861":1509788624897,"1020979574861":1478686417087,"1021848167863":1509788624897,"1021848167881":1509788624897,"1020979574833":1478686417087,"1019001769492":1480585069069,"1025043981898":1509788624191,"1025043981895":1509788624191,"1024587317519":1509788624887,"1021848167875":1509788624897,"1076170728":1509788625018,"1026728215271":1523788103987,"1020979574845":1478686417087,"1025043981919":1509788624191,"1024781702785":1509788624555,"1024587317527":1509788624888,"1024781702784":1509788624555,"1021848167897":1509788624897,"1024781702787":1509788624554,"1024781702786":1509788624555,"1021088101038":1478686417036,"1025043981915":1509788624191,"1021733874476":1509788624918,"1021873726291":1478686417257,"1024587317522":1509788624888,"1025043981909":1509788624191,"1025043981908":1509788624191,"1024587317532":1509788624888,"1020916137063":1478686417032,"1025043981906":1509788624191,"1024587317530":1509788624888,"1024587317529":1509788624888,"1025642824221":1509788624186,"1024973335077":1509788624288,"1024587317543":1509788624888,"1024587317542":1509788624888,"1024587317539":1509788624888,"1025642824213":1509788624197,"1025642824212":1509788624204,"1021848167905":1509788624897,"1024587317549":1509788624888,"1025043981924":1509788624192,"1024587317547":1509788624888,"1020796724026":1478686417029,"1025043981921":1509788624191,"1025043981920":1509788624191,"1025642824210":1509788624200,"1024587317556":1509788624887,"1025791597290":1509788624409,"1024587317552":1509788624887,"1024587317566":1509788624887,"1024587317564":1509788624887,"1024587317562":1509788624887,"1001385195484":1480585069061,"1025297737837":1509788624209,"1025050933543":1509788624568,"1012131952427":1478686417025,"1021015091667":1478686417090,"1020649665437":1480585069099,"1025297737828":1509788624208,"1023537258353":1509788624559,"1023537258352":1509788624559,"1023537258355":1509788624559,"1021787486136":1478686417129,"1023537258351":1509788624559,"1023537258350":1509788624559,"1025297737850":1509788624208,"1022019085806":1478686417011,"331039660":1444487341755,"1024936374786":1509788625006,"1025297737807":1509788624271,"1025685299029":1509788624382,"1023372105077":1509788625071,"1025685299028":1509788624382,"1025685299031":1509788624382,"1025685299030":1509788624382,"1025685299027":1509788624383,"1021827201378":1509788624394,"1022767362411":1509788625074,"1025685299032":1509788624382,"1925915365":1444487341712,"1021530441514":1478686417244,"1025685299015":1509788624383,"1024812632909":1509788624972,"1022432468321":1478686417212,"1021530441518":1478686417244,"1025297737817":1509788624215,"1021530441506":1478686417244,"1025297737813":1509788624228,"1025297737812":1509788624228,"1025685299017":1509788624383,"1012277960865":1478686804022,"1025685299016":1509788624383,"1025297737809":1509788624270,"4984502616":1509788624160,"1021594798949":1509788624817,"1144984699":1478686804022,"1024780650757":1509788667508,"1025685299005":1509788624382,"1025685299004":1509788624382,"1025685299001":1509788624382,"1025685299003":1509788624382,"1025685299002":1509788624382,"1021974258388":1509788624994,"1021974258389":1509788624994,"1022121061265":1478686417183,"1017629622218":1509788624363,"1022062995209":1478686417012,"1021063457962":1478686417093,"1021974258396":1509788624994,"1021974258398":1509788624994,"1021974258399":1509788624994,"1021974258394":1509788624995,"1021974258395":1509788624994,"1020322373502":1465470268301,"1021974258400":1509788624994,"1021974258401":1509788624994,"1021974258402":1509788624994,"1025297737737":1509788625113,"1021344980066":1478686417041,"213212381":1491634246512,"1925915297":1444487341709,"1025297737733":1509788625165,"1925915323":1444487341709,"1020748626373":1478686416996,"1025902349328":1509788667448,"1025297737750":1509788625133,"1025297737749":1509788625133,"1025297737748":1509788625133,"1025297737747":1509788625133,"1016587215165":1478686804042,"1016587215164":1478686804042,"1016587215167":1478686804042,"1016587215166":1478686804042,"1016587215161":1478686804042,"1016587215160":1478686804042,"1001004810470":1478686417022,"1016587215163":1478686804042,"1016587215162":1478686804042,"1016587215157":1478686804042,"1224939915":1491634246519,"1016587215156":1478686804042,"1016587215159":1478686804042,"1016587215158":1478686804042,"1016587215153":1478686804042,"1016587215152":1478686804042,"1022060373992":1478686417173,"1016587215155":1478686804042,"1016587215154":1478686804042,"1016587215149":1478686804042,"1016587215148":1478686804042,"1016587215150":1478686804042,"1025297737976":1509788624270,"1024574741776":1509788624925,"1021881597079":1509788624510,"1025297737972":1509788624270,"1023901644094":1509788624847,"1019596453091":1509788624971,"420956596":1444487341738,"1023095563637":1509788625145,"1023095563639":1509788625145,"1023095563641":1509788625145,"1023095563640":1509788625145,"1023095563647":1509788625145,"1021348388160":1478686417041,"1021201060989":1509788624977,"1021201060983":1509788624977,"1021201060980":1509788624977,"1021201060981":1509788624977,"1024333000483":1509788625031,"1025703379086":1509788624295,"1025685299108":1509788624297,"1024215820346":1509788624560,"1021396885440":1478686417106,"1024215820345":1509788624560,"1024215820344":1509788624560,"1024215820349":1509788624560,"1024215820343":1509788624560,"1025685299093":1509788624377,"1025685299095":1509788624377,"1025685299094":1509788624377,"1025685299101":1509788624377,"1025685299100":1509788624377,"1025685299102":1509788624377,"1025685299097":1509788624377,"1025297737858":1509788624208,"1025685299096":1509788624377,"1025685299099":1509788624377,"1025685299098":1509788624377,"930047901":1491634246515,"123819927":1491634246515,"1016587215172":1478686804042,"1001004810394":1478686417022,"1025297737876":1509788624230,"1016587215169":1478686804042,"1016587215168":1478686804042,"1016587215171":1478686804042,"1016587215170":1478686804042,"1025297737872":1509788624208,"1022463794809":1480585069117,"1022463794811":1480585069117,"1025297738093":1509788624839,"1022463794810":1480585069117,"1025297738092":1509788624839,"1022463794813":1480585069117,"1022463794812":1480585069117,"1025297738089":1509788624839,"1001113732841":1478686417024,"1022463794814":1480585069117,"1022240838569":1478686417065,"1025297738082":1509788624839,"1022371126255":1509788624290,"1021900078128":1478686417054,"1022255387373":1509788624280,"1021501605882":1478686417007,"1025297738078":1509788624865,"1020755703832":1478686417076,"1025297738076":1509788624865,"1020012997723":1478686804069,"1025297738074":1509788624916,"1022463794753":1480585069121,"1025297738070":1509788624917,"1022460780220":1478686417217,"1022460780216":1478686417217,"1022463794744":1480585069121,"1022463794746":1480585069121,"1022463794748":1480585069121,"1022463794737":1480585069121,"1025297738022":1509788624230,"1925915521":1444487341709,"1022463794739":1480585069121,"1021757600985":1509788624395,"1022463794741":1480585069121,"1022463794743":1480585069121,"1025297738017":1509788624208,"1925915524":1444487341710,"1022463794742":1480585069121,"1025297738016":1509788624208,"1022463794728":1480585069121,"1022463794730":1480585069121,"1022463794733":1480585069121,"1022463794732":1480585069121,"1025607965511":1509788624213,"1022463794734":1480585069121,"1012172716930":1478686417025,"1022132595309":1478686417276,"1022463794723":1480585069121,"1022463794722":1480585069121,"1001004810556":1478686417022,"1025593285549":1509788624929,"1020294062067":1465470268286,"1022463794724":1480585069121,"1022463794727":1480585069121,"1025297737998":1509788624199,"1021152563424":1478686417037,"1020392228243":1478686804028,"1022463794719":1480585069121,"1025297737992":1509788624228,"1022344387070":1478686417202,"1025297737988":1509788624228,"1016587215056":1478686804069,"1016587215053":1478686804069,"1016587215052":1478686804069,"1016587215055":1478686804069,"1021537651196":1509788624401,"1016587215054":1478686804069,"1016587215049":1478686804069,"1016587215051":1478686804069,"1016587215050":1478686804069,"1016587215045":1478686804069,"1025297738007":1509788624208,"1016587215044":1478686804069,"1022463794688":1480585069121,"1016587215047":1478686804069,"1016587215046":1478686804069,"1022463794690":1480585069121,"1022463794693":1480585069121,"1022463794692":1480585069121,"1025297738002":1509788624215,"1016587215043":1478686804069,"1022463794694":1480585069121,"1016670447400":1478686804018,"1019283309419":1509788624374,"1025607965597":1509788624212,"1025318840480":1509788624598,"1001385195091":1480585069061,"1010013534213":1491634246526,"1025297738235":1509788625165,"1025297738230":1509788625244,"1020796730697":1478686417029,"1025297738226":1509788625246,"1023220608451":1509788624585,"1025297738182":1509788624546,"653883219":1444487341716,"1025297738181":1509788624546,"1025297738178":1509788624546,"1025297738176":1509788624546,"1002386174854":1478686416993,"1025318840478":1509788624548,"331039247":1444487341726,"1021912006635":1478686417140,"1021912006630":1478686417140,"1001004810718":1478686417022,"1021040126870":1478686417036,"4985420007":1509788624160,"1022302835923":1478686417199,"1021040126869":1478686417036,"1022302835922":1478686417199,"1021594798821":1509788624419,"1021040126866":1478686417035,"1021040126867":1478686417036,"1925915405":1444487341709,"1025508611125":1509788624336,"1022076758432":1509788624417,"1025508611124":1509788624343,"1025297738150":1509788624565,"1025607965658":1509788624212,"1023946864351":1491634246531,"1025297738147":1509788624612,"1025508611120":1509788624341,"1025297738145":1509788624613,"1025593547545":1509788624425,"1025593547544":1509788624431,"1025297738169":1509788624546,"1025593547546":1509788624407,"1025297738168":1509788624546,"1025297738166":1509788624546,"1022245950383":1478686417195,"1025593547543":1509788624428,"1025731953495":1509788624922,"1025792378056":1509788624975,"1025297738163":1509788624565,"1022463794841":1480585069118,"1001004810626":1478686417022,"1022463794843":1480585069118,"1022463794842":1480585069118,"1022463794844":1480585069118,"1022463794832":1480585069117,"1022463794834":1480585069118,"1925915430":1444487341709,"1022463794836":1480585069118,"1016719599671":1478686804063,"1022463794839":1480585069118,"1023946864355":1491634246531,"1021848173560":1509788624493,"1021848173561":1509788624492,"1022463794827":1480585069117,"1021848173562":1509788624492,"1021848173563":1509788624492,"1022463794829":1480585069117,"1021848173564":1509788624492,"1022463794831":1480585069117,"1022076758430":1509788624417,"1021848173566":1509788624492,"1022076758431":1509788624417,"1021848173567":1509788624492,"1021848173552":1509788624492,"1021848173553":1509788624493,"1021848173555":1509788624493,"1021848173556":1509788624493,"1022463794820":1480585069117,"1021848173557":1509788624493,"1022348319141":1478686417202,"1021848173558":1509788624493,"1021848173559":1509788624493,"1022235202330":1478686417065,"1022996217272":1509788625050,"1022984289377":1509788625073,"1022235202319":1478686417065,"1022376892574":1478686804040,"592146769":1444487341721,"1022024984487":1478686416974,"1021797446936":1478686417130,"1025318841089":1509788625223,"1025318841088":1509788625136,"1019294974057":1509788625078,"4986731278":1509788624161,"1023751556744":1509788624926,"1755134682":1444487341744,"1021290191646":1465470268202,"1025297738255":1509788625132,"1021970325665":1478686417010,"1024055655674":1509788624329,"1025297738240":1509788625113,"1025297738271":1509788625169,"1021071978040":1478686417232,"1025710850999":1509788624305,"1025297738257":1509788625133,"1023172504388":1509788625044,"1755134493":1444487341719,"1022463794681":1480585069121,"1021039995093":1478686417232,"1022463794680":1480585069121,"1022463794683":1480585069121,"1025710850893":1509788624305,"1755134494":1444487341721,"1022463794685":1480585069121,"1022463794684":1480585069121,"1022463794686":1480585069121,"1016719600465":1478686804069,"1022463794672":1480585069121,"1001495822254":1478686417022,"1022463794674":1480585069121,"1022463794676":1480585069121,"1020175308108":1478686804031,"4986731444":1509788624161,"1020175308114":1478686804034,"1024147005844":1509788667462,"1022463794667":1480585069120,"1001385194831":1480585069061,"1022463794666":1480585069120,"1022463794669":1480585069121,"1022463794668":1480585069120,"1022463794671":1480585069121,"1020878250863":1509788624960,"1023856160999":1491634246537,"1023856160996":1491634246537,"1024294465274":1509788624249,"1022463794651":1480585069120,"1024294465273":1509788624249,"1024294465272":1509788624249,"1024294465279":1509788624249,"1023856160990":1491634246537,"1024294465278":1509788624249,"1024294465277":1509788624249,"1022463794641":1480585069120,"1020294061063":1465470268286,"1024294465266":1509788624249,"1022463794642":1480585069120,"1022463794645":1480585069120,"1022463794647":1480585069120,"1022463794632":1480585069120,"1022463794635":1480585069120,"1022463794634":1480585069120,"1022463794636":1480585069120,"1024294465262":1509788624249,"1022463794639":1480585069120,"1024294465261":1509788624249,"1022463794638":1480585069120,"1022463794625":1480585069120,"1022463794624":1480585069120,"1022463794627":1480585069120,"1022463794629":1480585069120,"1022463794616":1480585069120,"1025791854554":1509788624814,"1025051589625":1509788624435,"1025791854553":1509788624814,"1022463794618":1480585069120,"1025791854559":1509788624814,"1001004810917":1478686417022,"1022463794620":1480585069120,"1022463794623":1480585069120,"1025051589629":1509788624435,"1025791854557":1509788624814,"1025051589628":1509788624435,"1025051589619":1509788624452,"1024538171672":1509788624436,"1025051589620":1509788624440,"1025051589615":1509788624509,"1025791854543":1509788624814,"1025051589614":1509788624509,"1025051589612":1509788624509,"1021669257742":1478686417120,"1025629593213":1509788625166,"1022348188290":1478686417202,"1020175308066":1478686804031,"1025791854578":1509788624814,"1021850925326":1480585069075,"1025791854570":1509788624814,"1025791854572":1509788624814,"1025791854561":1509788624814,"1025791854560":1509788624814,"1022234153974":1509788624932,"1024294465370":1509788625196,"1077482298":1478950494920,"1024294465368":1509788625196,"1024294465375":1509788625196,"1007871982134":1478686804023,"1024294465373":1509788625196,"1001004811111":1478686417022,"1024294465372":1509788625196,"1024294465363":1509788625196,"1025546753213":1509788625007,"1024294465365":1509788625196,"1024294465354":1509788625196,"1024294465353":1509788625196,"1024294465358":1509788625196,"1024294465357":1509788625196,"1017973788672":1509788624372,"1024294465344":1509788625196,"1024294465351":1509788625196,"1021261616161":1478686417101,"1022046086516":1478686417269,"1019876812449":1509788624391,"1025710850789":1509788624308,"1022046086515":1478686417269,"1024294465384":1509788625196,"1024730973539":1509788624467,"1021261616180":1478686417101,"1024294465388":1509788625196,"1024294465379":1509788625196,"1024294465378":1509788625196,"1024294465377":1509788625196,"1024294465383":1509788625196,"1012117402928":1478686417223,"1024294465380":1509788625196,"1021691802174":1509788624299,"1016719600280":1478686804042,"1012142439371":1478686417025,"1021712642431":1478686417122,"1020235864419":1465470268180,"1024294465310":1509788624249,"1024294465299":1509788624249,"1021412082502":1478686417106,"1024294465302":1509788624249,"1012211908387":1478686416977,"1024294465290":1509788624249,"1024294465295":1509788624249,"1022129711130":1478686417013,"1024294465281":1509788624249,"1022746391517":1509788625021,"1024294465286":1509788624249,"1024294465285":1509788624249,"1022746391520":1509788625008,"1022746391522":1509788625017,"1025607965044":1509788624229,"1022746391524":1509788625016,"1024294465342":1509788625196,"1020771563826":1478686417029,"1024294465341":1509788625196,"1024294465340":1509788625196,"1023821165563":1509788624960,"1023297917643":1509788624969,"522538059":1478950494910,"1022746391534":1509788624997,"1022746391537":1509788625017,"1021821565648":1478686417132,"1024294465321":1509788624249,"1024294465320":1509788624249,"1024294465314":1509788624249,"1024294465319":1509788624249,"1024294465317":1509788624249,"1024294465316":1509788624249,"1021813963700":1478686416984,"1022919408084":1509788624393,"1025593547073":1509788624834,"1025593547072":1509788624829,"1022919408095":1509788624393,"1025593547075":1509788624800,"1025593547074":1509788624823,"1024090907625":1495284743424,"1022919408072":1509788624393,"1022630906616":1509788624456,"1024294465529":1509788624888,"1786591705":1444487341748,"1024294465523":1509788624888,"1024294465521":1509788624889,"1024294465520":1509788624889,"1025315957448":1509788624393,"1024294465518":1509788624888,"1022919408108":1509788624393,"1021832313558":1478686417134,"1021769397526":1509788624395,"1021832313557":1478686417134,"1021832313555":1478686417134,"1019283308860":1509788624374,"1021961020069":1478686417262,"1019102565391":1509788624317,"1011251224689":1478686804015,"1024926413141":1509788624182,"1016539250047":1478686804065,"1024926413143":1509788624182,"1024926413147":1509788624182,"1025000862241":1509788624996,"1023572116819":1509788624974,"1021653650313":1509788624534,"1023251409495":1509788625084,"1025509003720":1509788624292,"1022943787165":1509788624291,"1022943787166":1509788624291,"1021346945441":1478686417041,"1023730716607":1509788624970,"1020924782438":1478686417000,"1017128387882":1478686804020,"1001113732023":1478686417024,"1023428337058":1509788624286,"1023428337057":1509788624286,"1025593286315":1509788624929,"1023428337056":1509788624286,"1021558885672":1478686417245,"1023428337055":1509788624286,"1023428337054":1509788624286,"1023428337053":1509788624286,"1018946218344":1478686804043,"1018946218345":1478686804043,"1018946218346":1478686804043,"1018946218347":1478686804043,"1018946218349":1478686804043,"1018946218350":1478686804043,"1018946218351":1478686804043,"1022269542557":1478686417067,"1018946218352":1478686804043,"1022269542554":1478686417014,"1022943787174":1509788624291,"1022746391806":1509788625017,"1012639175063":1478686417026,"1021938345003":1478686417260,"1021797970830":1509788624834,"1021797970831":1509788624801,"1021797970829":1509788624829,"2004951817":1491634246533,"1023981076064":1509788624199,"1021583134591":1509788624429,"1021938344996":1478686417260,"1021352712510":1465470268227,"1021938344998":1478686417260,"1024973336907":1509788624288,"1022397341658":1478686417070,"1024500948341":1509788624436,"1012514155263":1478686417223,"1022027735506":1478686417164,"1021339867357":1478686417041,"1022409136148":1480585069077,"1023032517948":1509788624213,"1024906491256":1509788624342,"1015966062620":1465470268264,"1019455277164":1478686804021,"1209736406":1478950494921,"2004951886":1491634246533,"1020040391453":1509788624335,"1025710851347":1509788624309,"310986336":1444487341738,"1018946218477":1478686804040,"1025295773059":1509788624946,"1023691263294":1509788624937,"1023958138197":1509788667535,"1022304670690":1478686417068,"1019150016484":1465470268272,"1021166852024":1478686417234,"1016826161791":1509788624171,"1022485284112":1478943089488,"1019150016476":1465470268272,"1000526160333":1444487341713,"1024008076905":1509788667551,"1024008076906":1509788667551,"1000526160320":1444487341736,"1023878444590":1509788624385,"1023878444589":1509788624385,"1023878444588":1509788624385,"1024008076902":1509788667551,"1020779167471":1478686417225,"1021999294011":1478686417157,"1025051589642":1509788624467,"1023919338374":1509788624957,"1000987777631":1478686417022,"1025051589640":1509788624456,"1025051589647":1509788624424,"1025051589646":1509788624461,"1019455277471":1478686804021,"1025051589644":1509788624454,"1024008076922":1509788667551,"1022485284107":1478943089488,"1023919338380":1509788624292,"1025051589638":1509788624435,"1023919338378":1509788624957,"1022485284111":1478943089488,"1024008076915":1509788667551,"1022485284110":1478943089488,"1025051589636":1509788624435,"1024008076914":1509788667551,"1020878251193":1509788624945,"1021653650172":1509788624195,"1012069822854":1478686804067,"1721709561":1491634246520,"1021653650126":1509788624818,"1024687456703":1509788624420,"1025533514515":1509788624348,"1024688112063":1509788624503,"1021971376043":1478686417056,"1025810072217":1509788667451,"1022746391809":1509788625017,"1023878444681":1509788624385,"1023878444680":1509788624385,"1000987777791":1478686417022,"1022646636288":1509788624920,"1021496361108":1478686417007,"1021496361111":1478686417007,"1023946470017":1491634246531,"1591806785":1491634246513,"1025533514700":1509788624348,"1021773984569":1509788624815,"423054467":1491634246514,"1021970327418":1478686417010,"1021230027611":1478686417003,"1021797970614":1509788624543,"1021797970615":1509788624524,"1021797970613":1509788624541,"1024008076941":1509788667551,"1024008076943":1509788667552,"1009865029003":1478686804025,"1024008076936":1509788667552,"1024008076939":1509788667551,"1024008076938":1509788667551,"1024008076935":1509788667551,"1024008076930":1509788667551,"1000987777724":1478686417022,"1024008076952":1509788667551,"1024008076955":1509788667552,"1024008076949":1509788667551,"1021366082330":1478686416976,"1024786550533":1509788624512,"1010813307939":1509788624276,"1021797970670":1509788624205,"1021797970671":1509788624186,"1021797970669":1509788624201,"1012228028543":1478686417223,"1022038745922":1478686417058,"1001573672810":1478686417023,"1023032517741":1509788625140,"1021597551900":1478686417115,"1545538073":1478950494925,"1022490134464":1509788625065,"1021848173568":1509788624492,"1021848173569":1509788624492,"1025607965723":1509788624212,"1024723632301":1509788667888,"1009848502601":1491634246513,"1021848173571":1509788624493,"1021848173572":1509788624493,"1022463793513":1480585069120,"1022463793512":1480585069120,"1020311099833":1509788624437,"1022463793505":1480585069120,"1022463793497":1480585069120,"1021895097214":1478686804048,"1022463793499":1480585069120,"1012514154564":1478686417223,"1022463793501":1480585069120,"1025178986404":1509788624550,"1020294060167":1465470268285,"1022463793488":1480585069120,"1022463793491":1480585069120,"1020965937295":1478686417086,"1020965937292":1478686417086,"1022463793494":1480585069120,"1012286088744":1478686417026,"1020311099803":1509788624452,"1009987711277":1491634246533,"1022316728334":1509788624384,"1022463793485":1480585069120,"1020311099806":1509788624586,"1276713519":1478686416992,"1021040258150":1478686417092,"1022463793487":1480585069120,"1022463793486":1480585069120,"1021782634535":1509788624868,"1019455277712":1478686804021,"1022463793473":1480585069120,"1022463793472":1480585069120,"1021615901658":1478686417116,"1022463793476":1480585069120,"1022463793479":1480585069120,"1020954665740":1478686417085,"1022463793467":1480585069120,"1023855899709":1491634246537,"1022463793469":1480585069120,"1022463793468":1480585069120,"1021920524702":1478686417054,"1022463793471":1480585069120,"1022463793470":1480585069120,"1020954665730":1478686417085,"1021974389972":1509788624421,"1021848173659":1509788625014,"1021058870626":1478686417232,"1021848173662":1509788625014,"1021848173663":1509788625014,"1021848173649":1509788625014,"1021848173650":1509788625015,"1021848173651":1509788625015,"1021848173652":1509788625015,"1021848173653":1509788625015,"1021848173654":1509788625015,"1021848173655":1509788625014,"1021643163680":1478686417119,"1019166137732":1478686804020,"1022463793433":1480585069120,"1019166137733":1478686804020,"1022463793435":1480585069120,"1022463793434":1480585069120,"1021848173675":1509788625015,"1022128401681":1478686417184,"1019166137729":1478686804020,"1022463793436":1480585069120,"1024688112288":1509788624503,"1019166137730":1478686804020,"1022463793438":1480585069120,"1022463793425":1480585069119,"1021848173664":1509788625014,"1023432138696":1509788624518,"1022463793427":1480585069119,"1021848173666":1509788625014,"1021058870623":1478686417232,"1023432138698":1509788624516,"1021848173667":1509788625014,"1022463793429":1480585069120,"1023432138701":1509788624517,"1021848173668":1509788625014,"1021175370827":1465470268188,"1002086795139":1478686417024,"1021848173669":1509788625014,"1022463793431":1480585069120,"1023432138702":1509788624518,"1021848173671":1509788625014,"1022463793416":1480585069119,"1022463793419":1480585069119,"1022463793418":1480585069119,"1022463793421":1480585069119,"1010085755730":1491634246512,"1022463793409":1480585069119,"1022463793408":1480585069119,"1022463793411":1480585069119,"1022463793410":1480585069119,"1022463793413":1480585069119,"1022463793412":1480585069119,"1022463793415":1480585069119,"1022463793414":1480585069119,"1023730847091":1509788624970,"1024597416111":1509788624939,"1021797446074":1478686417130,"1024687456836":1509788624818,"1022376893449":1478686804050,"1000116555248":1478686804029,"1020258015847":1465470268311,"1019166137727":1478686804020,"1024998895811":1509788624836,"1022442428441":1478686417016,"1022463793617":1480585069117,"1022463793618":1480585069117,"1022418442914":1478686417015,"1022463793608":1480585069117,"1019356053506":1478686804020,"1022463793615":1480585069117,"1022463793603":1480585069117,"1022463793602":1480585069117,"1022463793605":1480585069117,"1021599124061":1478686417008,"1022463793607":1480585069117,"1022463793606":1480585069117,"1025412819313":1509788624426,"1022463793594":1480585069117,"1025412819312":1509788624431,"1022463793598":1480585069117,"1022463793587":1480585069117,"1022463793588":1480585069117,"1023958138505":1509788667535,"1022463793590":1480585069117,"1022463793568":1480585069120,"1022079250076":1478686417012,"1022463793571":1480585069120,"1022599053715":1509788624462,"1022463793572":1480585069120,"1021685643013":1509788624396,"1012069822980":1478686804067,"1022463793561":1480585069120,"1024998895807":1509788624836,"1025908247275":1509788667464,"1021520609619":1478686417113,"1022463793560":1480585069120,"1024998895806":1509788624836,"1024998895804":1509788624842,"1022463793565":1480585069120,"1024261696715":1509788624298,"1022463793564":1480585069120,"1025908247278":1509788667458,"1024998895801":1509788624835,"1022463793566":1480585069120,"1025589878754":1509788624351,"1022463793553":1480585069120,"1022463793552":1480585069120,"1022463793555":1480585069120,"1022463793557":1480585069120,"1022463793556":1480585069120,"1022463793558":1480585069120,"1022463793545":1480585069120,"1021950535392":1478686417055,"1022463793547":1480585069120,"1022463793549":1480585069120,"1008297809191":1478686804030,"1022463793551":1480585069120,"1022463793550":1480585069120,"1024998895784":1509788624871,"1025908247283":1509788667464,"1024998895780":1509788624871,"1024688112184":1509788624503,"1022463793543":1480585069120,"1022463793542":1480585069120,"1022463793273":1480585069119,"1022909185485":1509788624248,"1022463793275":1480585069119,"1022909185487":1509788624248,"1022463793274":1480585069119,"1022463793277":1480585069119,"1022909185481":1509788624248,"1022463793276":1480585069119,"1022909185480":1509788624248,"1022909185482":1509788624248,"1022909185477":1509788624249,"1022463793264":1480585069119,"1022909185476":1509788624249,"1022463793267":1480585069119,"1022909185479":1509788624248,"1022463793268":1480585069119,"1022463793271":1480585069119,"1022909185475":1509788624248,"1022463793257":1480585069118,"1022909185501":1509788624249,"1022463793256":1480585069118,"1022463793259":1480585069118,"1023861536027":1491634246533,"1022909185503":1509788624249,"1022463793258":1480585069118,"1022463793260":1480585069118,"1022909185496":1509788624248,"1022463793262":1480585069118,"1022909185498":1509788624248,"1022463793249":1480585069118,"1022909185492":1509788624248,"1022463793251":1480585069118,"1022909185495":1509788624248,"1022463793250":1480585069118,"1022909185494":1509788624248,"1023821166474":1509788624960,"1022463793253":1480585069118,"1022447671633":1478686804027,"1022463793255":1480585069118,"1022909185491":1509788624248,"1025713079987":1509788624305,"1005578450641":1509788624392,"1022463793254":1480585069118,"1022909185490":1509788624248,"1024688112614":1509788624503,"1025172301518":1509788624942,"1022909185509":1509788624248,"1024557964207":1509788624437,"1022909185508":1509788624248,"1022909185510":1509788624248,"1022909185505":1509788624249,"1022909185507":1509788624249,"1023032518307":1509788624847,"1025906150169":1509788667457,"1024557964212":1509788624428,"1025906150168":1509788667461,"1025533776200":1509788624347,"1022415559534":1478686417209,"1025906150172":1509788667460,"1012213349199":1478686417025,"4986732035":1509788624157,"1021458220145":1478686417108,"1025533776194":1509788624347,"1025284890643":1509788624328,"1024668452177":1509788625025,"1025533776181":1509788624347,"1009854412706":1478686804064,"1025533776177":1509788624347,"1025533776178":1509788624347,"1024557964232":1509788624434,"1024557964246":1509788624451,"1021363984822":1478686416990,"1003255218454":1478686804060,"1003255218456":1478686804060,"1021498327485":1478686417046,"1023116534256":1509788624282,"1024557964262":1509788624408,"1022105857487":1478686417275,"1021969278359":1478686417262,"1024688112546":1509788624503,"1021881596775":1509788624510,"1024557964268":1509788624508,"1024998895924":1509788624836,"1023325836668":1509788625008,"1021757862428":1509788624395,"1024998895917":1509788624836,"1022463793153":1480585069118,"1022463793152":1480585069118,"1022463793154":1480585069118,"1022463793156":1480585069118,"1022463793158":1480585069118,"1005925786291":1509788624390,"1021942933474":1478686417260,"1021140768723":1478686417037,"1022463793385":1480585069119,"1022463793384":1480585069119,"1024688112470":1509788624503,"1025569431497":1509788624352,"1021646703002":1509788624836,"1025569431496":1509788624351,"1024502390368":1509788625028,"1022463793377":1480585069119,"1022463793376":1480585069119,"1018584465193":1509788624367,"1022463793379":1480585069119,"1025569431494":1509788624352,"1022463793381":1480585069119,"1558514554":1478686804029,"1022463793368":1480585069119,"1022463793371":1480585069119,"1022463793370":1480585069119,"1022463793373":1480585069119,"1022463793372":1480585069119,"1022463793374":1480585069119,"1025295773482":1509788624946,"1022463793361":1480585069119,"1144984470":1478686804022,"1022463793360":1480585069119,"1021605808951":1509788624397,"1022463793363":1480585069119,"1022463793362":1480585069119,"1021775032776":1478686804047,"1022463793365":1480585069119,"1022463793364":1480585069119,"1022463793366":1480585069119,"1021955778066":1478686417146,"1021955778067":1478686417146,"1023859701137":1509788625038,"1022463793359":1480585069119,"1022463793358":1480585069119,"1024783404685":1509788625021,"554530486":1491634246534,"1023929430435":1509788625006,"1024688112390":1509788624503,"1021519167592":1478686417047,"1022463793321":1480585069119,"1022463793320":1480585069119,"1022463793323":1480585069119,"1022463793325":1480585069119,"1019283309884":1509788624374,"1022463793324":1480585069119,"1021386135661":1478686417300,"1022463793316":1480585069119,"865690694":1478950494918,"1022463793318":1480585069119,"1022463793305":1480585069119,"1022463793304":1480585069119,"1022463793307":1480585069119,"1022463793306":1480585069119,"1025540592118":1509788624311,"1022463793309":1480585069119,"1022463793308":1480585069119,"1022463793311":1480585069119,"1022463793296":1480585069119,"1015324029185":1465470268246,"1022463793299":1480585069119,"1022376893804":1478686804050,"1022463793301":1480585069119,"1022463793300":1480585069119,"1022463793302":1480585069119,"1022463793290":1480585069119,"1022463793293":1480585069119,"1010142636507":1444487341757,"1006580204607":1478686804025,"1021828772168":1478686417133,"1024274670452":1509788624957,"1006954687449":1478686804054,"1022370468545":1478686417290,"1019596455025":1509788624959,"1020882053527":1478686417079,"1021144307754":1478686417096,"1021315486705":1465470268209,"1023561763289":1509788624812,"1021691935047":1509788624311,"1021643163138":1478686417119,"1025512283623":1509788624392,"1025512283622":1509788624392,"116088482":1444487341753,"1025512283625":1509788624392,"1025512283624":1509788624392,"1025512283626":1509788624392,"289098094":1444487341734,"1021438167803":1509788624817,"1021201063128":1509788624977,"1021873075428":1478686804032,"1023859571279":1509788625038,"1021873075429":1478686804032,"1021201063124":1509788624977,"1006868182686":1509788624386,"1021460581205":1478686417045,"1024619563139":1509788624299,"1019246876493":1509788624312,"1019857939666":1509788625017,"1024007811851":1509788667829,"1022463793144":1480585069118,"1022463793149":1480585069118,"1022463793148":1480585069118,"1022463793151":1480585069118,"1022463793150":1480585069118,"1022463793139":1480585069118,"1022463793142":1480585069118,"1022463793129":1480585069118,"1022463793130":1480585069118,"1022463793133":1480585069118,"1022463793135":1480585069118,"1022463793120":1480585069118,"1023354543320":1509788624195,"1022463793123":1480585069118,"1022463793122":1480585069118,"1022463793127":1480585069118,"1022463793126":1480585069118,"1023821297869":1491634246535,"1022463793096":1480585069118,"1015478171497":1480585069075,"1022463793098":1480585069118,"307841773":1444487341750,"1022463793089":1480585069118,"1022849810127":1509788625074,"1022463793091":1480585069118,"1022463793090":1480585069118,"1022463793092":1480585069118,"1006890202881":1478686804025,"1022463793080":1480585069118,"1023032518994":1509788624550,"1022463793082":1480585069118,"1022463793084":1480585069118,"1022463793087":1480585069118,"1023354543239":1509788624420,"1022463793073":1480585069118,"1021685905693":1478686417121,"1021188086697":1478686417235,"1022463793072":1480585069118,"1022463793075":1480585069118,"1022463793077":1480585069118,"1022463793076":1480585069118,"964518323":1509788625019,"1022463793078":1480585069118,"1022987302644":1509788625049,"1022463793067":1480585069118,"1022463793068":1480585069118,"1022463793070":1480585069118,"4935614198":1509788624157,"1022463793058":1480585069118,"1021530181569":1478686417244,"1022463793063":1480585069118,"1022966068612":1509788624419,"1020796728366":1478686417029,"1022438496252":1478686417213,"1022447409012":1478686417215,"1021729290794":1478686417124,"1025508613357":1509788624340,"4899962140":1509788624161,"1021318369948":1465470268209,"1022966068297":1509788624816,"1021318369951":1465470268209,"1021954992269":1478686417261,"1021729290758":1478686417123,"974873406":1444487341739,"1021729290766":1478686417123,"1020820583527":1478686417030,"1021729290778":1478686417123,"1025731955637":1509788624922,"1021729290776":1478686417123,"1004390941577":1478686804029,"1023596366517":1509788624519,"1022966068267":1509788625101,"1021882250563":1478686416975,"1021882250565":1478686416975,"1023354543371":1509788624818,"1023596366523":1509788624519,"1545536850":1478950494925,"2004954830":1491634246533,"1023596366497":1509788624519,"1023596366496":1509788624519,"1023596366511":1509788624519,"1021354284228":1465470268229,"1021354284229":1465470268229,"1021354284230":1465470268229,"1021386135273":1478686417300,"1023596366487":1509788624519,"1023596366486":1509788624519,"1021881595242":1509788624434,"1021387970303":1478686417006,"1022488955028":1478943089315,"1007979063720":1478686804023,"1023251408668":1509788625083,"1020786373129":1478686416997,"1023218771435":1509788625072,"1021617472606":1478686417117,"1020867635460":1478686417031,"1022364963070":1509788624958,"1022381085677":1478686417290,"1024267199063":1509788625016,"1021318631939":1478686417041,"1019356188431":1509788624321,"1020665527624":1478686417028,"1021981731835":1478686417151,"1021470805336":1478686417109,"1022486858186":1478943089532,"1025803128732":1509788667814,"1025803128728":1509788667814,"1021981731823":1478686417151,"1020750458949":1478686416996,"1022293793917":1478686417199,"1023530702374":1509788625082,"1022966068355":1509788624533,"2004954734":1491634246533,"1022293793899":1478686417199,"1007458175037":1444487341699,"1022966068369":1509788624194,"1022293793888":1478686417199,"1021902959812":1478686417139,"1022301527814":1478686417015,"1021902959809":1478686417139,"1016399002864":1480585069069,"1021887363024":1478686804065,"1001573673119":1478686417023,"1023845022472":1491634246537,"1024961281678":1509788624932,"1020831724726":1478686416998,"1025610584540":1509788624520,"1019524758169":1509788625077,"1021733748449":1478686417124,"1025629197965":1509788624846,"1025629197967":1509788624846,"1025629197960":1509788624846,"1022035340486":1478686417058,"1020389476663":1465470268321,"1025610584544":1509788624521,"1010013533118":1491634246526,"1000308981195":1478686417018,"1025610584569":1509788624521,"1016862841701":1478686804016,"1022238611708":1509788624932,"1025610584564":1509788624521,"1025629197970":1509788624846,"1022238611706":1509788624947,"1020909054029":1478686417032,"1021320073685":1509788624171,"1010013533120":1491634246530,"1022769593186":1509788624439,"1023209727676":1509788625042,"1018265161690":1509788624286,"1019590164166":1509788624309,"1025515167742":1509788624371,"1005577796484":1509788624392,"1023958135345":1509788667535,"4824319240":1509788624161,"1021895882719":1478686417139,"4899962526":1509788624157,"1008244202096":1478686804030,"1025847165753":1509788667888,"1020815734561":1478686417077,"1019283310705":1509788624375,"1019835394204":1509788625077,"1025629591096":1509788624866,"1002314335451":1478686416993,"1022050282672":1478686417172,"1022398910950":1478686417207,"507200640":1444487341744,"1001573672999":1478686417023,"1021713692879":1509788624400,"1022769593326":1509788624439,"1025515167563":1509788624371,"1025500618404":1509788625004,"1025515167565":1509788624371,"1025515167564":1509788624371,"1025515167567":1509788624371,"1025515167566":1509788624371,"1021729290750":1478686417123,"1001644715176":1444487341702,"1020389214701":1465470268317,"2004954478":1491634246533,"1021354284905":1465470268229,"1001573673065":1478686417023,"1022090519369":1478686417180,"1020796728876":1478686417029,"1024672778580":1509788625069,"1021354284903":1465470268229,"1023958135629":1509788667535,"1024056440190":1509788624289,"1015273568497":1478686804067,"1008100043910":1478686804030,"1021797448722":1478686417130,"1025791856186":1509788624419,"1025791856190":1509788624418,"1025791856189":1509788624418,"1025791856188":1509788624418,"1022197605501":1478686417189,"1021881595687":1509788624433,"1025791856183":1509788624419,"1025791856180":1509788624419,"2004954288":1491634246533,"1025791856175":1509788624418,"1025791856172":1509788624418,"1025791856163":1509788624418,"1025791856167":1509788624418,"1022961612518":1509788624435,"1021867308969":1509788624394,"1022578871763":1509788625062,"1021654041841":1509788624396,"1022790039733":1509788624200,"1022984680728":1509788625050,"1025791856204":1509788624419,"1024780648985":1509788624472,"1025791856194":1509788624418,"1025791856192":1509788624419,"1025791856198":1509788624418,"1024215688075":1509788625033,"1021831918202":1478686417053,"1024087501773":1509788624523,"1021744103203":1478686417253,"1025791856281":1509788624193,"1025791856286":1509788624193,"1025791856285":1509788624193,"1025791856284":1509788624193,"1025791856275":1509788624193,"1025791856274":1509788624193,"1022790039662":1509788624198,"1025791856278":1509788624193,"1025791856276":1509788624193,"1025791856267":1509788624193,"1020995429225":1478686417001,"1022438495597":1478686417213,"1025791856269":1509788624193,"1024967442345":1509788625023,"1025791856268":1509788624193,"1025791856256":1509788624193,"1025791856263":1509788624193,"1022085538425":1478686417179,"1025791856260":1509788624193,"1025791856315":1509788624814,"1025791856319":1509788624814,"1025050931843":1509788624568,"1021961153276":1478686417148,"1025609535564":1509788625007,"1025609535552":1509788624999,"1020973280745":1478686417034,"1025791856288":1509788624193,"1025609535554":1509788624998,"1025609535557":1509788624998,"1022194984126":1478686417189,"1022238611718":1509788624931,"1022238611713":1509788624930,"1025609535549":1509788625084,"1025609535548":1509788624998,"1009433927134":1478686804055,"1022238611715":1509788624931,"1025609535539":1509788625003,"1025609535540":1509788625003,"1025791856331":1509788624814,"1025609535531":1509788625002,"1025791856321":1509788624814,"1018052957081":1465470268320,"1025791856324":1509788624814,"1025609535510":1509788624999,"1025609535499":1509788624999,"1012754913273":1478686804024,"1021828772520":1478686417256,"1021340522423":1465470268223,"1022776146209":1509788625056,"307842635":1444487341755,"1021185859485":1478686417098,"1024215819471":1509788624857,"1024215819469":1509788624857,"1024215819468":1509788624857,"1022477946024":1478943089315,"1022005192835":1478686417158,"1022002571461":1478686417266,"1024374857125":1509788625084,"1024677891927":1509788625070,"1024215819473":1509788624857,"1024215819472":1509788624857,"1024273622949":1509788624176,"1024273622950":1509788624176,"1025068758644":1509788624606,"1025591973547":1509788624335,"1019788209317":1478686804053,"1019788209318":1478686804053,"1019788209319":1478686804053,"1019788209320":1478686804053,"1021940444369":1478686417260,"1019788209321":1478686804053,"1019788209322":1478686804053,"1019788209323":1478686804053,"1019788209324":1478686804053,"1019788209325":1478686804053,"1019788209326":1478686804053,"1023902169571":1509788625037,"1022381086247":1478686417290,"1001309961788":1444487341753,"1021494135121":1509788624515,"1009848894268":1491634246514,"1021937036454":1509788624466,"1009987713888":1491634246520,"1023821823001":1491634246536,"1025040446906":1509788624185,"1025486069546":1509788624436,"1022023280958":1478686417163,"1022493412668":1478943089490,"1022493412671":1478943089490,"1022493412667":1478943089490,"1023999424353":1509788625017,"1000975717045":1478686417021,"1021643162321":1478686417119,"1023999424352":1509788625017,"1023999424355":1509788625017,"1022475455495":1478943089253,"1024215819339":1509788624219,"1024215819336":1509788624219,"1024215819341":1509788624219,"1024215819340":1509788624219,"1025331553987":1509788625171,"1025593546337":1509788624540,"1025331553991":1509788625172,"1025331553990":1509788625172,"1025331553988":1509788625172,"1025792379296":1509788624974,"1024215819344":1509788624219,"1020612443502":1478686417027,"1021514058455":1478686417112,"1021514058462":1478686417112,"1021514058460":1478686417112,"1408307003":1478686804024,"1022577298041":1509788667889,"1021514058457":1478686417112,"1022020004140":1478686417161,"1022364964283":1509788624958,"1021386134353":1478686417300,"1021847385796":1509788624402,"1024261695191":1509788624298,"1022283045061":1478686417014,"1021658366854":1478686417050,"1022216854835":1478686417064,"1016115611861":1509788625082,"1021341438284":1478686417005,"1018041554430":1478686804043,"1018041554431":1478686804043,"1021402647983":1478686417106,"1025656197164":1508010983420,"1025508612316":1509788624340,"957703223":1444487341754,"1025508612319":1509788624339,"1021483256058":1478686417045,"1000975717148":1478686417021,"1019165873878":1478686804026,"1002290217201":1478686416993,"1022029179005":1509788624434,"1025771800943":1509788624408,"1025771800936":1509788624408,"1025771800939":1509788624408,"1025771800933":1509788624408,"1008545664935":1478686804061,"1019724640754":1509788625077,"1025771800957":1509788624408,"1025771800956":1509788624408,"1020919803444":1478686417228,"1022769593449":1509788624439,"670005937":1478950494913,"1025771800947":1509788624408,"1007458176164":1444487341701,"1022932514317":1509788624585,"1025331554063":1509788624871,"1025331554061":1509788624871,"1025050932301":1509788624457,"1022241103827":1478686417283,"1021341438255":1478686417005,"1025331554072":1509788624871,"1022769593417":1509788624439,"1025331554067":1509788624871,"1022465364538":1478686416988,"1025449499679":1509788624337,"1023820512740":1491634246535,"1021828773072":1478686417133,"1023220605404":1509788624585,"1022941950333":1509788624935,"1023220605400":1509788624585,"1008907696888":1465470268235,"1023220605397":1509788624586,"1025297737188":1509788624546,"1025297737187":1509788624546,"1021858002457":1478686417009,"1023220605394":1509788624586,"1023220605391":1509788624585,"1021602136387":1478686417008,"1021847386019":1509788624402,"1025507956862":1509788624343,"1011857082903":1478686804024,"1021016794138":1478686417090,"1025297737167":1509788624553,"1023220605437":1509788624585,"1024936378297":1509788625006,"1025297737166":1509788624539,"1024434362438":1509788624462,"1023220605438":1509788624585,"1021604364564":1478686417115,"1025297737163":1509788624565,"1025297737160":1509788624612,"1023220605429":1509788624585,"1025297737159":1509788624613,"1023220605431":1509788624585,"1022420799554":1478686417016,"1025771800961":1509788624408,"1023220605424":1509788624585,"1017171380577":1478686804019,"1023220605426":1509788624585,"1025297737183":1509788624546,"1023220605421":1509788624585,"1022769593485":1509788624439,"1025297737179":1509788624546,"1023220605419":1509788624585,"1023220605418":1509788624585,"1025458413379":1509788624351,"1025458413378":1509788624350,"1023220605412":1509788624585,"1025458413377":1509788624350,"1023220605415":1509788624585,"1025458413376":1509788624352,"1023220605414":1509788624585,"1023220605408":1509788624585,"1026187047120":1514456869767,"1023220605411":1509788624585,"1022562879569":1509788625063,"1007540620082":1509788624375,"1025331554223":1509788624467,"1022106249060":1478686417182,"1025331554235":1509788624467,"1020962138926":1478686417085,"1023855116221":1491634246537,"1025331554236":1509788624467,"1023995492310":1491634246532,"1022296807569":1478686417287,"1025331554229":1509788624467,"1001384016416":1480585069061,"1021507767194":1509788624405,"1022018824210":1478686417266,"1023325839335":1509788625008,"1025665634434":1509788624511,"1025665634437":1509788624509,"1709128664":1444487341729,"1021409988128":1478686417006,"1016444352045":1478686804025,"1025629590184":1509788624455,"1025665634449":1509788624435,"1024632933916":1509788624567,"1017506674407":1478686804047,"1017506674406":1478686804047,"1025665634452":1509788624435,"1021781850122":1478686417300,"1025525127415":1509788624523,"1017506674411":1478686804047,"1025525127417":1509788624523,"1025665634456":1509788624435,"1025665634459":1509788624435,"1025525127418":1509788624523,"1025665634460":1509788624435,"1025525127420":1509788624523,"1017506674412":1478686804047,"1023902170000":1509788625037,"1021881594431":1509788624426,"1022608492264":1509788624994,"1022234681154":1478686417065,"1019596454410":1509788624942,"1022376891596":1478686804065,"1026232135312":1514456869770,"1023309061977":1509788624368,"1023171585913":1509788624589,"1007458176916":1444487341699,"1023171585917":1509788624589,"1025902740002":1509788667458,"1020932909796":1478686417083,"1023171585911":1509788624589,"1025902740001":1509788667460,"1020932909797":1478686417083,"4985419641":1509788624160,"1024375643909":1509788624478,"1024375643908":1509788624478,"1025902739998":1509788667463,"1024375643911":1509788624478,"670005644":1478950494913,"1024375643910":1509788624478,"1024375643905":1509788624479,"1024375643904":1509788624478,"1024375643907":1509788624478,"1024670944673":1509788667503,"1024375643912":1509788624478,"1020932909771":1478686417083,"1020241106304":1478686804065,"1024921697422":1509788624279,"1022232846149":1478686417193,"1022232846148":1478686417193,"1022238874693":1509788624947,"1023171585954":1509788624589,"1024327360714":1509788625086,"1020932516396":1478686417228,"1019930289899":1509788624373,"1025594463307":1509788624507,"1025792379785":1509788625005,"1023171585970":1509788624589,"1023171585974":1509788624589,"4935612552":1509788624161,"1025050933123":1509788624232,"1023171585923":1509788624589,"1023171585922":1509788624589,"1023171585926":1509788624589,"1023171585947":1509788624589,"1023171585949":1509788624589,"1023171585951":1509788624589,"1022396028372":1478686417070,"1021643161848":1478686417119,"1023171585939":1509788624589,"1017171380851":1478686804019,"1016758396374":1478686804023,"1023171585942":1509788624589,"1025407050026":1509788625132,"1025407050024":1509788625132,"1025407050029":1509788625132,"1022343861843":1478686417289,"1022343861842":1478686417289,"1025524996149":1509788624523,"1077616354":1444487341731,"1012109408347":1478686804051,"1021513795780":1478686417047,"1019523841623":1509788624315,"1023171585992":1509788624589,"1019523841621":1509788624317,"1023171585994":1509788624589,"1023171585999":1509788624589,"1022470737414":1478686417219,"1023171585987":1509788624589,"1018041554432":1478686804043,"1024602525971":1509788624389,"1019283311620":1509788624390,"1018041554433":1478686804043,"1024602525970":1509788624389,"1018041554434":1478686804043,"1024602525969":1509788624389,"1025407050010":1509788625165,"1025407050009":1509788625165,"1021753146145":1478686417126,"1025407050002":1509788625246,"1000975716570":1478686417021,"1025407050005":1509788625244,"1023150876512":1509788624977,"1024210839647":1509788625033,"1021881594625":1509788624427,"1003686588313":1478686804060,"1003686588315":1478686804060,"1003686588316":1478686804060,"1003686588317":1478686804060,"1023835061931":1491634246536,"1003686588319":1478686804060,"1024783402539":1509788625020,"1024879476828":1509788624478,"1023150876493":1509788624978,"1003686588323":1478686804060,"1003686588324":1478686804060,"1022122370193":1478686417013,"1021146537661":1478686417234,"1020955191808":1478686417033,"1025034024820":1509788625023,"1023150876477":1509788624977,"1022066927705":1478686417175,"1022066927708":1478686417175,"1019283312011":1509788624390,"1010013533949":1491634246521,"1010013533950":1491634246521,"1020294058437":1465470268285,"1010013533945":1491634246526,"1010013533946":1491634246521,"1023354542899":1509788624534,"1024879476739":1509788624478,"1024375643877":1509788624478,"1023150876645":1509788624977,"1024375643879":1509788624478,"1024375643878":1509788624478,"1024375643873":1509788624479,"1023150876641":1509788624978,"1024375643872":1509788624478,"1024375643875":1509788624479,"1018690236865":1509788624378,"1000526162789":1444487341750,"1022395897064":1478686417070,"1024375643883":1509788624478,"1024375643882":1509788624478,"1025297737727":1509788625244,"1022628677140":1509788624842,"1025297737726":1509788625246,"1022001392504":1478686417157,"1024375643894":1509788624478,"1024375643889":1509788624478,"1000975716785":1478686417021,"1024375643891":1509788624478,"1024375643901":1509788624478,"1024375643900":1509788624478,"1021727325376":1478686417251,"1024375643897":1509788624478,"1021885526636":1478686417044,"1024375643899":1509788624478,"1023150876667":1509788624977,"1021955255816":1509788624466,"1023150876614":1509788624977,"1024602525786":1509788624392,"1019817832103":1509788625019,"169301432":1478686417019,"1022250802619":1478686417014,"1022435087039":1478686417213,"1024215820123":1509788625153,"1024215820122":1509788625153,"1023150876631":1509788624978,"1024215820121":1509788625153,"1024215820125":1509788625153,"1022250802620":1478686417014,"1023150876626":1509788624978,"1024215820119":1509788625153,"1002454071743":1491634246519,"1023150876635":1509788624978,"1024579064452":1509788624932,"1016808464815":1509788625018,"1022082263031":1478686417272,"1025507957295":1509788624297,"1021773723987":1478686417009,"1020822811366":1478686417031,"1025507957301":1509788624297,"1025507957298":1509788624297,"1023150876592":1509788624978,"1020822811379":1478686417031,"1025507957310":1509788624297,"1020822811376":1478686417031,"116087094":1444487341733,"1018041554737":1478686804058,"1022082263017":1509788624943,"1018041554738":1478686804058,"1018041554739":1478686804058,"1025507957304":1509788624297,"1025525127424":1509788624523,"1019739583028":1509788624173,"1021828773537":1478686417133,"1022388163594":1478686417290,"1016719599146":1478686804063,"1025508612622":1509788624344,"1019739583021":1509788624173,"1021543417775":1478686417047,"1022254472202":1478686417196,"1023354543036":1509788625100,"1021039991381":1478686417035,"1022645598850":1480585069133,"1022645598849":1480585069133,"1022645598856":1480585069133,"1021841476253":1478686417257,"1022645598869":1480585069133,"1022645598873":1480585069133,"1024302063069":1509788624521,"1012136265969":1478686417073,"1022645598876":1480585069133,"1022207025286":1478686417280,"1022646909518":1480585069080,"1022646909516":1480585069080,"1022646909514":1480585069080,"1022464716652":1478686417298,"1022646909511":1480585069080,"1150756030":1478950494920,"1022646909510":1480585069080,"1024752482497":1509788667502,"1024985384226":1509788625069,"1021980807700":1478686416983,"1022646909526":1480585069080,"1022646909522":1480585069080,"1022645598910":1480585069094,"1024145560325":1509788624453,"1022646909520":1480585069080,"1022645598913":1480585069094,"1022645598918":1480585069094,"1022645598922":1480585069094,"1022646909478":1480585069141,"1022645598927":1480585069094,"1022646909475":1480585069141,"1022646909473":1480585069141,"1022775739023":1509788624538,"1016301601011":1480585069065,"1022645598935":1480585069094,"1022390397836":1478686417291,"1022645598933":1480585069094,"349926531":1444487341728,"1009230518881":1478686804030,"1022645598936":1480585069094,"1022646909455":1480585069141,"1022645598946":1480585069094,"1022645598944":1480585069094,"1022646909451":1480585069141,"1022645598950":1480585069094,"1022646909450":1480585069141,"1022646909448":1480585069141,"1022645598954":1480585069094,"1022646909445":1480585069141,"1021998764894":1478686417157,"1022645598959":1480585069094,"1022645598958":1480585069094,"1022646909442":1480585069141,"1025261164240":1509788624279,"1025214632718":1509788624437,"1022645598957":1480585069094,"1022041233125":1478686417268,"1022646909471":1480585069141,"1022645598961":1480585069094,"1022645598960":1480585069094,"1022646909464":1480585069141,"1020243602389":1465470268321,"1024327360063":1509788625086,"1022646909459":1480585069141,"1007253316718":1478686804057,"1025507960164":1509788624339,"1025593682511":1509788624204,"1021993391085":1478686417265,"1021986706265":1478686417057,"1021986706271":1478686417057,"1021770303034":1478686417127,"1022645598747":1480585069132,"1025593682514":1509788624200,"1021387058974":1478686417006,"1025593682512":1509788624198,"1022645598750":1480585069132,"1025593682518":1509788624186,"1021986706260":1478686417057,"1021770303026":1478686417127,"1022645598748":1480585069132,"1022645598755":1480585069132,"1022645598754":1480585069132,"1022645598752":1480585069132,"1020812316014":1478686417225,"1022645598758":1480585069132,"1022645598756":1480585069132,"1022802215818":1509788624819,"1022645598763":1480585069133,"1022645598762":1480585069132,"1022645598760":1480585069132,"1022645598766":1480585069133,"1022645598765":1480585069133,"1022645598764":1480585069133,"1022645598771":1480585069133,"1022645598770":1480585069133,"1022645598768":1480585069133,"1021616176457":1478686417116,"1022645598773":1480585069133,"1025515824594":1509788624336,"1025261164154":1509788624279,"1021021641090":1478686417090,"1019596440732":1509788624930,"1022645598817":1480585069133,"1022272562235":1478686417285,"1022645598822":1480585069133,"1020638249677":1478686416987,"1022645598827":1480585069133,"1017128399251":1478686804016,"1024936362741":1509788625006,"1294282187":1444487341755,"1022645598829":1480585069133,"1012406016029":1478686417074,"1022645598833":1480585069133,"1024597552863":1509788624939,"1022645598838":1480585069133,"1022645598836":1480585069133,"1018516816960":1478686804066,"1022645598843":1480585069133,"1025261164101":1509788624280,"1022645598842":1480585069133,"1294282206":1444487341749,"1022645598847":1480585069133,"1022645598845":1480585069133,"1022645598844":1480585069133,"1022100215816":1478686417275,"1021905964970":1509788624858,"1021905964971":1509788624859,"1022058403476":1478686417060,"1021905964975":1509788624859,"1021905964972":1509788624859,"1022216331566":1478686417281,"307852097":1444487341751,"1021214696686":1478686417038,"1022879680938":1509788625017,"1022473761254":1478943089253,"1022091040923":1478686417273,"1025540597562":1509788624302,"1022072297883":1509788624453,"1026225049105":1514456869774,"1020294197225":1465470268296,"1020556868692":1478686417017,"1022479397173":1478943089531,"1016284053170":1480585069064,"1217079779":1478950494921,"1003721577460":1478686804060,"1003721577458":1478686804060,"1003721577459":1478686804060,"1022802215488":1509788625102,"1003721577456":1478686804060,"1003721577457":1478686804060,"1003721577454":1478686804060,"1003721577455":1478686804060,"1022315947866":1478686417287,"1003721577453":1478686804060,"1025593682879":1509788624524,"1003721577451":1478686804060,"1025593682878":1509788624542,"1003721577448":1478686804060,"1025593682877":1509788624537,"1022315947870":1478686417288,"1003721577449":1478686804060,"1025593682876":1509788624540,"1021603331545":1478686416980,"1003721577447":1478686804060,"1021603331546":1478686416980,"1003721577444":1478686804060,"1022450298716":1478686417302,"1003721577445":1478686804060,"1021603331551":1478686416980,"1003721577441":1478686804060,"1018405289152":1478686804026,"1018908465871":1509788624930,"1021264898395":1478686417237,"1025832237333":1509788667452,"1023995612064":1491634246532,"1007871969436":1478686804023,"1021975696164":1509788624464,"1021712368615":1478686417122,"1022056306288":1478686417173,"1022775739152":1509788624538,"4997859378":1509788667398,"1022566167688":1509788625002,"1021344591341":1478686804040,"1022416088499":1478686804071,"1021959966848":1509788624898,"1022416088498":1478686804071,"1135551048":1444487341739,"1021370019695":1478686804040,"1025796323131":1509788624274,"1021721281097":1478686804050,"1021344591344":1478686804040,"1021344591345":1478686804040,"1021344591346":1478686804040,"1025714663498":1509788624342,"1021886435270":1478686417137,"1022646909032":1480585069140,"1022646909031":1480585069140,"1021550508998":1478686416982,"1009990585053":1491634246515,"1022072298171":1509788624453,"1021692183406":1509788625003,"1022646909001":1480585069140,"1022646909023":1480585069140,"1022646909015":1480585069140,"1022646909010":1480585069140,"1875709427":1444487341754,"1022646908971":1480585069140,"1024887997118":1509788624423,"1022646908969":1480585069140,"1008818815204":1509788624372,"1022646908967":1480585069140,"1022646908964":1480585069140,"1022646908963":1480585069140,"1021831121729":1478686417256,"1022646908960":1480585069140,"1025607444566":1509788624866,"761614133":1444487341740,"1022646908991":1480585069140,"1023164373987":1509788624373,"1023164373986":1509788624373,"1023164373985":1509788624373,"1023164373984":1509788624373,"4997860285":1509788667398,"1022646908980":1480585069140,"1024879230209":1509788624564,"1024879230208":1509788624564,"1024879230210":1509788624564,"1022196030757":1478686417189,"1009849957689":1478686804067,"1023856017423":1491634246537,"1010024532148":1491634246527,"1010024532146":1491634246521,"1022646909166":1480585069140,"1022072298030":1509788624190,"1022646909161":1480585069140,"1022072298026":1509788624190,"936990032":1478950494919,"1022072298016":1509788624190,"1022072298044":1509788624190,"1022646909181":1480585069141,"1022072298047":1509788624190,"1022646909178":1480585069140,"1022072298042":1509788624190,"1022072298043":1509788624190,"1022646909175":1480585069140,"1022072298037":1509788624190,"1022072298038":1509788624190,"1022072298039":1509788624190,"1022072298032":1509788624190,"1022072298034":1509788624190,"1008808330204":1444487341757,"1022466813321":1478686417218,"1022442564629":1478686417016,"1022072298015":1509788624190,"1021843310784":1478686417257,"1022646909103":1480585069140,"1108287694":1444487341725,"1022646909102":1480585069140,"1022646909101":1480585069140,"1008629560620":1478686804030,"1022646909095":1480585069140,"1022646909091":1480585069140,"1022646909089":1480585069140,"1025593288766":1509788624929,"1021947908843":1478686417260,"1025607968964":1509788624550,"1022646909111":1480585069140,"1012136266295":1478686417073,"1025607968968":1509788624550,"1022646909108":1480585069140,"1012754919122":1478686804024,"1025607968973":1509788624550,"1022646909106":1480585069140,"1022072298057":1509788624190,"1021002504823":1478686417089,"1022072298059":1509788624190,"1024597683398":1509788624938,"1022646909087":1480585069140,"1022646909086":1480585069140,"1022646909084":1480585069140,"1021721280844":1478686804050,"1022646909082":1480585069140,"1207772427":1444487341742,"1022646909079":1480585069140,"1025784002409":1509788624351,"1023095821999":1509788624995,"1016930215467":1478686804016,"1022646909291":1480585069141,"1023095821992":1509788624995,"1022646909289":1480585069141,"1022646909287":1480585069141,"1025428399023":1509788624423,"1022645598607":1480585069132,"1010812402424":1509788624299,"1025428399019":1509788624423,"1022645598610":1480585069132,"1022646909310":1480585069141,"1022645598608":1480585069132,"1023095822009":1509788624995,"1022645598614":1480585069132,"1020596831156":1478686804031,"1022645598613":1480585069132,"1022645598612":1480585069132,"1022645598619":1480585069132,"1022646909303":1480585069141,"1022645598617":1480585069132,"1022645598616":1480585069132,"1022646909300":1480585069141,"1022645598622":1480585069132,"1023095822002":1509788624995,"1025428398980":1509788624423,"1023095821966":1509788624995,"1022645598631":1480585069132,"1023095821960":1509788624995,"1025428398978":1509788624423,"1022645598635":1480585069132,"1022645598634":1480585069132,"1022645598633":1480585069132,"1006962544740":1478686804025,"4997860047":1509788667398,"1022645598637":1480585069132,"1022453574971":1509788624937,"1022645598636":1480585069132,"1022409273224":1480585069097,"1022409273227":1480585069097,"1022645598641":1480585069132,"1007384522514":1478686804025,"1022645598647":1480585069132,"1021922872460":1478686417010,"1021922872462":1478686417010,"1022409273219":1480585069097,"1022409273221":1480585069097,"1022409273220":1480585069097,"1025474011344":1509788624945,"1022409273222":1480585069097,"1024597683478":1509788624938,"1023670563880":1509788624199,"1025428399075":1509788624423,"1025428399074":1509788624423,"1021983035722":1478686417152,"1022097857121":1478686417181,"1022646909219":1480585069141,"120677503":1444487341760,"1022646909217":1480585069141,"1020556869200":1478686417017,"1021595334763":1509788624397,"1025713484528":1509788624305,"1020092311":1444487341735,"1022453574985":1509788624937,"1022645598685":1480585069132,"1022453574987":1509788624937,"1022645598684":1480585069132,"1022645598691":1480585069132,"1025042926303":1509788624498,"1021849078142":1509788625015,"1022645598689":1480585069132,"1022646909197":1480585069141,"1025428399047":1509788624423,"1025428399046":1509788624423,"1023095822030":1509788624995,"1022645598694":1480585069132,"1022645598693":1480585069132,"1022646909193":1480585069141,"1023095822027":1509788624995,"1022645598692":1480585069132,"1022645598699":1480585069132,"1024156571643":1509788667500,"1022645598698":1480585069132,"1022646909190":1480585069141,"1599683635":1444487341737,"1022645598696":1480585069132,"1024879229962":1509788624863,"1022645598703":1480585069132,"1023095822017":1509788624995,"1022646909186":1480585069141,"1022645598707":1480585069132,"1024879229969":1509788624863,"1022645598706":1480585069132,"1022645598705":1480585069132,"1024879229971":1509788624863,"1024879229970":1509788624863,"1024879229973":1509788624863,"1022097857119":1478686417181,"1022645598710":1480585069132,"1022646909210":1480585069141,"1022645598709":1480585069132,"1022645598708":1480585069132,"1022645598712":1480585069132,"1022646909204":1480585069141,"1025261163971":1509788624280,"974870884":1444487341738,"1022646909200":1480585069141,"1022030485156":1478686417165,"1022646909433":1480585069141,"1020391585641":1478686804071,"1022646909431":1480585069141,"738545566":1478686417020,"1021976089075":1478686417056,"1019241770234":1509788624301,"1024879230207":1509788624564,"1024879230206":1509788624564,"1022646909391":1480585069141,"1022646909388":1480585069141,"1022646909387":1480585069141,"1022646909386":1480585069141,"1022646909385":1480585069141,"1024597683598":1509788624938,"4971908080":1509788624162,"1022646909379":1480585069141,"1022646909377":1480585069141,"1022646909406":1480585069141,"1025529062676":1509788624340,"1022646909402":1480585069141,"1022646909400":1480585069141,"1022646909396":1480585069141,"1022646909394":1480585069141,"1022459603975":1478686417072,"1022646909392":1480585069141,"1025275581441":1509788624331,"1025275581440":1509788624331,"1025275581443":1509788624331,"1023095821935":1509788624995,"1025275581442":1509788624331,"1020172821536":1509788624320,"1025275581445":1509788624331,"1025428398945":1509788624423,"1020172821537":1509788624320,"1025275581444":1509788624331,"1025275581447":1509788624331,"1023095821931":1509788624995,"1025275581446":1509788624331,"1025428398946":1509788624423,"1022645598538":1480585069132,"1025275581448":1509788624331,"1012136266532":1478686417073,"1022645598537":1480585069132,"1016514334660":1478686804053,"1025607444936":1509788624846,"1022645598545":1480585069132,"1022646909373":1480585069141,"1022645598544":1480585069132,"309686694":1491634246534,"1016514334657":1478686804053,"1025607444941":1509788624845,"1016514334659":1478686804053,"1022645598549":1480585069132,"1022352911298":1478686417069,"1016514334658":1478686804053,"1025275581465":1509788624331,"1022645598554":1480585069132,"1023095821940":1509788624995,"1025275581467":1509788624331,"1022645598552":1480585069132,"1025275581466":1509788624331,"1022645598559":1480585069132,"1025275581469":1509788624331,"1025275581468":1509788624331,"1025275581470":1509788624331,"1022645598562":1480585069132,"1022646909325":1480585069141,"1022646909324":1480585069141,"1025275581477":1509788624331,"1025428398913":1509788624423,"1022645598566":1480585069132,"1022645598565":1480585069132,"1022646909321":1480585069141,"1022646909320":1480585069141,"1025275581478":1509788624331,"1025428398914":1509788624423,"1022645598571":1480585069132,"1022646909319":1480585069141,"1019067573805":1509788625079,"1022645598569":1480585069132,"1022646909317":1480585069141,"1022646909315":1480585069141,"1022645598574":1480585069132,"1022645598579":1480585069132,"1021626662573":1509788624930,"1025864874320":1509788667590,"1022645598577":1480585069132,"1022645598580":1480585069132,"1009701713402":1478686804052,"1020172821533":1509788624320,"1020172821534":1509788624320,"1020172821535":1509788624320,"1022646909328":1480585069141,"1026224786642":1514456869768,"1022069546238":1478686417301,"1022633803103":1480585069117,"1021930736437":1478686417142,"1025269158447":1509788624343,"1025711519189":1509788624305,"1022093925751":1478686417181,"1022633803078":1480585069117,"1021752869325":1478686417051,"1025275581401":1509788624332,"4964959223":1509788624162,"1025275581400":1509788624332,"1025275581403":1509788624332,"1025275581402":1509788624332,"1023605815129":1509788625142,"1025447929278":1509788624537,"1025275581419":1509788624332,"1025275581418":1509788624332,"1021093730604":1478686417094,"1025275581421":1509788624331,"1022645599918":1480585069133,"1025275581420":1509788624332,"1022645599916":1480585069133,"1022645599923":1480585069133,"1022645599922":1480585069133,"1022633803109":1480585069149,"1025428399255":1509788624423,"1021976876623":1509788625080,"1022645599927":1480585069133,"1022633803106":1480585069117,"1022645599924":1480585069133,"1022645599931":1480585069133,"1022645599930":1480585069133,"1022645599929":1480585069133,"1022645599935":1480585069133,"1022645599933":1480585069133,"1017165100816":1478686804020,"1022645599932":1480585069133,"1025428399258":1509788624423,"1024973455745":1509788624174,"1025428399335":1509788624423,"1022645599936":1480585069133,"1022767219975":1509788625074,"4997860771":1509788667399,"1025515168209":1509788624371,"1025515168208":1509788624371,"1025515168211":1509788624371,"1014925306596":1478950494940,"1025515168210":1509788624371,"1025515168213":1509788624371,"1025428399337":1509788624423,"1025515168212":1509788624371,"1025515168215":1509788624371,"1025515168214":1509788624371,"1025447929288":1509788624524,"1016910946341":1465470268246,"1024577235253":1509788667501,"1016910946343":1465470268267,"1025275581335":1509788624332,"1025515168207":1509788624371,"1025275581337":1509788624332,"1022645599962":1480585069133,"1025275581336":1509788624332,"1022645599960":1480585069133,"1025275581338":1509788624333,"1025275581341":1509788624333,"1022645599966":1480585069133,"1025275581340":1509788624333,"1025275581343":1509788624332,"1022645599964":1480585069133,"1025275581342":1509788624332,"1025792914059":1509788624182,"1025275581345":1509788624332,"1025428399301":1509788624423,"1025275581344":1509788624332,"1025275581347":1509788624332,"1022633803060":1480585069117,"1025275581346":1509788624332,"1022645599975":1480585069133,"1025792914063":1509788624182,"1025275581349":1509788624332,"1021663361896":1509788624515,"1025275581348":1509788624332,"1022645599973":1480585069133,"1025275581351":1509788624332,"1025275581350":1509788624332,"1022645599979":1480585069133,"1025275581353":1509788624332,"1025275581352":1509788624332,"1022645599977":1480585069133,"1025275581355":1509788624332,"1025275581354":1509788624332,"1022633803067":1480585069149,"1025275581357":1509788624332,"1025428399305":1509788624423,"1021976876560":1509788625080,"1025275581356":1509788624332,"1022645599981":1480585069133,"1022645599980":1480585069133,"1025792914075":1509788624182,"1022645599986":1480585069133,"1025792914074":1509788624182,"1022645599985":1480585069133,"1025792914073":1509788624182,"1021976876558":1509788625080,"1022645599984":1480585069133,"1021918415756":1509788624916,"1025792914067":1509788624182,"1025792914064":1509788624182,"1025792914071":1509788624182,"1022269546640":1509788624940,"1021623122192":1509788624861,"1012641669696":1478686417074,"1025373886827":1509788624309,"1021623122182":1509788624861,"1021976876780":1509788625080,"1021688513821":1509788624404,"1025593683546":1509788624425,"1025593683545":1509788624428,"1025593683544":1509788624431,"1025906292927":1509788667461,"1024615639968":1509788624199,"1025906292926":1509788667463,"1021623122188":1509788624861,"1022193146627":1478686416992,"1018980424577":1509788624439,"1021350881584":1509788624918,"1021623122187":1509788624861,"1022030614966":1509788624847,"1025428399109":1509788624423,"1025428399106":1509788624423,"1610679465":1444487341756,"1025593683555":1509788624407,"1024973455727":1509788624174,"1024973455726":1509788624174,"1022507841140":1509788624935,"1024253566470":1509788624948,"1021614471348":1478686417116,"1024973455725":1509788624174,"1025078972215":1509788624280,"1020436804252":1478686804026,"1021721282316":1478686804050,"1020294064667":1465470268286,"1021721282317":1478686804050,"1024973455734":1509788624174,"1021721282318":1478686804050,"1021721282319":1478686804050,"1015291641932":1480585069068,"1025428399129":1509788624422,"1025428399131":1509788624422,"1021976876732":1509788625080,"1025428399206":1509788624423,"1021721282428":1478686804050,"1021721282429":1478686804050,"1025428399200":1509788624423,"1021721282430":1478686804050,"1021976876731":1509788625080,"1024782761450":1509788625080,"1022269024197":1478686804065,"1022633803142":1480585069117,"1022238877209":1509788624933,"201158436":1491634246513,"1023730859816":1509788624961,"1025428399225":1509788624423,"1009832262278":1509788625081,"1022029566341":1478686417165,"1025428399226":1509788624423,"1025428399169":1509788624422,"1021976876696":1509788625080,"1025428399170":1509788624423,"1017781001340":1509788624284,"1025906292928":1509788667457,"4935860952":1509788624162,"1020810348815":1478686417030,"1025901967512":1509788667460,"1021515117331":1509788624819,"936989472":1478950494919,"1025901967511":1509788667459,"1023087562966":1509788624820,"1025901967510":1509788667464,"1020857535434":1478686417227,"1023087562965":1509788624820,"1025901967509":1509788667461,"1025783738519":1509788624343,"1022645600135":1480585069134,"1022645600133":1480585069134,"1022645600138":1480585069134,"1025796322270":1509788624274,"1025783738525":1509788624343,"1022645600143":1480585069134,"1022645600142":1480585069134,"1021976876913":1509788625081,"1022645600141":1480585069134,"1025783738520":1509788624346,"1025428399541":1509788624422,"1022645600146":1480585069134,"1021509612361":1478686417007,"1022645600151":1480585069134,"1025428399537":1509788624422,"1022645600149":1480585069134,"1022645600155":1480585069134,"1022078459240":1478686417177,"4971908418":1509788624163,"1021435819943":1478686417107,"1022645600158":1480585069134,"1023819318672":1491634246533,"1022645600156":1480585069134,"1022645600161":1480585069134,"1022645600164":1480585069134,"1021976876876":1509788625081,"1009038101122":1478686804054,"1025783738530":1509788624343,"1021330434515":1478686416984,"1022206240235":1480585069087,"1009038101128":1478686804054,"1022701303915":1509788624972,"1021978974055":1478686417151,"1020556867646":1478686417017,"1020801698135":1478686417030,"1024869399336":1509788624949,"1020900267976":1478686417080,"1025798550517":1509788624430,"1024117905280":1509788624326,"1025798550516":1509788624428,"1025798550518":1509788624425,"1016819735179":1478686804063,"370635613":1478950494908,"1016819735181":1478686804063,"1022645600207":1480585069134,"1016819735180":1478686804063,"1022645600206":1480585069134,"1016819735183":1478686804063,"1016819735182":1478686804063,"1016819735185":1478686804063,"1022645600211":1480585069134,"1016819735184":1478686804063,"1016819735187":1478686804063,"1022645600209":1480585069134,"1016819735186":1478686804063,"1022645600213":1480585069134,"1022645600218":1480585069134,"1021976876839":1509788625080,"1022270464419":1509788624938,"1022645600222":1480585069134,"1022270464418":1509788624938,"1024007802412":1509788667834,"1022645600227":1480585069134,"1022645600226":1480585069134,"4964958860":1509788624162,"1022645600224":1480585069134,"1022645600229":1480585069134,"1022060106253":1509788624958,"1021855633106":1478686417135,"1022645600235":1480585069134,"1021574102803":1509788624814,"1025515167979":1509788624371,"1022645600247":1480585069134,"1025515167981":1509788624371,"1025515167980":1509788624371,"1021855633100":1478686417135,"1022645600245":1480585069134,"1025428399581":1509788624422,"1025428399580":1509788624422,"1025628023206":1509788624523,"1025628023202":1509788624537,"1025628023201":1509788624542,"1022286323858":1478686417198,"1025628023200":1509788624540,"1025428399399":1509788624422,"1025428399401":1509788624422,"1021976877040":1509788625081,"1023210903932":1509788625042,"1007983777254":1509788624373,"1022927916605":1509788624439,"1021976877039":1509788625081,"1022645600022":1480585069133,"1022645600021":1480585069133,"1022212400610":1478686417281,"1022645600026":1480585069133,"1023821415924":1491634246536,"1019879297279":1509788624369,"1025515167744":1509788624371,"1025515167747":1509788624371,"1025515167746":1509788624371,"1022645600029":1480585069133,"1022645600028":1480585069133,"1025713091596":1509788624306,"1018559808430":1478686804015,"1025428399368":1509788624423,"1025428399371":1509788624423,"1022643896077":1509788624420,"1021154796751":1478686416981,"1022080949660":1478686417178,"1021976877002":1509788625081,"1025058787098":1509788624367,"1021905963780":1509788624533,"1022484641156":1478943089254,"1022270333217":1480585069093,"1022270333216":1480585069093,"1022270333218":1480585069093,"1016992738397":1478686804063,"1022645600079":1480585069133,"1019761331106":1509788625077,"1025879948823":1509788667405,"1022645600087":1480585069133,"1022645600085":1480585069133,"1022645600091":1480585069133,"1025428399484":1509788624422,"1022645600088":1480585069133,"1025428399486":1509788624422,"1020194844015":1509788625016,"1022645600095":1480585069133,"1022039004021":1478686417011,"1022645600099":1480585069134,"1022645600098":1480585069134,"1025027198318":1509788624329,"1022927916621":1509788624439,"1022645600096":1480585069133,"1022927916620":1509788624439,"1021976876952":1509788625081,"1021976876953":1509788625081,"1838745714":1478950494926,"1021976876951":1509788625081,"1022927916611":1509788624439,"1014068248110":1478686804064,"1025428399445":1509788624422,"1021604903289":1478686417116,"1022206240033":1480585069086,"1022270333205":1480585069092,"1010295201623":1491634246523,"1022270333206":1480585069092,"1025428399442":1509788624422,"1024637531198":1509788667502,"1022270333209":1480585069092,"1022270333208":1480585069092,"1022270333211":1480585069092,"1022270333210":1480585069092,"1022270333212":1480585069092,"1022270333215":1480585069093,"1022270333214":1480585069092,"1020597094075":1478686804031,"1021721281964":1478686804050,"1021016137656":1478686417035,"1023734791595":1509788624969,"1023094772675":1509788624439,"1024780795712":1509788624973,"1021261881663":1465470268201,"1025428399751":1509788624422,"1024785383230":1509788624250,"1024785383217":1509788624250,"1024785383219":1509788624250,"1024785383221":1509788624250,"1025428399753":1509788624422,"1024785383223":1509788624250,"1008738614107":1444487341761,"1024785383209":1509788624250,"1022199437578":1478686417189,"1012680732326":1478686416994,"1025515168687":1509788624371,"1022206240484":1480585069087,"1022044639311":1478686417171,"1022044639307":1478686417171,"1021138150976":1478686417037,"1022471403173":1478686417219,"1024785383256":1509788624250,"1023858508821":1509788624199,"1022045556737":1478686417171,"1024785383262":1509788624250,"1024785383251":1509788624250,"1022045556756":1478686417171,"1024785383241":1509788624250,"1022045556759":1478686417171,"1024785383245":1509788624250,"1025428399857":1509788624422,"1025428399856":1509788624422,"1024785383233":1509788624250,"1012136267406":1478686417073,"1009317799564":1509788624369,"1025428399813":1509788624422,"1024780795710":1509788624973,"1024785383292":1509788624250,"1021948958316":1478686417055,"1018947524740":1509788624315,"1020339680892":1465470268323,"1024785383285":1509788624250,"1024785383287":1509788624250,"1025428399819":1509788624422,"1024785383273":1509788624250,"1019113578874":1509788624287,"1011852112271":1444487341712,"1019113578875":1509788624287,"1019113578872":1509788624287,"1019113578873":1509788624287,"1024785383279":1509788624250,"1019113578876":1509788624287,"1025428399837":1509788624422,"1025428399836":1509788624422,"604455547":1444487341744,"1024785383268":1509788624250,"1022478874129":1478943089487,"1025261162559":1509788624280,"1024096016013":1509788624522,"1020339680914":1465470268324,"1021976089836":1509788625142,"1025318707113":1509788625168,"1025318707112":1509788625166,"1022026421216":1478686417011,"1000211842848":1478686804068,"1025318707106":1509788625129,"1025447929610":1509788624198,"1024797965512":1509788624241,"1024096016030":1509788624522,"1025447929609":1509788624201,"1024797965515":1509788624241,"1025447929608":1509788624204,"1024797965514":1509788624241,"1024096016028":1509788624522,"1024797965517":1509788624241,"1024096016027":1509788624522,"1020052707738":1509788624281,"1024797965505":1509788624241,"1020339680911":1465470268323,"1024797965507":1509788624241,"1024096016020":1509788624522,"1000211842865":1478686804068,"1024797965509":1509788624241,"1024096016018":1509788624522,"1024785383353":1509788625198,"1025318707085":1509788625129,"1024785383355":1509788625198,"1025593683048":1509788624746,"1025318707084":1509788625110,"1018829033657":1478686804020,"1025318707082":1509788625144,"1000211842827":1478686804068,"1025318707079":1509788625164,"1024785383345":1509788625198,"1025318707078":1509788625164,"1024096016037":1509788624523,"1024096016036":1509788624522,"1025318707076":1509788625164,"1024096016035":1509788624522,"1025593683046":1509788624823,"1024785383348":1509788625198,"1025593683045":1509788624833,"1025593683044":1509788624828,"1025318707103":1509788625129,"1025428399636":1509788624421,"1023094772588":1509788624439,"1025318707101":1509788625129,"1024785383341":1509788625198,"1025318707098":1509788625129,"1025428399635":1509788624421,"1024096016057":1509788624523,"1025318707096":1509788625129,"1021272501952":1509788624433,"1024096016054":1509788624522,"1021272501955":1509788624433,"1024096016052":1509788624522,"604455611":1444487341720,"1025126025239":1509788624308,"1025318707090":1509788625129,"1024096016049":1509788624522,"1025318707088":1509788625129,"1025428399717":1509788624422,"1021272501944":1509788624433,"1023006296515":1509788624466,"1024785383385":1509788625198,"1024785383387":1509788625198,"1025428399718":1509788624422,"1024785383386":1509788625198,"1024096016075":1509788624523,"1837042616":1491634246516,"1024434234144":1509788624198,"1024096016072":1509788624522,"1025665640521":1509788667649,"1025665640520":1509788667650,"1837042613":1491634246516,"1025665640523":1509788667617,"1022189738336":1478686417013,"1021272501940":1509788624441,"1024096016066":1509788624522,"1025665640524":1509788667617,"4935860476":1509788624162,"1024785383383":1509788625198,"1021272501943":1509788624433,"1024785383382":1509788625198,"463961463":1491634246534,"1837042606":1491634246516,"1837042605":1491634246516,"1837042603":1491634246516,"1024785383373":1509788625198,"1024785383363":1509788625198,"1837042596":1491634246516,"1022083178196":1478686417272,"1024785383367":1509788625198,"1011886194454":1478686804062,"1025665640545":1509788667600,"1011886194455":1478686804062,"1011886194452":1478686804062,"1025428399687":1509788624422,"1011886194453":1478686804062,"1025428399686":1509788624422,"1026224785870":1514456869772,"1011886194450":1478686804062,"1023946457597":1491634246529,"1011886194451":1478686804062,"1021721281886":1478686804050,"1011886194449":1478686804062,"1025665640553":1509788667601,"1000211842887":1478686804068,"1024785383411":1509788625198,"1010295200841":1491634246522,"1025665640554":1509788667601,"1021978186936":1478686417056,"1023670563227":1509788624825,"1011579740355":1478686417220,"1024785383400":1509788625198,"1024785383403":1509788625198,"1600731550":1444487341750,"1024785383406":1509788625198,"1022170339341":1478686417013,"1024434234142":1509788624206,"1024434234141":1509788624198,"1024785383395":1509788625198,"1024785383397":1509788625198,"1022328136081":1478686417201,"1011826815878":1509788624944,"1018172237860":1478686804058,"1018172237859":1478686804058,"4997861101":1509788667399,"1021914089780":1509788624986,"1025686874198":1509788624309,"1024127341917":1509788624363,"1021025312314":1509788624933,"1020437066037":1478686804029,"1409626898":1509788625020,"1021905963427":1509788624817,"1025908390672":1509788667459,"1026223474776":1514456869766,"1021354289794":1465470268229,"1025508614886":1509788624339,"1022340329416":1478686417069,"1025508614880":1509788624346,"1022089862846":1478686416976,"1022042935628":1478686417170,"1022075707319":1478686417177,"1021594287134":1478686417246,"1022075707305":1478686417177,"1020886636098":1478686416999,"1020890437217":1509788624986,"1025515168477":1509788624371,"1025515168476":1509788624371,"1025318706794":1509788624538,"1025515168479":1509788624371,"1025515692758":1509788624340,"1025515168478":1509788624371,"1022076624681":1509788624928,"1025318706791":1509788624553,"1025318706788":1509788624564,"1025318706785":1509788624564,"1025318706813":1509788624544,"1021981463913":1478686417151,"1025318706810":1509788624544,"1022200617052":1478686417190,"1021115881605":1478686417095,"1025318706806":1509788624544,"1024773193352":1509788625069,"1022069546919":1478686417301,"1025318706802":1509788624544,"1022089862857":1478686416976,"1022089862862":1478686416976,"1022089862863":1478686416976,"1020832893411":1478686416998,"1025318706781":1509788624564,"1025593683389":1509788625088,"1025593683379":1509788625116,"1022192752889":1478686417279,"1022372048269":1480585069105,"1025593683383":1509788625108,"1025593683381":1509788625124,"1022812570382":1509788625110,"1025791734428":1509788667921,"1022372048242":1480585069098,"1021987624028":1478686417154,"1025791734427":1509788667921,"1021290458816":1478686417040,"1021148112458":1478686417037,"1023734791227":1509788624969,"1021290458820":1478686417040,"1025791734419":1509788667921,"1021097662804":1478686417002,"1022316470704":1478686417200,"1025791734412":1509788667911,"1025791734409":1509788667948,"1021097662802":1478686417002,"1009566181801":1480585069061,"1022461437957":1478686417303,"1025791734407":1509788667993,"1025791734406":1509788667993,"1021905963300":1509788624195,"1025318706831":1509788624566,"1021097662821":1478686417002,"4890379485":1509788624162,"1021097662822":1478686417002,"1025318706828":1509788624565,"1021794287844":1478686416981,"1021688776224":1478686417121,"1025318706823":1509788624544,"1025318706822":1509788624544,"1019449392303":1509788625084,"1025318706819":1509788624544,"1018546700637":1480585069063,"1025318706818":1509788624544,"1021976876493":1509788625080,"1025428399895":1509788624421,"1025428399894":1509788624421,"1025791734433":1509788667921,"1022418185201":1478686417293,"1008287196594":1478686804030,"1008287196593":1478686804025,"1025428399969":1509788624422,"1024961266523":1509788624933,"1018516816767":1478686804066,"1025428399970":1509788624422,"1021680519106":1509788624854,"1024961266517":1509788624933,"1023087563746":1509788624536,"1023087563745":1509788624536,"1024961266513":1509788624922,"1021680519111":1509788624854,"1021680519108":1509788624854,"1021680519109":1509788624854,"1022088158730":1478686417062,"1022156970613":1478686417278,"1021688514137":1509788624404,"1022088158728":1478686417062,"1022156970620":1478686417278,"1021828370106":1509788624205,"1021828370105":1509788624201,"1020940243918":1478686417033,"1021948958702":1478686417055,"1021828370109":1509788624186,"1025428399949":1509788624422,"1025428399950":1509788624422,"1024587065632":1509788667888,"4935860701":1509788624162,"1021680519162":1509788624219,"1020167840162":1509788625077,"1021680519161":1509788624219,"1021680519164":1509788624219,"1021097662781":1478686417002,"1021680519159":1509788624219,"1023946854163":1491634246531,"1021154666851":1478686417097,"1025628939475":1509788624431,"1025628939474":1509788624428,"1020924779315":1478686417000,"1023946854166":1491634246531,"1025628939476":1509788624425,"1023095823784":1509788624996,"1023095823780":1509788624996,"1025628939483":1509788624406,"1022631047530":1509788624231,"1023095823782":1509788624996,"1021154666862":1478686417097,"1022370210529":1509788624300,"1022454622184":1478686417072,"1021154666863":1478686417097,"1021154666867":1478686417097,"1022945477810":1509788625051,"1021154666870":1478686417097,"1023084551265":1509788624430,"1022453573173":1509788624937,"1023095823757":1509788624996,"1022453573174":1509788624936,"1480011795":1478686804024,"1021680519214":1509788624557,"1021032387213":1478686417091,"1023095823752":1509788624996,"1022453573171":1509788624937,"1022453573181":1509788624937,"1022453573180":1509788624937,"1022453573177":1509788624937,"1023094644210":1509788624533,"1020932512915":1509788624930,"1023095823746":1509788624996,"1020567746125":1478686417224,"1021404887207":1478686417240,"1023095823774":1509788624995,"1023095823768":1509788624995,"1022453573165":1509788624936,"1022453573164":1509788624936,"1021680519216":1509788624558,"1021680519217":1509788624558,"1022453573166":1509788624937,"1025011470243":1509788625084,"1025011470242":1509788625084,"1021680519220":1509788624557,"1023095823763":1509788624996,"1022453573162":1509788624937,"1021500702339":1478686417007,"1023095823855":1509788624996,"1020582164422":1478686417027,"1025593287349":1509788624929,"1023095823851":1509788624996,"1022458029977":1478686417072,"1022001650862":1478686417265,"1017165101926":1478686804020,"1022458029978":1478686417072,"1021770305250":1478686417127,"1023094644113":1509788625100,"1021770305251":1478686417127,"1023095823869":1509788624996,"1022453573188":1509788624937,"1022453573187":1509788624937,"1023095823861":1509788624996,"1023095823860":1509788624996,"1023095823857":1509788624996,"772097627":1491634246519,"1023095823859":1509788624996,"1023502918918":1509788624971,"1025628021855":1509788625088,"1025628021854":1509788625115,"1025628021853":1509788625107,"1025628021852":1509788625124,"1020482644":1478950494919,"1022479268067":1478943089487,"1002055870288":1478686417024,"1021272236267":1478686417101,"1022417921168":1478686417302,"1022429849033":1478686417071,"1021925754846":1478686804066,"1023572130185":1509788624974,"1023020194031":1509788625083,"1020294063724":1465470268286,"1021719972719":1509788624434,"1023627050183":1509788624612,"1023627050182":1509788624612,"1021185600323":1478686417098,"1023627050186":1509788624550,"1023627050185":1509788624550,"1019699725041":1509788624312,"1023095823718":1509788624996,"1023627050191":1509788624540,"1023627050190":1509788624540,"1023627050199":1509788624540,"1023627050197":1509788624540,"1023095823739":1509788624996,"1024002687848":1491634246532,"1016927595951":1478686804024,"1021729672160":1509788624563,"1024002687845":1491634246532,"1021982513878":1509788625067,"1023020194035":1509788625083,"1024002687842":1491634246532,"1023095823731":1509788624996,"1023020194033":1509788625083,"1000037269226":1478686417021,"1023020194032":1509788625083,"1024370272566":1509788624926,"1021729672155":1509788624563,"1024094968027":1509788625036,"1025709553927":1509788667888,"1021729672157":1509788624563,"1022401012689":1478686417207,"1021729672158":1509788624563,"1024096016610":1509788624522,"1021276299479":1480585069070,"1021183765342":1465469681394,"1021183765343":1465469681394,"1023095823700":1509788624996,"1022849011353":1509788624325,"1023095823697":1509788624995,"1018335031663":1478686804022,"1000526159329":1444487341714,"1022376895375":1478686804066,"1019310455366":1509788624315,"1021606868324":1509788624397,"1000526159333":1444487341735,"1025712830687":1509788624304,"1022360772754":1478686417203,"1022376895376":1478686804066,"1021331875282":1509788624975,"1021331875283":1509788624975,"1022757521621":1509788624352,"1021331875280":1509788624975,"1021331875286":1509788624976,"1021331875287":1509788624976,"1021331875284":1509788624975,"1021331875285":1509788624976,"1021331875288":1509788624975,"1021331875289":1509788624976,"1021331875295":1509788624975,"1021747629348":1478686417126,"1021331875292":1509788624976,"1000526159320":1444487341740,"1021338166695":1478686417041,"1021006041448":1509788624933,"1020136647995":1480585069063,"1021331875274":1509788624975,"1021331875275":1509788624975,"1021331875273":1509788624975,"1021331875278":1509788624975,"1021331875279":1509788624975,"1021331875277":1509788624975,"1021260574322":1478686804035,"1021490871348":1509788624398,"1021260574323":1478686804035,"1021722987203":1509788624395,"1012606807480":1478686416972,"1021260574321":1478686804035,"1022220921008":1480585069090,"1021260574326":1478686804035,"1018515639786":1509788624426,"1021260574327":1478686804035,"1021260574324":1478686804035,"1021260574325":1478686804035,"1025517136946":1509788624308,"1021260574328":1478686804035,"1016688533240":1478686804063,"1021170658110":1478686417098,"1021260574310":1478686804035,"1021260574311":1478686804035,"1021260574309":1478686804035,"1021260574314":1478686804035,"1021260574315":1478686804035,"1017165101685":1478686804020,"1022022753530":1509788624463,"1021260574318":1478686804035,"1021260574319":1478686804035,"1019963970340":1478686804021,"1021260574316":1478686804035,"1021260574317":1478686804035,"1022172436407":1478686417013,"1021700443036":1478686804046,"1023627050350":1509788624612,"1023627050349":1509788624612,"1023627050354":1509788624550,"1023627050358":1509788624553,"1023627050356":1509788624550,"1023627050370":1509788624540,"1023627050369":1509788624540,"1023627050374":1509788624540,"1023627050373":1509788624540,"1021354288146":1465470268229,"1021354288148":1465470268229,"1023627050383":1509788624567,"1023627050382":1509788624540,"1023627050380":1509788624540,"1023502918911":1509788624940,"1022004927840":1478686417158,"1022220920899":1480585069090,"1021831643325":1478686417256,"1021831643327":1478686417256,"1021330040146":1465470268219,"1021330040145":1465470268219,"1025322373333":1509788624309,"1022897111110":1509788667836,"1022897111106":1509788667889,"1021990640197":1478686417301,"1022105064213":1478686417012,"1025620157082":1509788624431,"1025627890977":1509788624866,"1023094644703":1509788624419,"1025367332426":1509788624304,"1005662850250":1480585069065,"1021976877164":1509788625080,"1021951581175":1478686417010,"1021976877162":1509788625080,"1024185408707":1509788624183,"1024185408709":1509788624184,"1023095824267":1509788624995,"267740626":1478686804050,"1023095824257":1509788624995,"1743850945":1444487341740,"1021976877129":1509788625080,"4890380618":1509788624163,"1021976877130":1509788625080,"1023095824272":1509788624995,"1021848944675":1509788624399,"1024185408666":1509788624184,"1012134169932":1478686417025,"1021588910558":1509788624397,"1021782363222":1509788624399,"1024185408664":1509788624184,"1021049950713":1478686417232,"1023939120428":1509788625006,"1020918225372":1509788624940,"1024185408668":1509788624184,"1022491196318":1478943089490,"1024185408657":1509788624185,"1024887999153":1509788624426,"1021925885217":1478686417055,"1024185408662":1509788624184,"1024185408661":1509788624185,"1024185408655":1509788624183,"1025090111130":1509788624292,"1021976877092":1509788625081,"1021976877093":1509788625081,"1020136648278":1480585069064,"1017228148020":1478686804049,"1010024530092":1491634246527,"1022169158795":1478686417063,"1024313202524":1509788624926,"1010024530095":1491634246527,"1024185408696":1509788624183,"1025798552785":1509788625113,"1024185408701":1509788624184,"1025798552787":1509788625106,"1025798552786":1509788625122,"1024185408691":1509788624184,"1024185408690":1509788624184,"1024185408688":1509788624184,"1024185408693":1509788624185,"1023020194368":1509788625083,"1024185408683":1509788624184,"1024185408681":1509788624184,"1024185408680":1509788624184,"1022312803340":1478686417287,"1024185408685":1509788624184,"1021019542293":1478686417035,"1024185408679":1509788624184,"1017165101392":1478686804020,"1024185408676":1509788624184,"1021260574130":1478686804054,"1021260574131":1478686804054,"1022066531719":1478686417060,"1004773415747":1478686804027,"1021260574132":1478686804054,"1017228148194":1478686804049,"1016688532796":1478686804063,"1021976877296":1509788625080,"1000037268666":1478686417021,"1021976877294":1509788625080,"1022266665368":1478686417197,"1021184157982":1478686417098,"1023095824132":1509788624995,"1021860348376":1509788624394,"1023095824135":1509788624995,"1023095824128":1509788624995,"1019761067069":1509788624315,"1023095824153":1509788624995,"1023095824152":1509788624995,"1021976877252":1509788625080,"1019192878837":1509788624298,"1023095824148":1509788624995,"1021976877253":1509788625080,"1023095824150":1509788624995,"1023095824144":1509788624995,"1021902423052":1509788625082,"1021902423053":1509788625082,"1009848513920":1491634246513,"1025050788837":1509788624461,"1021902423054":1509788625082,"1025385420695":1509788625169,"1021902423055":1509788625082,"1024785249246":1509788624434,"1025792916514":1509788624182,"1025050788845":1509788624461,"1025050788843":1509788624461,"1017228148134":1478686804033,"1024785249227":1509788624440,"1025447930703":1509788624824,"1025050788849":1509788624461,"1008738613180":1444487341761,"1025050788862":1509788624461,"1021118764378":1478686417233,"1021902423056":1509788625082,"1025792916532":1509788624182,"1021967833097":1478686417010,"1021967833101":1478686417010,"1025524084729":1509788624431,"1024785249267":1509788624510,"1025721613251":1509788624822,"1025524084728":1509788624428,"1025721613250":1509788624832,"1025721613249":1509788624828,"1025524084730":1509788624425,"1021354551160":1465470268231,"1025524084733":1509788624407,"1021976877200":1509788625080,"1021354551162":1465470268232,"1021354551163":1465470268232,"1025721613252":1509788624616,"1021779086554":1478686417052,"1017228148121":1478686804033,"1024785249259":1509788624453,"1022459602250":1478686417072,"1010024529976":1491634246521,"1024785249263":1509788624453,"1025050788819":1509788624461,"1022342029902":1478686417069,"1025792916510":1509788624182,"1010024529978":1491634246521,"1024785249261":1509788624452,"1024785249260":1509788624510,"1025524084713":1509788624542,"1025524084712":1509788624541,"1025524084715":1509788624524,"1025524084714":1509788624537,"1022252378386":1509788624175,"1022252378391":1509788624175,"1022252378389":1509788624176,"1022252378392":1509788624176,"1021357696593":1478686417104,"1021976877418":1509788625080,"1022252378372":1509788624175,"1021976877419":1509788625080,"1022252378377":1509788624175,"1025332859245":1509788667581,"1022252378376":1509788624175,"1022252378381":1509788624175,"1023095824011":1509788624993,"1017165101059":1478686804020,"1023095824001":1509788624993,"1021495721507":1478686417046,"1022002569177":1478686417265,"2086475634":1478686417024,"1012406014912":1478686417074,"1021976877387":1509788625080,"1023095824021":1509788624993,"1022754376510":1509788624185,"1022269024299":1478686804065,"1019527629638":1509788624315,"1025515826733":1509788624340,"1023095824111":1509788624995,"1021939260410":1478686417143,"1021431757240":1478686417241,"1023605815297":1509788625168,"1023095824106":1509788624995,"1025569563410":1509788624349,"1023095824100":1509788624995,"1023210903485":1509788625042,"1000037268837":1478686417021,"1023095824125":1509788624995,"1020823979623":1478686416989,"1023095824118":1509788624995,"1157967451":1478950494921,"1022754376537":1509788624185,"1023095824115":1509788624995,"1021558239762":1509788624405,"1024934529367":1509788624418,"1024934529366":1509788624418,"1024934529361":1509788624418,"4780160911":1509788624162,"1024934529368":1509788624418,"1021976877331":1509788625080,"1023095824093":1509788624995,"1023791936861":1509788624961,"1019963838731":1478686804021,"1023932042369":1491634246530,"1023932042368":1491634246530,"1022442300887":1478686417214,"1024934529354":1509788624418,"1010024530251":1491634246521,"1021623908077":1509788624396,"1021680520066":1509788624421,"1023932042366":1491634246530,"1016301734704":1480585069065,"1024313464490":1509788624926,"1008734156354":1478686804034,"1022014758824":1478686417160,"1008734156353":1478686804034,"1022014758825":1478686417160,"1021437786394":1509788624399,"1023949079405":1509788667493,"1023095823885":1509788624996,"1023095823884":1509788624996,"1022103490901":1478686417181,"1023095823880":1509788624996,"1023095823883":1509788624996,"1021976877531":1509788625080,"1023095823876":1509788624996,"1023095823878":1509788624996,"1021197922147":1509788624171,"1012716642777":1509788624366,"1023095823874":1509788624996,"1025540599201":1509788624302,"1025285020907":1509788624329,"1023094644321":1509788624193,"1025798552949":1509788624542,"1025798552948":1509788624537,"1025711258122":1509788624345,"1023095823982":1509788624993,"1023095823976":1509788624993,"1025798552947":1509788624540,"1023095823972":1509788624993,"1023095823997":1509788624992,"1023095823994":1509788624992,"1023095823985":1509788624992,"1001351761409":1444487341700,"1665206434":1444487341729,"1021966392059":1478686417056,"1023095823946":1509788624993,"1008734156351":1478686804034,"1023095823941":1509788624993,"1008891170202":1478686804025,"1020816901738":1478686417078,"1022220921369":1480585069090,"1023095823936":1509788624992,"1018992339886":1509788624353,"1021925753991":1478686804057,"1023095823964":1509788624993,"1023095823967":1509788624993,"1023095823953":1509788624993,"1024934530613":1509788624531,"1024934530615":1509788624531,"1024934530609":1509788624531,"1024934530608":1509788624531,"1024934530611":1509788624531,"1024934530610":1509788624531,"1024934530618":1509788624531,"1021901767404":1509788624394,"1024887082238":1509788625023,"1024934530605":1509788624531,"1024934530604":1509788624531,"1022315817527":1478686417287,"1023572131159":1509788624974,"1024961267900":1509788624970,"1010091901671":1491634246522,"1318658736":1509788625016,"1021500832497":1478686417112,"1025573233710":1509788624338,"1021500832495":1478686417112,"309689926":1491634246534,"1025517136204":1509788624293,"1013050749521":1478686804064,"1001845501452":1478686417018,"1001845501454":1478686417018,"1001845501449":1478686417018,"1001845501451":1478686417018,"557141375":1444487341736,"1001845501446":1478686417018,"1019592640723":1478686804064,"1001845501440":1478686417018,"1024134553487":1509788625015,"1001845501441":1478686417018,"1019592640725":1478686804064,"1019592640726":1478686804064,"1001845501443":1478686417018,"1001845501465":1478686417018,"1001845501467":1478686417018,"1001845501458":1478686417018,"1025469296139":1509788624362,"1022203620505":1509788624325,"1022203620504":1509788624325,"1001845501480":1478686417018,"1021014955454":1478686417001,"1001845501476":1478686417018,"1022203620498":1509788624325,"1016866516337":1478686804019,"1022203620497":1509788624325,"1022203620496":1509788624325,"1001845501472":1478686417018,"1022203620502":1509788624325,"1022203620501":1509788624325,"1022203620500":1509788624325,"1022203620491":1509788624325,"1022203620488":1509788624326,"1022203620495":1509788624325,"1022203620494":1509788624325,"1022203620493":1509788624326,"1024887082143":1509788624467,"1022203620492":1509788624325,"1022203620483":1509788624326,"1022203620482":1509788624326,"1022203620486":1509788624325,"1022203620485":1509788624325,"1022203620484":1509788624325,"1021983039106":1478686417152,"1022203620474":1509788624325,"1021663359885":1509788624515,"1013170670018":1478686804049,"1022203620479":1509788624325,"267740019":1478686804050,"1022203620477":1509788624325,"1022203620476":1509788624325,"1022203620466":1509788624325,"1022203620464":1509788624324,"1024528082626":1509788625027,"1022287898977":1478686417286,"1024673185596":1509788624419,"1024673185585":1509788624816,"1024383774324":1509788624327,"1000051555326":1478686417021,"1022240976390":1478686417066,"1022240976393":1478686417066,"1021925753792":1478686804057,"1025515825628":1509788624339,"1022240976407":1478686417066,"1021707914912":1478686417122,"1021295044039":1478686417102,"1024934530813":1509788624418,"1021182193424":1478686417098,"1025374015801":1509788624305,"1024205986655":1509788624185,"1021426777589":1478686417044,"1021922739032":1478686417141,"1018397028664":1480585069072,"1024393342611":1509788667496,"1021386662761":1478686417006,"1022452654820":1478686417296,"1021922739027":1478686417141,"1022292486500":1478686804040,"1025796323876":1509788624274,"1021707914899":1478686417122,"1021779479256":1478686417128,"1322197557":1478686804029,"1021707914907":1478686417122,"1022646908781":1480585069140,"1017055125724":1465470268267,"1024235607253":1509788624484,"1020556865545":1478686417017,"1022646908771":1480585069140,"1024370142420":1509788624278,"1020891880473":1509788624971,"1022951899477":1509788625051,"1022646908794":1480585069140,"1012822293780":1478686804056,"1022385284880":1478686417205,"1022646908791":1480585069140,"767246500":1491634246508,"1025050788871":1509788624461,"1024785249338":1509788624508,"1021438312379":1509788624817,"1022293403811":1478686417068,"1025050788869":1509788624461,"1022438499288":1478686417213,"1025050788868":1509788624461,"1025485942385":1509788625088,"1022220528862":1478686417281,"767246483":1491634246508,"1024017498613":1509788667890,"1022220528851":1478686417281,"1024785249329":1509788624467,"1007474573293":1478686804015,"4649351217":1478686416965,"1018553649989":1478686804065,"1024673185414":1509788624194,"1024934530821":1509788624418,"1022370473944":1478686417290,"767246473":1491634246508,"1024934530823":1509788624418,"1024785249320":1509788624441,"1024934530817":1509788624418,"1025485942383":1509788625125,"1025485942382":1509788625117,"1022132983304":1478686417013,"1024785249312":1509788624480,"1024673185515":1509788624533,"1021202115018":1478686417099,"1024965462296":1509788624379,"1024965462298":1509788624379,"1000526158241":1444487341712,"1024965462295":1509788624379,"1024383774629":1509788624327,"1017726212233":1478686804059,"1008897723206":1478686804033,"1021651563158":1478686417120,"1024965462277":1509788624379,"1024965462276":1509788624379,"1021651563164":1478686417120,"1024965462275":1509788624379,"1024965462274":1509788624379,"1024529524536":1509788624477,"1024529524541":1509788624476,"1024529524540":1509788624477,"1024529524529":1509788624476,"1024529524531":1509788624477,"1021623120124":1509788624818,"1024529524533":1509788624477,"1022493162708":1478943089532,"1000037268315":1478686417021,"1024529524525":1509788624476,"1022493162703":1478943089532,"1024663748398":1509788625026,"1022493162691":1478943089532,"1023121775451":1509788625046,"1010044454592":1480585069062,"1022493162694":1478943089532,"1021937818961":1478686804071,"1008058227099":1480585069066,"1025407046249":1509788624865,"1025407046248":1509788624865,"1010091901764":1491634246522,"1021937818967":1478686804071,"1025407046252":1509788624849,"1021289407730":1478686417040,"1022646908903":1480585069140,"1022646908902":1480585069140,"1025407046241":1509788624917,"1022646908900":1480585069140,"1021937818972":1478686804071,"1008058227093":1480585069066,"1022646908899":1480585069140,"1025407046247":1509788624865,"1023094380623":1509788625047,"1025407046246":1509788624916,"1021937818974":1478686804071,"1022646908897":1480585069140,"1008058227083":1480585069066,"1021289407727":1478686417040,"1008058227087":1480585069066,"1023572131025":1509788624974,"1025407046258":1509788624838,"1000037268399":1478686417021,"1021728886462":1509788624271,"1021728886463":1509788624271,"1025407046256":1509788624838,"1021728886457":1509788624271,"1021728886458":1509788624271,"1025407046260":1509788624838,"1019592640824":1478686804053,"1019592640825":1478686804053,"4971906553":1509788624162,"1022646908877":1480585069140,"1020294062859":1465470268286,"1022646908874":1480585069140,"1024333517376":1509788624570,"1022646908871":1480585069140,"1022646908870":1480585069140,"1024973457514":1509788624173,"1022646908867":1480585069140,"1022243991358":1478686417283,"1021680520615":1509788624535,"1022257098245":1478686417067,"1016819733103":1478686804039,"1019254226187":1509788625079,"1021721415178":1478686804047,"1022646908895":1480585069140,"105737215":1444487341755,"1021937818978":1478686804072,"1021937818979":1478686804072,"1022646908892":1480585069140,"1022075835694":1509788624530,"1021937818982":1478686804072,"1024673185310":1509788625101,"1021831644348":1478686417134,"1021937818985":1478686804072,"1021486282756":1478686417007,"1021937818987":1478686804072,"1022646908883":1480585069140,"1021937818989":1478686804072,"1025806416892":1509788667449,"1010024531726":1491634246521,"1024333517348":1509788624570,"1024333517347":1509788624571,"1024333517346":1509788624571,"1016702293254":1478686804063,"1021408165262":1478686417106,"1024333517359":1509788624570,"1024383774496":1509788624327,"1024333517358":1509788624570,"1017726212115":1478686804059,"1024333517357":1509788624570,"1020919144099":1478686417081,"1024333517356":1509788624570,"1010024531714":1491634246521,"1025407046203":1509788624230,"1024333517366":1509788624571,"1025407046200":1509788624208,"1024333517363":1509788624570,"1010091901717":1491634246522,"1013285093698":1480585069065,"1024333517361":1509788624570,"1021480516033":1478686417110,"1024333517360":1509788624570,"1024333517375":1509788624570,"1024333517374":1509788624570,"1025407046193":1509788624207,"1024333517372":1509788624570,"1025407046199":1509788624207,"1024333517371":1509788624570,"1024333517370":1509788624571,"1025407046155":1509788624270,"1021728886468":1509788624271,"1021728886469":1509788624271,"1025407046153":1509788624270,"1021728886470":1509788624271,"1022646908812":1480585069140,"1021728886471":1509788624271,"1021728886464":1509788624271,"1022646908810":1480585069140,"1021728886465":1509788624271,"1025485942450":1509788624407,"1024333517314":1509788624570,"1024333517313":1509788624570,"1021728886467":1509788624271,"1024333517312":1509788624570,"1021728886476":1509788624271,"1020782036573":1478686416997,"1022646908806":1480585069140,"1021728886478":1509788624271,"1022646908804":1480585069140,"1021728886472":1509788624271,"1016587344978":1478686804053,"1021728886473":1509788624271,"1022646908801":1480585069140,"1021728886474":1509788624271,"1022646908800":1480585069140,"1021728886475":1509788624271,"1025407046171":1509788624207,"1024333517335":1509788624571,"1025407046170":1509788624215,"1009832260523":1509788625081,"1024333517332":1509788624571,"1021728886480":1509788624271,"1024333517329":1509788624570,"1022646908824":1480585069140,"1025407046163":1509788624228,"1025485942447":1509788624431,"1021891280995":1478686417009,"1022646908822":1480585069140,"1024798095278":1509788624472,"1024333517341":1509788624570,"1022646908818":1480585069140,"1024333517338":1509788624570,"1024798095273":1509788624473,"1012108741493":1478686417025,"1024333517336":1509788624570,"1024333517287":1509788624570,"1024333517283":1509788624570,"1018999418867":1509788624282,"1024333517280":1509788624570,"1024333517295":1509788624570,"1024333517294":1509788624570,"1024333517293":1509788624570,"1024333517291":1509788624570,"1020798288561":1478686417029,"1024333517289":1509788624570,"1024333517303":1509788624570,"1024333517302":1509788624570,"1024333517301":1509788624570,"1022270335730":1480585069093,"1024333517297":1509788624570,"1024333517296":1509788624570,"1024333517310":1509788624570,"1024333517306":1509788624570,"1024333517305":1509788624570,"1024333517304":1509788624570,"1021329384759":1478686804050,"1022422508518":1478686417070,"1022517672978":1509788625075,"1022410056379":1478686417292,"1022410056373":1478686417292,"1024333517278":1509788624570,"1024333517277":1509788624570,"1024333517276":1509788624570,"1020802220581":1478686417030,"1019820842154":1509788624315,"1021348651960":1478686417041,"1020999489260":1509788624175,"1021240911889":1478686417236,"1023607651684":1509788625081,"1021240911887":1478686417236,"1024925748463":1509788624926,"1024973458330":1509788624174,"1024973458328":1509788624174,"1021502929118":1509788624398,"1020437461057":1478686804029,"1021809493534":1478686417131,"1021363986562":1478686416990,"1021985922461":1478686416979,"1022376895732":1478686804066,"1022376895731":1478686804066,"1020243600859":1465470268318,"1024603972030":1509788624930,"1025285019947":1509788624328,"1022264700373":1478686417285,"1022264700370":1478686417285,"1023431878441":1509788624519,"1014965812948":1509788624352,"1024333517127":1509788624569,"1024333517126":1509788624569,"1024333517124":1509788624569,"1024333517123":1509788624570,"1024333517122":1509788624570,"1024333517129":1509788624569,"1024333517128":1509788624569,"1025508092758":1509788624344,"1020924779913":1478686417000,"1024333517095":1509788624570,"1024333517093":1509788624570,"1024333517092":1509788624570,"1024333517091":1509788624570,"1024333517090":1509788624569,"1022212009661":1478686417191,"1024333517103":1509788624569,"1024333517101":1509788624569,"1024333517100":1509788624569,"1024333517099":1509788624570,"1014935396604":1480585069074,"1021888660332":1478686417138,"1024333517097":1509788624570,"1021741337253":1478686417125,"1024333517096":1509788624570,"1024333517111":1509788624569,"1025627890192":1509788624231,"1024333517110":1509788624569,"1021329384903":1478686804050,"1024333517107":1509788624569,"1025883878728":1509788667405,"1022293404507":1478686417068,"1024333517117":1509788624569,"1020556866523":1478686417017,"1021709487255":1478686417122,"1016702293532":1478686804063,"1021782231237":1478686417300,"1024333517112":1509788624569,"1024333517060":1509788624874,"1025530898541":1509788624431,"1025530898540":1509788624428,"1022102311936":1478686417181,"1025530898543":1509788624407,"1025530898542":1509788624425,"1024333517071":1509788624874,"1024333517070":1509788624874,"1024333517069":1509788624874,"1024333517068":1509788624874,"1018828904686":1478686804020,"1024333517067":1509788624874,"1006896611760":1509788624392,"1024333517066":1509788624874,"1024333517065":1509788624874,"1024333517064":1509788624874,"1024333517072":1509788624874,"1021208275671":1478686804026,"1016007352613":1480585069075,"1019637991629":1509788624315,"1024333517038":1509788624874,"1024925748658":1509788624926,"1024198908134":1509788667888,"1024333517034":1509788624875,"1024333517033":1509788624874,"1024333517046":1509788624874,"1024333517045":1509788624874,"974869775":1491634246507,"1019637991632":1509788624312,"1024333517043":1509788624874,"1024333517042":1509788624874,"392394869":1444487341730,"1024333517041":1509788624874,"1024333517040":1509788624874,"1024333517054":1509788624874,"4964960500":1509788624163,"1024333517053":1509788624874,"1024333517051":1509788624874,"1021016790692":1478686417090,"1021955776188":1478686417146,"1021955776189":1478686417146,"1024333517048":1509788624874,"1025398788429":1509788624380,"1025398788431":1509788624380,"1025398788430":1509788624380,"1020830138865":1478686417078,"1025398788433":1509788624380,"1025398788432":1509788624380,"1025398788434":1509788624380,"1022248185104":1478686804046,"1015415243992":1480585069062,"1025398788399":1509788624381,"1025398788398":1509788624381,"1021969145278":1478686417149,"1021969145276":1478686417149,"1021091893879":1478686417036,"1025428140007":1509788625135,"1025529588204":1509788624339,"1025398788401":1509788624380,"1025398788400":1509788624380,"1025398788402":1509788624380,"1016702293916":1478686804063,"1024333516935":1509788624873,"1025428139977":1509788625129,"1025398788360":1509788624380,"1024333516934":1509788624873,"1025428139976":1509788625104,"1025607443835":1509788624213,"1025428139979":1509788625127,"1019697104161":1478686804033,"1025428139978":1509788625112,"1025607443837":1509788624213,"1024333516931":1509788624873,"1025428139981":1509788625127,"1024333516930":1509788624873,"1024333516928":1509788624873,"1025428139982":1509788625127,"1025607443825":1509788624213,"1024333516943":1509788624873,"1024333516942":1509788624873,"1025398788355":1509788624380,"1024333516941":1509788624873,"1021729016909":1509788624395,"1025398788357":1509788624380,"1025428139973":1509788625245,"1022376895978":1478686804066,"1025398788356":1509788624380,"1024333516938":1509788624873,"1025428139972":1509788625244,"1022376895977":1478686804066,"1025398788359":1509788624380,"1024333516937":1509788624873,"1025428139975":1509788625128,"1025398788358":1509788624380,"1024333516936":1509788624873,"1025428139974":1509788625128,"1009712068637":1491634246518,"1009749030434":1491634246512,"1025428139995":1509788625127,"1024333516946":1509788624873,"1025428139996":1509788625127,"1024333516944":1509788624873,"1025428139998":1509788625171,"1021953941156":1478686417261,"1025428139986":1509788625127,"1024798094633":1509788625177,"1024333516952":1509788624873,"1025428139990":1509788625127,"1024333516909":1509788624874,"1020556866187":1478686417017,"1024333516908":1509788624874,"1022999871721":1509788624465,"1024333516906":1509788624873,"1024333516918":1509788624873,"1024333516916":1509788624873,"1024333516913":1509788624873,"1024333516912":1509788624873,"1025607443840":1509788624213,"1024333516926":1509788624873,"1021922738214":1478686417141,"1025607443844":1509788624213,"1024333516922":1509788624873,"1025607443846":1509788624212,"1024055378180":1509788624326,"1024333516871":1509788624872,"1024333516870":1509788624872,"1024333516868":1509788624872,"1024333516867":1509788624872,"1024333516866":1509788624872,"1024333516865":1509788624872,"1022270335816":1480585069093,"1024333516878":1509788624872,"1024333516872":1509788624872,"1024205461560":1509788625034,"1001845501438":1478686417018,"1001845501433":1478686417018,"1024333516882":1509788624872,"1001845501434":1478686417018,"1024333516881":1509788624872,"1001845501435":1478686417018,"1001845501430":1478686417018,"1001845501431":1478686417018,"1021418126865":1509788624399,"1025398788523":1509788624380,"1025398788522":1509788624380,"1017621610961":1478686804067,"1021154799289":1478686416981,"1017621610960":1478686804067,"1025398788524":1509788624380,"1024333516846":1509788624872,"1024333516845":1509788624872,"1024333516844":1509788624873,"1980438983":1478950494928,"1024333516843":1509788624873,"1024333516840":1509788624872,"1024333516855":1509788624872,"1024333516854":1509788624872,"1024333516852":1509788624872,"1024333516851":1509788624872,"1022609553276":1509788625074,"1024333516849":1509788624872,"1017621610957":1478686804067,"1024333516863":1509788624872,"1017621610956":1478686804067,"1017621610959":1478686804067,"1017621610958":1478686804067,"1024333516860":1509788624872,"1022999347377":1509788624996,"1021427302140":1509788624405,"1024333516857":1509788624872,"1025398788483":1509788624380,"1025398788484":1509788624380,"1020887817893":1478686417079,"1021749201891":1509788624395,"1024188029250":1509788624441,"1022061811903":1478686417012,"1021923786877":1478686417141,"1024188029258":1509788624441,"1024434238949":1509788624497,"1024434238947":1509788624496,"1024434238944":1509788624496,"1023022284808":1509788625048,"1024434238959":1509788624497,"1024840297947":1509788624969,"1024434238954":1509788624496,"1024797436494":1509788625024,"1024434238964":1509788624497,"1024434238962":1509788624496,"1025428140223":1509788624432,"1024434238960":1509788624497,"4935603766":1509788624165,"1025428140209":1509788624511,"1025428140208":1509788624510,"1025771938864":1509788624503,"1024434238919":1509788624497,"1022270338240":1480585069093,"1024556530844":1509788667843,"1022270338243":1480585069093,"1022928051087":1509788624301,"1022270338242":1480585069093,"1024434238916":1509788624497,"1025428140170":1509788625136,"1012134172458":1478686417223,"1022270338245":1480585069093,"1022270338244":1480585069093,"1024434238914":1509788624497,"1022270338247":1480585069093,"1022270338246":1480585069093,"1024434238912":1509788624496,"1024434238927":1509788624497,"1024501610955":1509788624851,"1024212535060":1509788624276,"1024434238926":1509788624497,"1025428140160":1509788625127,"1024556530839":1509788667830,"1025428140165":1509788625127,"1024501610958":1509788624851,"1024501610957":1509788624851,"1024501610956":1509788624851,"1024434238934":1509788624496,"1024501610960":1509788624851,"1020790954808":1478686417077,"742612085":1478686417020,"1024434238929":1509788624497,"1024434238943":1509788624496,"1024434238941":1509788624496,"1008678971682":1478686804030,"1024434238940":1509788624496,"1024434238938":1509788624497,"1021477233762":1478686417110,"1022270338235":1480585069093,"1022270338234":1480585069093,"1020805635184":1478686416997,"1020819660070":1478686417030,"1022270338237":1480585069093,"1022270338236":1480585069093,"1022270338239":1480585069093,"1025576384922":1509788624349,"1021683011978":1478686417050,"1025428140226":1509788624432,"1182873328":1478686804033,"1022422252935":1478686417210,"1025428140241":1509788624432,"1025428140242":1509788624432,"1025428140247":1509788624437,"651646548":1444487341735,"1024333516643":1509788624235,"1024333516640":1509788624235,"1024333516655":1509788624235,"1024333516653":1509788624235,"1024333516648":1509788624235,"1024333516663":1509788624235,"1024333516662":1509788624235,"1025428140088":1509788625127,"1025428140091":1509788625171,"1020836306667":1478686417031,"1022454497140":1478686417297,"1024333516660":1509788624235,"1020836306669":1478686417031,"1024333516657":1509788624235,"1024333516670":1509788624235,"1024333516669":1509788624235,"1008601638182":1478686804030,"1024333516667":1509788624235,"1025533785825":1509788624348,"1025533785824":1509788624348,"1024333516664":1509788624235,"1025533785826":1509788624348,"1025628945520":1509788624460,"1021962322431":1509788624978,"1025428140040":1509788625128,"1025628945523":1509788624460,"1025628945522":1509788624460,"1021962322426":1509788624978,"1025628945524":1509788624460,"1021962322424":1509788624978,"1025628945526":1509788624460,"1025628945529":1509788624460,"1024333516622":1509788624235,"1025628945528":1509788624460,"1024333516621":1509788624235,"1025628945531":1509788624460,"1021962322420":1509788624978,"1025428140035":1509788625244,"1024333516620":1509788624235,"1021962322421":1509788624978,"1020662895742":1478686804032,"1024333516619":1509788624235,"1020662895743":1478686804034,"1020662895740":1478686804031,"1024333516617":1509788624235,"1025428140038":1509788625245,"1021234886152":1465470268323,"1021680521400":1509788624819,"1024333516628":1509788624235,"1024333516624":1509788624235,"1024333516638":1509788624235,"1025628945512":1509788624460,"1024333516637":1509788624235,"1025628945515":1509788624460,"1545546916":1478950494925,"1024333516636":1509788624235,"1025628945519":1509788624460,"1024333516581":1509788624235,"1024333516580":1509788624235,"1012840505808":1478686804062,"1022240715360":1478686417194,"1024333516578":1509788624235,"1025428140140":1509788625127,"1020880994581":1478686417079,"1024333516591":1509788624235,"1025428140129":1509788625128,"1025428140128":1509788625245,"1024333516589":1509788624235,"1021208278240":1478686804026,"1024333516587":1509788624235,"1024333516585":1509788624235,"1022768796153":1509788624304,"1021207884930":1478686417038,"1024333516595":1509788624235,"1017582165158":1478686804020,"1024333516592":1509788624235,"1025428140158":1509788625127,"1020294200945":1465470268296,"1012840505807":1478686804062,"1025428140146":1509788625127,"1024333516603":1509788624235,"1024333516602":1509788624235,"1024848817551":1509788624959,"1024333516600":1509788624235,"1025902619777":1509788667452,"1022451089119":1478686417296,"1022047913669":1478686417011,"1022292227414":1478686417068,"1025864870473":1509788667410,"1024237439308":1509788624176,"1024237439311":1509788624176,"1022240715348":1478686417194,"1025428140124":1509788625244,"1024333516574":1509788624235,"1022240715358":1478686417194,"1024333516570":1509788624235,"1024333516568":1509788624235,"1023569371283":1509788624516,"1025767482735":1509788624844,"1012134172175":1478686417223,"1025628814801":1509788624548,"1024002693819":1491634246532,"1024002693818":1491634246532,"1021263854068":1478686417101,"1024333516527":1509788624235,"1024333516526":1509788624235,"1025428402600":1509788624422,"1025428402602":1509788624422,"1024333516535":1509788624235,"1021598346748":1509788624401,"1022238618581":1509788624946,"1024333516533":1509788624235,"1024333516532":1509788624235,"1025767482748":1509788624844,"1017168634369":1478686804016,"1024333516531":1509788624235,"1024333516530":1509788624235,"1025767482739":1509788624844,"1024333516536":1509788624235,"1025749656253":1509788624350,"4883173927":1509788624165,"1019787936195":1478686804015,"1027387770061":1523788103996,"1012103763910":1478686417223,"1000527726028":1444487341714,"1020991882760":1478686417088,"1022630914083":1509788624869,"1021887618195":1478686417137,"1024333516454":1509788624234,"1022243861462":1478686417066,"1025428402657":1509788624422,"1025428402656":1509788624422,"149256611":1444487341731,"1024333516448":1509788624234,"1019093137163":1509788624373,"1024333516460":1509788624234,"1012134172226":1478686417223,"1024333516458":1509788624234,"1024333516456":1509788624234,"1024333516471":1509788624234,"1024333516470":1509788624234,"1024333516469":1509788624235,"1024333516467":1509788624235,"1024333516466":1509788624234,"1024028515680":1509788624517,"1008057304409":1478686804034,"1024333516465":1509788624234,"1024333516464":1509788624234,"1024333516476":1509788624234,"1022430379051":1478686417211,"1024333516474":1509788624234,"1024333516472":1509788624234,"1024333516423":1509788624234,"1025428402625":1509788624422,"1025428402626":1509788624422,"1012134172260":1478686417223,"1020640482154":1478686417028,"1024333516425":1509788624235,"1009848512050":1491634246513,"1024333516439":1509788624235,"1024333516437":1509788624235,"1021143265663":1478686417234,"1024333516436":1509788624234,"1024333516435":1509788624235,"1024333516434":1509788624234,"1024333516432":1509788624235,"1021631376490":1509788624440,"1021143265676":1478686417234,"1025428402464":1509788624422,"1023933093452":1491634246517,"1024352579916":1509788624177,"1023251927030":1509788624479,"1021143265671":1478686417037,"1021143265666":1478686417234,"1025100602784":1509788624172,"1019723455807":1478686804022,"1021287184387":1478686417101,"1012134172305":1478686417223,"1022438113150":1478686417295,"1005848182898":1509788624385,"1020850462245":1478686417031,"1012134172331":1478686417223,"1022127606475":1478686417063,"1021665972552":1478686417248,"1021312744376":1509788624940,"1024300747860":1509788624279,"1025749656110":1509788624350,"1025626979710":1509788625005,"1025428402461":1509788624422,"1026506584541":1515854751199,"1021166990183":1465470268307,"1012134172360":1478686417223,"1019356063614":1509788624313,"1018797835314":1478686804032,"1025428402543":1509788624422,"1022754378188":1509788624185,"1025428402542":1509788624422,"1023749074194":1491634246518,"1023527829052":1509788624325,"1024293014947":1509788667903,"1024313461994":1509788624176,"1025627766037":1509788625115,"1025627766043":1509788625087,"1025732223830":1509788624942,"1012134172397":1478686417223,"1022229704875":1478686417065,"1465067194":1444487341727,"1025636810163":1509788624338,"1025428402510":1509788624422,"1025428402507":1509788624422,"1009994783099":1491634246520,"1025428402852":1509788624422,"1025428402854":1509788624422,"1022074129085":1478686417060,"1021451936179":1509788624179,"1022426972049":1478686417211,"1024752478963":1509788667502,"1023149034145":1509788624373,"1023149034146":1509788624373,"1024167708653":1509788624441,"1024167708652":1509788624441,"1024167708655":1509788624441,"1024167708654":1509788624441,"1025428402831":1509788624422,"1024805169633":1509788625021,"1021795210622":1478686417130,"1000100702306":1478686417021,"1012139285228":1478686417223,"1025428402832":1509788624422,"1021845018734":1478686417135,"1006748898356":1478686804054,"1024167708656":1509788624441,"2244212610":1495284743407,"1025607448664":1509788624454,"1022381619222":1478686417205,"1018144717982":1509788625081,"1025428402943":1509788624422,"1020531961597":1480585069077,"1022941945499":1509788624935,"1022941945501":1509788624935,"1020940764740":1478686417000,"1020531961594":1480585069077,"1022941945488":1509788624935,"1020531961590":1480585069077,"1020924248403":1478686417228,"1020531961587":1480585069077,"1025428402901":1509788624422,"1020531961583":1480585069077,"1025428402896":1509788624422,"1020673250892":1478686804026,"1021356392440":1465469681398,"1006590570259":1478686804064,"1022303237225":1478686417199,"1024434239331":1509788624206,"1022941945470":1509788624935,"1000100702402":1478686417021,"1024434239336":1509788624230,"1021451936056":1509788624179,"1023796653427":1509788625038,"1021728887228":1509788624614,"1022879423019":1509788625053,"1021728887229":1509788624613,"1015982980923":1478686804046,"1021728887230":1509788624613,"1025428402745":1509788624422,"1021728887225":1509788624613,"1021728887226":1509788624614,"1025428402692":1509788624422,"1025428402689":1509788624422,"1020744424272":1478686417028,"1024434239310":1509788624206,"1022002562655":1478686417265,"1024383774786":1509788624327,"1021009578665":1478686417231,"1024789309555":1509788624233,"1021929561570":1478686417142,"1024434239317":1509788624206,"1025428402711":1509788624518,"1022238879862":1509788624946,"1024434239325":1509788624206,"1021929561577":1478686417142,"1022238879866":1509788624931,"1025026546181":1509788624329,"1022238879868":1509788624930,"1021865859546":1478686417136,"1019430643942":1478686804065,"1019042935194":1509788624317,"1012548743863":1478686804062,"1021832698846":1509788624556,"1024434239276":1509788624227,"1021473695407":1509788624816,"1025732223064":1509788624942,"1021422576568":1478686417106,"1021943186101":1509788624464,"1012163271570":1478686417223,"1025428402813":1509788624422,"1024434239294":1509788624214,"1025428402812":1509788624422,"1021091893216":1478686417094,"1021728887236":1509788624613,"1021728887237":1509788624613,"1025428402759":1509788624422,"1021728887238":1509788624613,"1021728887232":1509788624613,"1021121383835":1478686417095,"1021728887233":1509788624613,"1021728887234":1509788624613,"1021728887235":1509788624613,"1021728887244":1509788624613,"1022041752683":1478686417058,"1021728887245":1509788624613,"1000527857176":1444487341712,"1022093265793":1478686417063,"1020791609835":1478686417077,"1021728887241":1509788624613,"1021728887243":1509788624613,"1019277419442":1509788624376,"1021728887248":1509788624614,"1021728887249":1509788624614,"1021832698850":1509788624557,"1024142934453":1509788667499,"1021832698851":1509788624557,"1021199234594":1478686417235,"1025428402782":1509788624422,"1025428402776":1509788624422,"1021832698858":1509788624556,"1022270339040":1480585069094,"1021962322527":1509788624982,"1012094326381":1478686417223,"1021962322525":1509788624982,"1021962322521":1509788624982,"1001845502276":1478686417019,"1025134157095":1509788624384,"1001845502277":1478686417019,"1025134157094":1509788624384,"1021962322519":1509788624982,"1001845502278":1478686417019,"1025134157093":1509788624384,"1021962322516":1509788624982,"1001845502279":1478686417019,"1021395975191":1478686417240,"1025134157092":1509788624384,"1021962322517":1509788624982,"1001845502275":1478686417019,"1023233183373":1509788624958,"1013121126726":1478686804058,"1022473102302":1478943089231,"1025428403120":1509788624421,"1025428403122":1509788624421,"1298087495":1478686417024,"1025134157111":1509788624384,"1025134157110":1509788624384,"1021962322500":1509788624182,"1023606333509":1509788624215,"1025134157109":1509788624384,"1021962322498":1509788624183,"1009994783636":1491634246520,"1021962322496":1509788624182,"1021962322497":1509788624182,"651646454":1444487341731,"1009611006537":1478686804064,"1025607448892":1509788624438,"1022392891546":1478686417015,"1025607448880":1509788624438,"1023606333557":1509788624200,"1021962322542":1509788624982,"1019687934461":1509788624389,"1022270339029":1480585069093,"1025428403089":1509788624422,"1022270339028":1480585069093,"1025607448876":1509788624438,"1022270339031":1480585069093,"1021962322536":1509788624982,"1022270339030":1480585069093,"1025428403090":1509788624422,"1025607448878":1509788624438,"1022270339033":1480585069093,"1022270339032":1480585069093,"1021962322535":1509788624982,"1022270339035":1480585069093,"1022270339034":1480585069093,"1022270339037":1480585069093,"1021962322531":1509788624982,"1022270339039":1480585069094,"1022270339038":1480585069093,"1013121126675":1478686804058,"1024333515940":1509788625174,"1826955169":1444487341749,"1016871891427":1509788624977,"1025428403181":1509788624421,"1024333515951":1509788625174,"1024333515950":1509788625173,"1025428403183":1509788624421,"1024333515949":1509788625174,"1023606333459":1509788624213,"1024333515946":1509788625174,"1022056826102":1478686417173,"1022284887884":1478686417198,"1021962322446":1509788624978,"1021962322444":1509788624978,"1024453375383":1509788624975,"1021962322442":1509788624978,"1021286398674":1478686417004,"1021962322440":1509788624978,"1024333515953":1509788625173,"1024333515952":1509788625173,"4670842175":1478686416965,"1023606333444":1509788624271,"1021962322437":1509788624978,"1021962322435":1509788624979,"1826955141":1444487341705,"1001845502252":1478686417019,"1021962322494":1509788624183,"1024333515911":1509788625174,"1021962322495":1509788624182,"1025147526146":1509788624512,"1001845502255":1478686417019,"1021962322493":1509788624183,"1025147526144":1509788624511,"1001845502248":1478686417019,"1021962322490":1509788624182,"1001845502249":1478686417019,"1023606333498":1509788624213,"1023734786258":1509788624969,"1024333515904":1509788625174,"1025147526155":1509788624423,"1001845502245":1478686417019,"1024333515918":1509788625174,"1021962322485":1509788624182,"1024333515916":1509788625174,"1001845502241":1478686417018,"1025147526158":1509788624441,"1024333515914":1509788625174,"1001845502243":1478686417018,"1001845502268":1478686417019,"1025428403157":1509788624421,"1024333515927":1509788625174,"1001845502269":1478686417019,"1021962322479":1509788624182,"1025147526162":1509788624507,"1024333515926":1509788625173,"1001845502270":1478686417019,"1025147526161":1509788624441,"1024333515925":1509788625173,"1001845502264":1478686417019,"1024333515923":1509788625174,"1001845502266":1478686417019,"1025428403155":1509788624421,"1025147526164":1509788624507,"1001845502260":1478686417019,"1001845502263":1478686417019,"1025147526168":1509788624507,"1001845502258":1478686417019,"1021834664325":1478686417053,"1025732223478":1509788624942,"1024333515928":1509788625174,"1024333515878":1509788625173,"1025283966147":1509788624272,"1025283966146":1509788624272,"1025283966149":1509788624272,"1021351935547":1478686417041,"1025283966153":1509788624272,"1022470873958":1478686417299,"1025283966156":1509788624272,"1024333515882":1509788625174,"1020791085185":1478686804065,"1023606333648":1509788624213,"1024333515880":1509788625174,"1025428402997":1509788624422,"1024333515892":1509788625174,"1021617876562":1478686417117,"1023946986629":1491634246531,"1024333515891":1509788625174,"1021617876563":1478686417117,"1023946986628":1491634246531,"1025283966166":1509788624272,"1024701228938":1509788625025,"1021501744458":1509788624434,"1025428403006":1509788624422,"1023606333635":1509788624230,"1024333515896":1509788625174,"1021907541282":1509788624434,"1024333515846":1509788625172,"1025428402945":1509788624422,"1024333515843":1509788625173,"1024333515842":1509788625172,"1023404094698":1509788624929,"1024333515840":1509788625172,"1024333515855":1509788625173,"1024333515854":1509788625173,"1024333515852":1509788625173,"1022940108985":1509788624550,"1024333515851":1509788625172,"1025732223271":1509788624942,"1011344411543":1478686804022,"1025908912049":1509788667462,"1025283966192":1509788624272,"1025283966194":1509788624272,"1024333515860":1509788625172,"1024333515858":1509788625172,"1024333515857":1509788625173,"1020049427701":1509788624972,"1024333515856":1509788625172,"1022092741204":1478686417062,"1021962322589":1509788624982,"1021962322584":1509788624982,"1021962322583":1509788624982,"1024333515822":1509788625173,"1021962322581":1509788624982,"1024333515820":1509788625173,"1020798820216":1478686417029,"1023606333586":1509788624200,"1021962322579":1509788624982,"1011950153675":1509788625018,"1024333515818":1509788625173,"1024333515817":1509788625172,"1021962322574":1509788624983,"1024333515831":1509788625173,"1025627766546":1509788624425,"1025627766545":1509788624431,"1024333515829":1509788625173,"1021962322573":1509788624982,"1024333515828":1509788625173,"1021962322571":1509788624982,"1021795996914":1478686417052,"1021962322568":1509788624982,"1024333515824":1509788625173,"1024333515839":1509788625172,"1025458417954":1509788624350,"1024333515838":1509788625172,"1025627766552":1509788624407,"1024333515836":1509788625172,"1021962322562":1509788624982,"1021962322563":1509788624982,"1025458417946":1509788624352,"1021962322621":1509788624982,"1025458417951":1509788624350,"1025458417948":1509788624351,"1021962322617":1509788624982,"1826955023":1444487341749,"1024210961594":1509788625242,"1016977931136":1478686804049,"1025428403037":1509788624422,"1021962322599":1509788624983,"1025283966139":1509788624272,"1025428403039":1509788624422,"1025749655652":1509788624351,"1023606333603":1509788624200,"1024333515751":1509788624468,"1025428403364":1509788624421,"1024333515749":1509788624469,"1025428141226":1509788624433,"1024333515748":1509788624469,"1025428403361":1509788624421,"1024333515746":1509788624469,"1024333515744":1509788624469,"1020776538080":1478686416997,"1024333515755":1509788624468,"1025428141220":1509788624433,"1024333515754":1509788624468,"1024333515752":1509788624469,"1025428141241":1509788624432,"1021540936814":1478686417047,"1022195108712":1478686417189,"1022098246967":1478686417181,"1022098246968":1478686417181,"1022098246969":1478686417181,"1022356323803":1478686804071,"1025399704161":1509788624298,"1022356323804":1478686804071,"1022195108704":1478686417189,"1025428141238":1509788624427,"1024333515719":1509788624469,"1024333515717":1509788624469,"1024333515715":1509788624468,"1025003344445":1509788624346,"1024333515727":1509788624469,"1024333515726":1509788624469,"886784240":1444487341717,"1024333515724":1509788624469,"1021582356428":1478686417114,"1024333515722":1509788624469,"1024333515720":1509788624469,"1024333515732":1509788624469,"1024333515731":1509788624469,"1022435227960":1478686417213,"1024333515730":1509788624469,"1025428141212":1509788624510,"4883175224":1509788624165,"1025428141215":1509788624510,"1024333515728":1509788624469,"1024333515742":1509788624469,"1024333515739":1509788624469,"886784229":1444487341729,"1022600635247":1509788624200,"1024333515736":1509788624468,"1024333515686":1509788624468,"1024333515685":1509788624468,"1022600635154":1509788624200,"1024333515683":1509788624468,"1024333515680":1509788624468,"1020891874626":1509788624971,"1021691532594":1478686417121,"1021691532595":1478686417121,"1020986508080":1478686417088,"1013178274451":1478686804049,"1021660998410":1509788624815,"1024333515655":1509788624468,"1024333515653":1509788624468,"1021660998451":1509788624419,"1024333515652":1509788624468,"1024333515651":1509788624468,"1024333515649":1509788624468,"1025749657592":1509788624350,"1024333515648":1509788624468,"1024333515659":1509788624468,"1838750198":1478950494926,"1016491925307":1465470268235,"1025428141276":1509788624437,"1024333515666":1509788624468,"1023306708302":1509788625101,"1024333515665":1509788624468,"1025428141265":1509788624432,"1025428403420":1509788624421,"1025428403422":1509788624421,"1020918482922":1478686417081,"1024333515675":1509788624468,"1025428141268":1509788624466,"1024333515674":1509788624468,"1022075833572":1509788624530,"1008869020114":1509788624928,"1025270071989":1509788624532,"1024313199037":1509788624927,"1025270071988":1509788624532,"1019422912056":1478686804019,"1023995485839":1491634246529,"1025270071990":1509788624531,"1022416091349":1478686804071,"1025270071985":1509788624532,"1022416091348":1478686804071,"1025270071987":1509788624532,"1025270071986":1509788624532,"1025270071996":1509788624531,"1024333515629":1509788624468,"1025270071998":1509788624532,"1025270071993":1509788624531,"1024333515626":1509788624468,"1025270071992":1509788624531,"1024333515625":1509788624468,"1946353811":1444487341727,"1022072425534":1478686417271,"1024333515639":1509788624468,"1009331041450":1509788624929,"1025428403254":1509788624422,"1024333515632":1509788624468,"1024333515647":1509788624468,"1025270071983":1509788624532,"1024333515644":1509788624468,"1025270071982":1509788624531,"1022272958532":1478686417285,"1023995485840":1491634246529,"1025428403256":1509788624422,"1024333515641":1509788624468,"1018089143962":1478686804026,"1025428403204":1509788624421,"1025428403208":1509788624421,"1023934010214":1491634246531,"1022424873246":1478686417070,"1023995485872":1491634246532,"1025428403227":1509788624421,"1025428403226":1509788624421,"1022654115520":1509788625101,"1025270072055":1509788624915,"1025270072054":1509788624915,"1025270072049":1509788624915,"1025270072061":1509788624871,"1025270072060":1509788624871,"1025270072062":1509788624821,"1021420479814":1478686417007,"1025270072057":1509788624871,"1008906769341":1465470268235,"1025507963191":1509788624339,"1025507963188":1509788624341,"1025507963187":1509788624346,"1021416809754":1478686417007,"1022049092332":1478686804072,"1025507963193":1509788624336,"1025507963192":1509788624343,"405892305":1478686804029,"1009994783848":1491634246520,"1018546704926":1480585069063,"1923810885":1491634246517,"1025715578231":1509788625107,"1025270072004":1509788624531,"1025715578230":1509788625123,"1025715578229":1509788625114,"1022486734056":1478943089489,"1025428403293":1509788624421,"1025270072012":1509788624532,"1021803076644":1478686416986,"395797354":1444487341706,"1025428403290":1509788624421,"1025270072010":1509788624531,"1025715578232":1509788625087,"1025428141480":1509788624510,"1021260575287":1478686804046,"1025428141484":1509788624510,"1025428141487":1509788624433,"992169514":1444487341701,"1021892335717":1478686417138,"1019916517921":1509788624932,"1021502268346":1478686417244,"1022454495991":1478686417297,"1020465507718":1509788624309,"1020465507719":1509788624309,"1020465507717":1509788624309,"1025428141498":1509788624434,"1020944826615":1478686417229,"1025428141489":1509788624433,"1021964026939":1478686417148,"1022047912766":1478686417011,"1020465507720":1509788624309,"1020465507721":1509788624309,"1025428141494":1509788624424,"1021542509920":1478686417047,"1021542509925":1478686417047,"1022076882255":1478686417061,"1022128524880":1478686417063,"1015188629552":1465470268313,"1019739576566":1509788624173,"1025270072068":1509788624915,"1025270072071":1509788624871,"1025270072070":1509788624824,"1025270072064":1509788624835,"1025270072067":1509788624821,"1025270072066":1509788624835,"1022076882258":1478686417061,"1022076882262":1478686417061,"1025270072074":1509788624915,"1025428141548":1509788624437,"1025270072179":1509788624269,"1020999486954":1478686417088,"1025270072189":1509788624269,"1025428141536":1509788624432,"1020999486952":1478686417088,"1025270072190":1509788624234,"1025428141538":1509788624432,"1025270072185":1509788624269,"1025428141541":1509788624466,"1024327355144":1509788625086,"1020999486956":1478686417089,"1001061181021":1478686417022,"1025428141513":1509788624432,"1024333515397":1509788624468,"4887500339":1509788624165,"1024333515396":1509788624468,"1024333515395":1509788624468,"1025428141519":1509788624432,"1024333515393":1509788624468,"1018509481583":1509788624426,"1024333515392":1509788624468,"1025428141505":1509788624427,"1024333515407":1509788624468,"1024333515406":1509788624468,"1024333515401":1509788624468,"1025428141529":1509788624432,"1298085933":1478686417024,"1025428141533":1509788624432,"1019810350327":1509788624321,"1022097722462":1478686417275,"1022416091433":1478686804071,"1022416091432":1478686804071,"1022192880359":1478686417188,"1025428141526":1509788624432,"1024333515366":1509788624468,"1025715577861":1509788624185,"1025715577860":1509788624197,"1024333515364":1509788624468,"1021583011454":1478686417114,"1025715577859":1509788624203,"1021902953281":1478686417010,"1025715577858":1509788624200,"1024333515361":1509788624468,"1024333515374":1509788624468,"1025270072252":1509788624508,"1006890195509":1478686804064,"1024459535343":1509788625029,"1025270072254":1509788624508,"1024333515370":1509788624468,"1024333515368":1509788624468,"1024333515383":1509788624468,"1020914550336":1478686417032,"1024333515381":1509788624468,"1024333515380":1509788624468,"1020914550342":1478686417032,"1021617875026":1478686417117,"1025270072224":1509788624269,"1021278272920":1478686804039,"1024333515391":1509788624468,"1025428403516":1509788624421,"1024333515387":1509788624468,"1025428403512":1509788624421,"1024333515386":1509788624468,"1025270072211":1509788624197,"1020853082846":1509788625068,"1025270072220":1509788624198,"1025428403468":1509788624421,"1025270072223":1509788624269,"1022879423769":1509788625053,"1025270072222":1509788624234,"1025428403470":1509788624421,"1025270072216":1509788624269,"1021465436488":1478686417045,"1025019335351":1509788625006,"1025270072199":1509788624234,"1025270072193":1509788624234,"1022193797669":1478686416975,"1021660998375":1509788624194,"1025607450542":1509788624455,"1024333515359":1509788624468,"888226120":1478686804051,"1024333515358":1509788624468,"1533882070":1478686417020,"1025270072206":1509788624206,"1022100212922":1478686417275,"1025270072201":1509788624206,"1025270072200":1509788624197,"1021465436487":1478686417045,"1024116066109":1509788667890,"1025609416250":1509788625129,"1025609416248":1509788625105,"1022416091541":1478686804071,"1025428403552":1509788624421,"1022416091543":1478686804071,"1022416091542":1478686804071,"1025428403554":1509788624421,"1022416091544":1478686804071,"1025609416235":1509788625168,"1024370275331":1509788624926,"1025609416239":1509788625171,"1024014227769":1509788667884,"1023018354065":1509788625048,"1025609416231":1509788625130,"1022195370651":1478686417280,"1025609416212":1509788625131,"1025609416202":1509788625131,"1025270072263":1509788624433,"1021967828760":1509788624464,"1025270072257":1509788624461,"1025270072258":1509788624461,"1008849096965":1478686804025,"951668034":1478686417020,"1019899478953":1509788624353,"1020294200148":1465470268296,"1019174665881":1509788624375,"1022212404854":1478686417191,"1025399703665":1509788624294,"1022406916822":1478686417207,"1022212404857":1478686417191,"1022507836631":1509788624936,"1025876405279":1509788667478,"1022406916861":1478686417208,"1023319815250":1509788624288,"1020972744824":1509788624940,"1021885520854":1478686417044,"1022406916858":1478686417208,"1009220947075":1478686804030,"1025876405305":1509788667478,"1022406916852":1478686417208,"1025609416145":1509788625143,"1025876405307":1509788667478,"1019206908849":1464448510786,"1009220947072":1478686804025,"1025876405306":1509788667478,"1012153049055":1478686417073,"1025607449643":1509788624229,"1020896462078":1478686417032,"1022406916837":1478686417208,"1023319815243":1509788624288,"1023319815242":1509788624289,"1021847378958":1478686417135,"1023319815241":1509788624288,"1025876405291":1509788667478,"1025876405293":1509788667478,"1025876405292":1509788667478,"1023319815245":1509788624280,"1025876405294":1509788667478,"1025609416123":1509788625165,"1009862661672":1491634246513,"1021260575096":1478686804046,"1025609416116":1509788625165,"1025876405313":1509788667478,"1023306708841":1509788624534,"1025609416105":1509788625243,"1025876405314":1509788667478,"1025428141821":1509788625244,"1019380441461":1509788625018,"1025428141822":1509788625245,"1025876405321":1509788667400,"4670578747":1478686416965,"1025609416098":1509788625243,"1025876405323":1509788667400,"1025876405322":1509788667400,"1021693105941":1509788624400,"1025609416090":1509788625244,"1020967502057":1478686417086,"1025788060464":1509788624972,"1022030873411":1509788625066,"1006004685837":1478686804046,"1023537002762":1509788624459,"1009862661639":1491634246514,"1011889860558":1478686804064,"1025560657589":1509788624344,"1023306708812":1509788624195,"1025399703553":1509788624294,"1025908386423":1509788667460,"1025732224002":1509788624942,"1017534324647":1444487341760,"1022415174348":1478686417209,"1021831913368":1478686417009,"1021831913371":1478686417009,"1022447679698":1478686804027,"1020465507894":1509788624309,"1020465507895":1509788624309,"1020465507893":1509788624309,"1021660998134":1509788624533,"1020006828896":1509788624361,"1020465507896":1509788624309,"1020465507897":1509788624309,"1001061180860":1478686417022,"1023846454367":1491634246537,"1025627765362":1509788624828,"1022236521552":1478686417193,"372072596":1491634246519,"1000363105380":1478686417024,"1022452791492":1478686804067,"1023306708979":1509788624818,"1021885520672":1478686417044,"1021600180778":1478686417048,"1021616827179":1478686417117,"1008351686777":1478686804023,"1022079241888":1478686417178,"1022966979467":1509788624224,"1022966979466":1509788624224,"1022966979465":1509788624224,"1022966979469":1509788624224,"1022966979468":1509788624224,"1021739766665":1478686417124,"1021684848336":1478686417050,"1023753661326":1509788625082,"1024313199135":1509788624927,"1024096536352":1509788624325,"1025428141952":1509788624437,"1020756090383":1478686417076,"1015638593298":1465470268314,"1022645071281":1509788625061,"1024313199231":1509788624927,"514025959":1478686417019,"514025963":1478686417019,"1022356323985":1478686804071,"1016800594357":1509788624976,"1022240847344":1478686417065,"1024913954332":1509788624342,"1025525133748":1509788624523,"1022803137641":1509788625055,"1025907731301":1509788667460,"514025972":1478686417019,"1018044710795":1509788625080,"1018706876447":1465470268242,"1023995092335":1491634246529,"1013081282541":1478686416978,"1016800594305":1509788624976,"1016800594325":1509788624976,"1019607847622":1509788624315,"1019607847624":1509788624313,"1016800594276":1509788624976,"1021941876510":1478686417260,"1016800594287":1509788624976,"1022356323917":1478686804071,"1022425266728":1478686417070,"1021721416750":1478686804047,"1001061180566":1478686417022,"4945432923":1509788624164,"1025428141836":1509788625127,"1025428141825":1509788625104,"1021123873022":1478686417095,"1025428141829":1509788625112,"1025428141851":1509788625127,"1025428141850":1509788625127,"4886451444":1509788624164,"1025009242133":1509788624287,"1022433655452":1478686417212,"1022439291252":1478686417016,"1020556864201":1478686417017,"1001061180637":1478686417022,"1022406916876":1478686417208,"1022416092037":1478686804067,"1025428141948":1509788624437,"828327561":1444487341742,"1021550505500":1478686416982,"1022406916869":1478686417208,"1022356323869":1478686804071,"1022406916864":1478686417208,"1022406916867":1478686417208,"1022406916866":1478686417208,"1022356323870":1478686804071,"1020235873732":1465470268180,"1025428141899":1509788624510,"1025428141903":1509788624510,"1022461311093":1478686416990,"1022100213483":1478686417275,"4558125148":1465469681390,"1025428141914":1509788624432,"1012641673530":1478686417074,"1002821716938":1478686417299,"1025428141918":1509788624432,"1025428141907":1509788624433,"1025428141908":1509788624424,"1022608502564":1509788624994,"1025428141911":1509788624434,"1024433978851":1509788624462,"1020986249057":1478686416985,"1003127568369":1478686804054,"1020323293384":1509788625078,"1019739575793":1509788624173,"1000038837809":1478686417021,"334851033":1478686417023,"1021660997480":1478686417050,"1021655885762":1509788624396,"1025530511055":1509788625116,"1025508097452":1509788624343,"1025508097450":1509788624340,"1025635496990":1509788624306,"1021966256469":1478686416983,"1025790291306":1509788624348,"1021588120530":1478686804050,"1021588120531":1478686804050,"1025530511059":1509788625088,"1025530511057":1509788625108,"1025530511056":1509788625125,"1025906025544":1509788667449,"1022056304586":1478686417173,"1021501746872":1509788624451,"1002300974414":1478686417018,"1020993326960":1478686417034,"1022998829050":1509788624434,"1009117662345":1478686804023,"1020791083916":1478686804050,"1001385189209":1480585069061,"1008678969750":1478686804030,"1012490159461":1478686417026,"122257375":1444487341748,"1024681438134":1509788625025,"1022477690917":1509788624513,"1022966978003":1509788625159,"1021354554685":1465470268232,"1022966978002":1509788625159,"1021354554686":1465470268232,"1022395904975":1478686417070,"1022966978001":1509788625159,"1022966978000":1509788625159,"1021354554682":1465470268232,"1022477690932":1509788624271,"1022477690934":1509788624613,"1022477690929":1509788624918,"1022966977999":1509788625159,"1021312086748":1509788624942,"1023317719635":1509788625103,"1025473100511":1509788624360,"1025473100510":1509788624360,"1025473100509":1509788624360,"1025473100508":1509788624360,"1021312086747":1509788624940,"1022541261840":1509788625063,"1021354554689":1465470268232,"1022018030899":1478686417057,"1023317719631":1509788625103,"4971909254":1509788624165,"1022282267851":1478686417014,"1023317719667":1509788625103,"1019028126400":1509788624316,"1023317719665":1509788625103,"1008155738818":1478686804030,"1019281353185":1509788624388,"1012134174688":1478686417223,"1025473100522":1509788624359,"1025473100521":1509788624359,"1025473100520":1509788624359,"1000038837989":1478686417021,"1025473100515":1509788624360,"1025473100514":1509788624360,"1025473100513":1509788624360,"1025473100512":1509788624360,"1022068097047":1509788624924,"1025473100519":1509788624360,"1024670952247":1509788667503,"1025473100518":1509788624360,"1025473100517":1509788624360,"1025906025683":1509788667449,"1025473100516":1509788624360,"1022344786326":1478686417202,"1407920883":1491634246505,"1012134174225":1478686417223,"1021588120236":1478686804050,"1021588120237":1478686804050,"1020922546808":1478686417081,"1023306708995":1509788624420,"1021455870549":1509788624398,"1020781384351":1509788624319,"1010295194594":1491634246522,"1021885519027":1478686417044,"1022769584246":1509788624439,"1018987624901":1509788624312,"1023317720003":1509788625104,"1020825818186":1478686417226,"1025530511317":1509788624800,"1023317720009":1509788625104,"1025530511314":1509788624823,"1025530511313":1509788624833,"1024961273342":1509788624304,"1021438176252":1478686417007,"1021022683181":1478686417090,"1023143526791":1509788625045,"1021233053602":1478686417235,"262895150":1478686417024,"1025529593656":1509788624339,"1017612572427":1478686804053,"1017612572426":1478686804053,"1017612572425":1478686804053,"1017612572431":1478686804053,"1018279849813":1465470268270,"1017612572430":1478686804053,"1017612572429":1478686804053,"1017612572428":1478686804053,"1017612572435":1478686804053,"1016514336133":1478686804063,"1023855369207":1491634246537,"1017612572434":1478686804053,"1016514336132":1478686804063,"1025593291619":1509788624929,"1017612572432":1478686804053,"1016514336134":1478686804063,"1017612572438":1478686804053,"1016514336128":1478686804063,"1017612572437":1478686804053,"1016514336131":1478686804063,"1016514336130":1478686804063,"1016514336141":1478686804063,"1025569436101":1509788624350,"1016514336140":1478686804063,"1025569436100":1509788624350,"1025569436102":1509788624350,"1016514336137":1478686804063,"1016514336136":1478686804063,"1021562691729":1509788624401,"1016514336139":1478686804063,"1025314111499":1509788624327,"1025569436099":1509788624351,"1018279849799":1465470268270,"1016514336138":1478686804063,"1016284046962":1480585069064,"1025569173984":1509788624335,"1022811135245":1509788624352,"1022811921680":1509788624436,"1024973462647":1509788624174,"1022452791220":1478686804067,"4813449052":1509788624165,"1025783999528":1509788624352,"1016514336209":1478686804063,"1016514336208":1478686804063,"1016514336211":1478686804063,"1016514336210":1478686804063,"1022274403698":1478686417285,"1016514336196":1478686804063,"1016514336199":1478686804063,"1016514336198":1478686804063,"1016514336195":1478686804063,"1016514336194":1478686804063,"1016514336205":1478686804063,"1016514336204":1478686804063,"1016514336207":1478686804063,"1016514336206":1478686804063,"1016514336201":1478686804063,"1016514336200":1478686804063,"1020194451808":1509788625078,"1016514336202":1478686804063,"1020823721179":1478686417226,"1020805240251":1478686417077,"1021372118940":1478686417006,"1021837153066":1478686416979,"1025569567323":1509788624349,"1025628944080":1509788624460,"1021155326838":1465469681393,"1021155326844":1465469681394,"1000307792925":1478686417018,"1025628944090":1509788624460,"1019908787627":1509788625077,"1025628944093":1509788624460,"1363487562":1444487341738,"1021155326843":1465469681394,"1014487928527":1478686804016,"1020984151451":1478686417034,"1025373620218":1509788624304,"1020891089697":1478686417032,"1025628944068":1509788624460,"1025628944070":1509788624460,"1021421529997":1509788624817,"1025628944073":1509788624460,"1020984151447":1478686417034,"1020984151470":1478686417034,"1020984151457":1478686417034,"1000038837298":1478686417021,"1012120673740":1478686416993,"1022198908176":1478686804049,"1020984151472":1478686417034,"1025628944105":1509788624460,"1020984151473":1478686417034,"1025394066667":1509788667826,"1025628944108":1509788624460,"1025428142828":1509788625244,"1025428142830":1509788625245,"1022966978355":1509788624860,"1024313460592":1509788624179,"1022966978354":1509788624860,"1020917565898":1478686417081,"1022966978353":1509788624860,"1022966978352":1509788624860,"1022966978357":1509788624860,"1025428142842":1509788625113,"1025428142844":1509788625127,"1025428142835":1509788625128,"1025428142838":1509788625129,"1019324083965":1509788624302,"1025628944050":1509788624460,"1025628944053":1509788624460,"1022517143630":1480585069099,"1022517143629":1480585069099,"1025628944061":1509788624460,"1025628944060":1509788624460,"1021680654954":1478686804027,"1025628944063":1509788624460,"1021524421894":1478686417113,"1022231673693":1478686417193,"1022517143640":1480585069099,"1021312086120":1509788624932,"1021312086123":1509788624940,"1022517143635":1480585069099,"1022897116157":1509788667843,"1022897116156":1509788667843,"1022517143632":1480585069099,"1022517143639":1480585069099,"1022517143637":1480585069099,"1021281678259":1478686416972,"1022517143636":1480585069099,"1022015278758":1509788625067,"1024245040062":1509788625016,"1020599851526":1478686416979,"1023835839270":1491634246504,"1021417204549":1478686417241,"1025524612161":1509788624973,"1025524612160":1509788624998,"1017132592017":1478686804021,"1022966978496":1509788624449,"1022966978491":1509788624449,"1022192354630":1478686417188,"1022966978494":1509788624449,"1022966978493":1509788624449,"1024737013053":1509788624520,"1022966978492":1509788624449,"1022966978482":1509788624563,"1022452790474":1478686804067,"1022966978475":1509788624563,"1022462358971":1478686417218,"1022966978479":1509788624563,"1363487635":1444487341740,"1025524612159":1509788624999,"1022966978476":1509788624563,"1025524612158":1509788624998,"1022966978467":1509788624563,"1363487641":1444487341739,"1478435523":1478686417020,"1021841477748":1478686417257,"1012312557724":1478686417026,"1021920515360":1509788624465,"1022435227150":1478686417213,"1022032318012":1478686417166,"1000038837518":1478686417021,"1018829032708":1478686804023,"1020738523958":1478686417075,"1015430715284":1480585069075,"1019908525243":1509788624321,"1023934012661":1491634246531,"1020882176671":1478686417079,"1022029696638":1478686417058,"1023626653487":1509788625144,"1023819455399":1509788625082,"1021956819613":1478686417147,"1022466815002":1478686417218,"1022323162345":1478686417200,"1025791471155":1509788624428,"1023317719463":1509788624197,"1025791471157":1509788624425,"1023317719462":1509788624197,"1025791471156":1509788624431,"1025791471159":1509788624406,"1025533525334":1509788624347,"1020851770452":1478686417078,"1022210964308":1478686417191,"1022296292912":1478686417199,"1022384238975":1478686417290,"4887500826":1509788624165,"1022384238971":1478686417290,"1020496962042":1509788625076,"1025507442360":1509788624337,"1025507442359":1509788624338,"1025513078496":1509788624340,"1027792909961":1528271775279,"1025513078489":1509788624335,"1025513078495":1509788624337,"1021530844283":1478686417047,"1298085425":1478686417024,"1022871559288":1509788624381,"1023931784332":1491634246530,"1023931784334":1491634246530,"1010624181877":1509788625017,"360279557":1444487341719,"651648427":1444487341745,"1000038837602":1478686417021,"1010581188801":1478686804034,"1025297728492":1509788624566,"4997861997":1509788667399,"1025297728484":1509788624546,"1025297728483":1509788624546,"1025515831009":1509788624346,"1025428142908":1509788624510,"248739141":1478950494908,"1025507180431":1509788624339,"1025507180430":1509788624340,"1025428142857":1509788625127,"1025297728457":1509788624612,"1025297728453":1509788624613,"1021920515187":1509788624465,"1025428142872":1509788625135,"1025297728477":1509788624546,"1025297728473":1509788624553,"1020851770587":1478686417078,"1016758255830":1478686804031,"1025428142864":1509788625127,"1022265489553":1478686417285,"1001061181617":1478686417022,"1025297728465":1509788624565,"1009321605987":1478686804064,"1025428142944":1509788624436,"1022369952475":1509788624300,"1025428142951":1509788624437,"1022089462373":1478686417180,"1023877519587":1491634246512,"1016871893363":1509788624977,"1012641676566":1478686417074,"1025841275859":1509788667452,"1020688850685":1509788624933,"1021502664061":1478686417046,"1021803074361":1478686416986,"1022252382706":1509788624176,"1022245960080":1478686417066,"1022252382710":1509788624176,"1024330368479":1509788625007,"1025428142912":1509788624510,"1022125637737":1478686417183,"1025428142937":1509788624432,"1023299238521":1509788625041,"1025428142940":1509788624432,"1025428142943":1509788624466,"1022317002190":1478686417068,"1022452790777":1478686804067,"1022245960076":1478686417066,"1025428142928":1509788624427,"1025428142931":1509788624432,"1025428142932":1509788624432,"1022737999100":1509788625057,"1024501609955":1509788624443,"1024434239974":1509788624262,"1024501609954":1509788624443,"1025297728622":1509788625246,"1024501609953":1509788624443,"1024434239972":1509788624262,"1024501609952":1509788624443,"1024434239969":1509788624262,"1024434239983":1509788624262,"1024434239982":1509788624262,"1024434239981":1509788624262,"1024434239980":1509788624262,"1024434239979":1509788624262,"1024434239977":1509788624262,"1025478082464":1509788624543,"1021354291592":1465470268230,"1024434239991":1509788624262,"1021354291593":1465470268230,"1024434239990":1509788624262,"1025297728637":1509788625133,"1024434239988":1509788624262,"1012163794260":1478686416994,"1021354291588":1465470268230,"1025297728626":1509788625244,"1020922548042":1478686417081,"543251524":1478686417019,"1026224788253":1514456869768,"1013113527967":1465470268252,"1024434239958":1509788624262,"1024434239957":1509788624262,"1024434239956":1509788624262,"1024434239955":1509788624262,"1024434239954":1509788624262,"1024434239967":1509788624262,"1358638274":1491634246519,"1024434239966":1509788624262,"1024434239963":1509788624262,"1024501609951":1509788624443,"651647720":1444487341725,"1019423041163":1478686804026,"1021828371738":1509788624541,"1025297728555":1509788624208,"1025297728552":1509788624208,"1025478082536":1509788625089,"1025478082533":1509788625126,"1025297728547":1509788624208,"1022780858049":1509788624983,"1020969339450":1478686804066,"1024501609911":1509788624554,"1024633465939":1509788625026,"1022350029940":1478686417069,"1020969339451":1478686804066,"1024501609910":1509788624554,"1020969339448":1478686804066,"1025297728569":1509788624230,"1024501609909":1509788624554,"1326265178":1444487341731,"1020969339446":1478686804066,"1024501609914":1509788624554,"1020969339445":1478686804066,"1024501609912":1509788624554,"1024856285824":1509788624949,"1025478082501":1509788624429,"1025297728543":1509788624208,"1024322896633":1509788667836,"1025297728538":1509788624209,"1025297728537":1509788624215,"1025297728535":1509788624228,"1025297728532":1509788624228,"1025297728531":1509788624270,"1025297728530":1509788624271,"1021678296234":1509788625199,"1021348524403":1478686417104,"1021678296235":1509788625200,"1021362811294":1478686417042,"1021678296236":1509788625200,"1021678296238":1509788625200,"1025478082339":1509788624824,"1022077142251":1478686417271,"1025478082337":1509788624829,"1023728494232":1509788625082,"1021678296248":1509788625200,"1022118299264":1478686417276,"1022454100862":1478686417297,"1021678296251":1509788625199,"1021678296252":1509788625199,"1021678296253":1509788625199,"1025050924466":1509788624457,"1022359074095":1478686417203,"1023725086387":1491634246523,"1024501609851":1509788624216,"1024935583389":1509788625006,"1021678296241":1509788625200,"1021678296243":1509788625200,"1024501609855":1509788624216,"1024501609854":1509788624216,"1025285016524":1509788624328,"1021678296245":1509788625199,"1021356388838":1465469681398,"1024501609853":1509788624216,"1021678296246":1509788625200,"1024501609852":1509788624216,"1021678296247":1509788625200,"1024935583397":1509788625006,"1025297728713":1509788624868,"1022263263207":1478686417067,"1025297728704":1509788624839,"1019596577011":1509788624940,"1024935583414":1509788625006,"1024935583408":1509788625006,"1024935583422":1509788625006,"1020136650931":1480585069064,"1025869850292":1509788667715,"1025297728683":1509788624865,"1025297728682":1509788624916,"1025297728680":1509788624917,"1024935583426":1509788625007,"1025478082404":1509788624186,"1025478082403":1509788624205,"1024935583447":1509788625006,"1025297728699":1509788624839,"1024935583442":1509788625006,"1025297728695":1509788624839,"1020805369995":1478686417030,"1025297728691":1509788624839,"1021510920953":1478686417047,"1025297728688":1509788624849,"1024935583460":1509788625006,"1021678296265":1509788625200,"1021678296266":1509788625200,"1022416089266":1478686804065,"1022454493955":1478686417297,"1021476841675":1478686417109,"1021678296256":1509788625200,"1022312807056":1478686417200,"1024935583470":1509788625007,"1025593292317":1509788624929,"1025297728642":1509788625133,"1021678296261":1509788625200,"1021678296262":1509788625200,"1025810082571":1509788667457,"1021979627193":1478686417151,"1022055779143":1478686417270,"1021678296263":1509788625200,"1025297728666":1509788625169,"1021476841687":1478686417109,"1022182785728":1478686417063,"1022055779154":1478686417270,"1025142281001":1509788624566,"1025297728656":1509788625133,"1024434239719":1509788624261,"1022092739733":1478686417062,"1024434239716":1509788624261,"1024434239715":1509788624261,"1024434239714":1509788624261,"1024434239713":1509788624261,"1024434239712":1509788624261,"1024434239727":1509788624262,"1024434239726":1509788624261,"1021301864370":1478686417238,"1024434239725":1509788624261,"1012544290231":1478686417223,"1024434239723":1509788624261,"1024434239722":1509788624261,"1021120070300":1478686417037,"1024434239720":1509788624261,"1020831847343":1478686416998,"918768592":1491634246511,"1022416089412":1478686804065,"1000687283":1491634246518,"1024434239729":1509788624262,"1024434239728":1509788624261,"1021509610360":1478686417007,"1011851979485":1444487341758,"1021113647808":1465469681399,"1024434239703":1509788624261,"1024434239711":1509788624262,"1023317721003":1509788624421,"1024434239709":1509788624262,"1024434239707":1509788624262,"1024973330680":1509788624288,"1024434239705":1509788624262,"1023317721005":1509788624421,"1024434239704":1509788624262,"1016433857920":1478686804017,"1016433857925":1478686804017,"1021606207952":1509788624817,"1021183246059":1478686417098,"1016433857926":1478686804019,"1023418905900":1509788624285,"1016433857931":1478686804016,"1009744438472":1491634246512,"1016433857942":1478686804016,"1019241771581":1509788624282,"1021608567085":1478686417008,"4997862533":1509788667399,"1019260644652":1509788624316,"1016433857962":1478686804019,"1022389614251":1478686417070,"1023947117953":1491634246532,"1023947117952":1491634246532,"1023386925825":1509788624440,"811027748":1509788625016,"1025906286941":1509788667461,"1025906286943":1509788667461,"1025906286942":1509788667463,"1025530510085":1509788624428,"1023829810272":1509788624940,"1023947117951":1491634246532,"1023947117949":1491634246532,"1021059516049":1478686417002,"1021445124013":1478686417242,"1024434239559":1509788625215,"1023829810254":1509788624940,"1025530510123":1509788624524,"1024434239554":1509788625215,"1024332465072":1509788624206,"1025530510120":1509788624543,"1024434239552":1509788625215,"1024434239567":1509788625216,"1024434239566":1509788625215,"1024434239565":1509788625215,"1024434239564":1509788625215,"1021989064214":1478686417154,"1024919723175":1509788624432,"1023829810269":1509788624939,"1024919723174":1509788624429,"1021879751070":1478686417136,"1018546707273":1480585069063,"1021989064221":1478686417154,"1024919723176":1509788624426,"1023829810258":1509788624940,"1024434239527":1509788625215,"1024434239526":1509788625215,"1024434239524":1509788625216,"1024434239522":1509788625216,"1021988933219":1478686417154,"1024434239520":1509788625215,"1024434239534":1509788625215,"1020616105042":1478686417075,"1020616105044":1478686417075,"1021857601109":1478686417053,"1024434239530":1509788625215,"1024208341683":1509788667888,"1018928120315":1509788624368,"1022374016771":1478686417069,"1024434239541":1509788625215,"1024434239539":1509788625215,"1024434239537":1509788625215,"1025818995364":1509788667457,"1019454365959":1478686804021,"1024434239546":1509788625215,"1024434239545":1509788625215,"1024434239544":1509788625215,"1025472708584":1509788625126,"1016959711874":1478686804063,"1023324405734":1509788624925,"1021627179172":1478686417049,"1022452134910":1478686417215,"1025530510199":1509788624201,"1021854455208":1509788625012,"1021854455210":1509788625012,"1021384831406":1478686417006,"1021854455212":1509788625012,"1021854455215":1509788625012,"1025627894473":1509788624210,"1021854455203":1509788625012,"1021854455204":1509788625013,"1021854455205":1509788625013,"1021854455206":1509788625012,"1021854455207":1509788625012,"1021854455226":1509788625012,"1021854455227":1509788625012,"1021854455229":1509788625012,"1021854455218":1509788625012,"1025883743645":1509788667451,"1025010817431":1509788624461,"420570929":1478950494909,"1021821425539":1478686417053,"1022231805710":1478686417193,"1020150152046":1478686804031,"1022092740519":1478686417062,"1022466814228":1478686417218,"1021905965306":1509788624561,"1021905965307":1509788624561,"1020918222297":1478686417228,"1021905965305":1509788624561,"1021905965309":1509788624561,"1009848508684":1491634246513,"1025630384875":1509788624304,"1023606336778":1509788624552,"4997863347":1509788667398,"1024501610427":1509788625148,"1022039656699":1478686416990,"1025283967259":1509788624272,"1024501610425":1509788625148,"1025283967261":1509788624272,"1024501610431":1509788625148,"1024501610429":1509788625148,"1024501610428":1509788625148,"1025283967264":1509788624272,"1021287184380":1478686417101,"1021854455244":1509788625012,"1023946332540":1491634246531,"1021854455247":1509788625012,"1021854455235":1509788625012,"1023064624610":1509788625073,"1021854455236":1509788625012,"1021854455238":1509788625012,"1022701822810":1509788625059,"1021287184359":1478686417101,"1008612256662":1478686804030,"1021468060246":1478686417108,"1021468060253":1478686417108,"1022871558533":1509788624378,"1024529528023":1509788625175,"1022259330333":1478686417067,"1018893255869":1509788624971,"1022124328232":1478686417276,"1022076880586":1478686417061,"1022076880587":1478686417061,"1024529528056":1509788625175,"1022076880584":1478686417061,"1022076880585":1478686417061,"1022076880590":1478686417061,"1024256836656":1509788624491,"1022202969678":1478686417280,"1024256836658":1509788624491,"1022076880582":1478686417061,"1022076880583":1478686417061,"1021468060256":1478686417108,"1021468060258":1478686417108,"1025515698978":1509788624336,"1022452789437":1478686804027,"858869235":1491634246515,"1021786560786":1509788624997,"1021991423308":1478686417265,"1020614664038":1478686417027,"1021991423318":1478686417265,"1021905965147":1509788624220,"1021905965150":1509788624220,"1021294655468":1478686416981,"1021905965148":1509788624221,"1022287117062":1478686417067,"1021905965149":1509788624221,"1023000138128":1509788624462,"1010295194715":1491634246522,"1020791084037":1478686804067,"1025791470093":1509788624832,"1025791470092":1509788624827,"1025791470095":1509788624616,"1025791470094":1509788624822,"1022909961680":1509788624298,"1024577237581":1509788667501,"1021608567621":1478686417008,"1023251398994":1509788625083,"1024247531071":1495284743423,"1022462357585":1478686417217,"1022452789578":1478686804027,"1619206107":1478686417020,"1619206104":1478686417020,"1619206115":1478686417020,"1024918412905":1509788624844,"1021588120811":1478686804065,"1021683408537":1478686417249,"1020556862057":1478686417017,"1009712982030":1491634246533,"1008667829803":1478686804022,"1021768341828":1509788624400,"1020808123270":1478686417030,"1025607972255":1509788625136,"1021513935239":1478686417112,"1021363073677":1509788624394,"1025632744240":1509788624349,"1024918412972":1509788625000,"1020991883418":1478686417088,"1012141119333":1478686416994,"1020909440479":1478686416999,"1021699661093":1478686417250,"1708857884":1444487341748,"1021300553067":1478686416982,"1333866570":1444487341741,"1016578166752":1478686804022,"1022031399658":1478686417165,"1020918221947":1478686417228,"1021699661071":1478686417250,"1018969669704":1509788624313,"1021850653713":1480585172195,"1021797046477":1478686417130,"1020909440480":1478686416999,"1021935456009":1509788624465,"1708857892":1444487341717,"1024512297310":1509788624443,"1024512297309":1509788624443,"1024512297308":1509788624443,"1024512297307":1509788624443,"1025626950859":1509788624544,"1024512297306":1509788624443,"1025626950856":1509788624544,"1025626950849":1509788624544,"1025626950848":1509788624544,"1021392015178":1478686416984,"1024785586435":1509788624436,"1025798264485":1509788624866,"1014535927747":1478686804052,"1024529730167":1509788624440,"1021117546384":1465470268306,"1014535927748":1478686804052,"1025626950885":1509788624548,"1024253622912":1509788624178,"1022451355160":1478686417296,"1025626950880":1509788625005,"1021398831280":1509788624394,"1021682868645":1478686417121,"1021682868642":1478686417121,"1021901631165":1509788624817,"1023638754619":1509788624964,"1022850868746":1509788625053,"1021514307142":1509788624815,"1021698466126":1478686417121,"1022056691682":1478686417270,"1010024557230":1491634246521,"1006574492675":1478686804025,"1020194785503":1509788625020,"1025626950846":1509788624551,"1021544454228":1509788624977,"1025626950845":1509788625002,"1022056691654":1478686417270,"1025626950839":1509788624544,"1025626950837":1509788624612,"1022471409816":1478686417219,"1025626950832":1509788624612,"1021901631094":1509788624195,"1024895688950":1509788624303,"1021022910924":1478686417091,"1024895688945":1509788624303,"1019981069293":1465470268236,"1021803063418":1478686804046,"1022034540104":1478686417167,"1021341289710":1478686417005,"1024607981370":1509788667589,"1019761126944":1509788624315,"1022455418692":1478686417216,"1021575256717":1478686417245,"1021575256719":1478686417245,"1021661241312":1478686804032,"1021096312373":1478686417036,"1021901631030":1509788624534,"1023821603005":1491634246536,"4951877631":1509788624154,"1021575256720":1478686417245,"1021575256723":1478686417246,"1023638754704":1509788624964,"1499060663":1478686417023,"1003492156627":1478686417220,"1021721404233":1478686804047,"1023638754698":1509788624964,"1021688857":1478950494920,"1022433659942":1478686417016,"1025219441212":1509788625230,"1025219441215":1509788625230,"1024280492598":1509788625080,"1022074780035":1478686417271,"1025219441203":1509788625230,"1021793232510":1478686417129,"1022074780039":1478686417271,"1025219441195":1509788625230,"1025219441197":1509788625230,"1025219441199":1509788625230,"1022135729651":1478686417013,"1025219441184":1509788625230,"1025219441187":1509788625230,"1025219441189":1509788625230,"1025219441191":1509788625230,"1021980930877":1478686417056,"1025219441190":1509788625230,"1020770200424":1478686417076,"1021468300684":1478686417109,"4959479480":1509788624155,"1025219441178":1509788625230,"1025219441181":1509788625230,"1012492876937":1478686417026,"1021468300681":1478686417108,"1006867967950":1509788624388,"1025219441180":1509788625230,"1021315468014":1465470268208,"1010024557546":1491634246521,"1021315468015":1465470268208,"1025219441182":1509788625230,"1018182996394":1465470268238,"1021468300679":1478686417108,"1025219441173":1509788625230,"1025219441175":1509788625230,"1022073862555":1509788624426,"1016092496396":1509788624941,"1025626951161":1509788624270,"1023149586862":1509788625044,"1021315468016":1465470268208,"1021260678708":1478686417101,"837398736":1444487341736,"1021315468017":1465470268208,"1016870290407":1478686804028,"1025626951157":1509788624270,"1025596803969":1509788624930,"1024895688996":1509788624303,"1017558166174":1509788624366,"1024895688993":1509788624303,"1022339156354":1509788624922,"1022458564334":1478686417217,"1025626951048":1509788624835,"1024781129745":1509788624442,"1022339156367":1509788624959,"1024781129744":1509788624442,"1022339156366":1509788624922,"1024781129747":1509788624442,"1024781129746":1509788624442,"1022339156363":1509788624922,"1024895689000":1509788624303,"1022339156362":1509788624922,"1024781129750":1509788624442,"1022339156371":1509788624923,"1025626951065":1509788624843,"1022339156368":1509788624923,"1012127704624":1478686417025,"1012583711488":1478686417223,"1024895688965":1509788624303,"1024895688973":1509788624303,"1020777278101":1478686417076,"1022394600176":1509788624957,"1024895688981":1509788624303,"1024895688989":1509788624303,"1021655473668":1509788624404,"1021497923435":1478686417046,"1022467346080":1478686417299,"1021901631355":1509788625101,"1503254537":1444487341706,"1010024557404":1491634246521,"1010024557405":1491634246527,"1025626951004":1509788624998,"1010024557403":1491634246527,"1019863102950":1509788625076,"1010024557397":1491634246527,"1025626950998":1509788625002,"1010024557398":1491634246521,"1023791849419":1509788624177,"1019863102947":1509788625076,"1025626950993":1509788625002,"1000527721812":1444487341714,"1021410496901":1478686417106,"1022339156332":1509788624922,"1019863102929":1509788624354,"1022339156328":1509788624923,"1021175350166":1465470268187,"1019009286386":1509788624389,"1020362822401":1465470268302,"1019009286387":1509788624314,"1022339156342":1509788624923,"1022339156340":1509788624922,"1022339156338":1509788624922,"1022339156336":1509788624923,"1022054332024":1478686416977,"1303366676":1444487341742,"1022339156348":1509788624922,"1022339156346":1509788624923,"1023659464587":1509788625110,"1022339156344":1509788624922,"1012132816632":1478686417025,"1022450962414":1478686417215,"1603264092":1478686804024,"1024244578445":1509788624948,"1023150373263":1509788625045,"1020876501503":1509788624390,"4891976312":1509788624154,"1023969585225":1509788624176,"1023969585224":1509788624176,"1025626950973":1509788624916,"1023969585226":1509788624176,"1022074780030":1478686417271,"1023969585229":1509788624176,"1023969585228":1509788625016,"1023969585230":1509788624176,"1020876501486":1509788624390,"1020876501487":1509788624390,"1025626950966":1509788624916,"1020876501484":1509788624390,"1020876501485":1509788624390,"1020876501483":1509788624390,"1023969585223":1509788624177,"1023638755185":1509788624965,"1023638755189":1509788624965,"1025882151357":1509788667406,"1022204412618":1509788624920,"1023638755190":1509788624965,"1021698466588":1478686417121,"1025626951364":1509788625128,"1025626951361":1509788625128,"1025882151350":1509788667465,"1025626951391":1509788625167,"1023638755168":1509788624965,"1023638755171":1509788624964,"1010076200900":1491634246534,"1021714849802":1509788624193,"1023638755173":1509788624964,"1020831149247":1478686416998,"1020876501504":1509788624390,"1025626951385":1509788625136,"1023638755179":1509788624964,"1023638755178":1509788624964,"1019934407203":1478686804053,"1022457384388":1480585069113,"1023638755155":1509788624964,"1022136385242":1478686417184,"1023638755156":1509788624965,"1022719007748":1509788624268,"1023638755158":1509788624965,"1000860386605":1478686804059,"1021690471352":1478686417121,"1023638755165":1509788624965,"1023638755166":1509788624965,"1020876501538":1509788624390,"1022150934053":1478686417063,"1021831768888":1478686417134,"1025219441016":1509788624501,"1025219441019":1509788624501,"1025219441018":1509788624501,"1010472306296":1444487341757,"1025219441021":1509788624501,"1025219441020":1509788624501,"1010472306299":1444487341757,"1025219441022":1509788624501,"1021948555845":1478686417145,"1025219441008":1509788624501,"1019704371642":1509788624354,"1598283023":1444487341738,"1010472306289":1444487341757,"1025219441012":1509788624501,"1000860386634":1478686804059,"1025219441015":1509788624501,"1000860386644":1478686804059,"1023638755105":1509788624964,"1000860386645":1478686804059,"1023638755104":1509788624964,"1025626951325":1509788625244,"1023638755106":1509788624964,"1023638755108":1509788624964,"1000860386642":1478686804059,"1023638755111":1509788624964,"1025626951321":1509788625245,"1023638755110":1509788624964,"1024719000757":1509788624342,"1025219440992":1509788624501,"1000860386655":1478686804059,"1000860386648":1478686804059,"1025219440997":1509788624501,"1000860386651":1478686804059,"1025219440984":1509788624501,"1023638755091":1509788624964,"1023638755090":1509788624964,"1023638755093":1509788624964,"1025219440988":1509788624501,"1023638755095":1509788624964,"1020991059275":1478686417088,"1024132379023":1509788624324,"1023638755098":1509788624964,"1023638755101":1509788624964,"1023638755100":1509788624964,"1025219440983":1509788624501,"1009704867229":1478686804046,"1025219440982":1509788624501,"1025626951356":1509788625128,"1025626951353":1509788625110,"1025626951348":1509788625002,"1023900510123":1491634246510,"1023638755313":1509788624963,"1023638755312":1509788624963,"1023638755315":1509788624963,"1018182996486":1465470268238,"1021811845840":1478686417131,"1025626951241":1509788624210,"1006890249528":1478686804015,"1021714849945":1509788624419,"1015231800035":1480585069068,"1021831506819":1478686417256,"1025626951238":1509788624229,"1023638755320":1509788624963,"1021917883754":1509788624827,"1021253207318":1478686417237,"1023638755309":1509788624963,"1023638755311":1509788624963,"1021714849982":1509788624814,"1023638755283":1509788624963,"1023638755286":1509788624963,"1023638755289":1509788624963,"1021743556329":1509788624400,"1021497922630":1478686417244,"1010472306316":1444487341757,"1025219441033":1509788624501,"1023638755265":1509788624963,"1010472306318":1444487341758,"1025219441034":1509788624501,"1010472306315":1444487341757,"1023638755270":1509788624963,"1022733950434":1509788625074,"1010472306306":1444487341757,"1023638755279":1509788624963,"1025191522306":1509788624971,"1023638755251":1509788624963,"1025626951178":1509788624214,"1022988627195":1509788624544,"1013065014593":1478686416977,"1025626951171":1509788624214,"1020294007907":1465470268280,"1023638755233":1509788624963,"1023638755232":1509788624963,"1023638755234":1509788624963,"1021638827090":1478686417049,"123831735":1508316495865,"1023638755239":1509788624963,"1019166050621":1478686804027,"1023638755238":1509788624963,"1025626951191":1509788624998,"1021736478217":1509788624395,"1021278374627":1478686417237,"4861174623":1509788624154,"1022107678803":1478686417275,"1012132816338":1478686417025,"1760160257":1478686804024,"1025626951206":1509788624205,"1025798263893":1509788624848,"1023638755229":1509788624963,"1025626951200":1509788624205,"1018182996595":1465470268238,"982628454":1491634246505,"1025626951218":1509788624205,"1024388825531":1509788624383,"1024388825530":1509788624383,"1024512297553":1509788624560,"1023638754913":1509788624964,"1021262251014":1478686804039,"657695776":1444487341716,"1024512297548":1509788624560,"1023638754914":1509788624964,"1024512297547":1509788624560,"1023638754917":1509788624964,"1024512297546":1509788624560,"1023638754916":1509788624964,"1024512297544":1509788624560,"1023638754925":1509788624964,"1023638754924":1509788624964,"1023638754897":1509788624964,"1021661109371":1478686804054,"1023638754906":1509788624964,"1024067235051":1509788667496,"1023638754911":1509788624964,"1020868637505":1478686417227,"1021102472618":1509788624309,"1022757937864":1509788625057,"1021922208924":1509788624466,"1023638754894":1509788624964,"1013800208542":1478686804068,"1013800208534":1478686804068,"4951876717":1509788624153,"1024597626210":1509788624938,"1022719008110":1509788624269,"1023927117173":1491634246530,"1023927117172":1491634246530,"1021610123013":1509788624401,"1022204412846":1509788624920,"1022273882061":1478686417197,"137857872":1444487341747,"1020557860479":1478686417026,"1013800208560":1478686804069,"1013800208559":1478686804069,"1013800208558":1478686804068,"1016092495944":1509788624941,"1013800208555":1478686804068,"1020788680743":1478686417225,"1013800208553":1478686804068,"1013800208552":1478686804068,"1022454107287":1478686417216,"1013800208548":1478686804068,"1013800208545":1478686804068,"1023638755057":1509788624964,"1023786343684":1509788624301,"1023638755056":1509788624964,"1020605834166":1478686417075,"1023638755061":1509788624964,"1023638755060":1509788624964,"1023638755063":1509788624964,"1025896701778":1509788667463,"1025896701781":1509788667460,"1021968085366":1509788624390,"1023638755040":1509788624964,"1022230758095":1478686417282,"1023638755043":1509788624964,"1024321125687":1509788667494,"1025896701775":1509788667456,"1023638755047":1509788624964,"1025896701773":1509788667460,"1023638755046":1509788624964,"1024321125695":1509788667494,"1023638755050":1509788624964,"1021226075809":1478686417003,"1023638755052":1509788624964,"1023638755055":1509788624964,"1024132378700":1509788624324,"1023324307874":1509788624344,"1023638755039":1509788624964,"1021289646784":1478686417238,"1017573371721":1478686804028,"1023638754994":1509788624964,"1023638754998":1509788624964,"1021355708073":1478686417006,"1021693223563":1478686804046,"1023638754976":1509788624964,"1023638754979":1509788624964,"1023638754978":1509788624964,"1023638754982":1509788624964,"1022303110453":1478686417287,"1023638754985":1509788624964,"1012184459732":1478686417073,"1023638754989":1509788624964,"1021015833156":1478686417035,"1023638754963":1509788624964,"1023638754965":1509788624964,"1024783489744":1509788625021,"1023638754966":1509788624964,"1023009469209":1509788625073,"1024887825174":1509788624867,"1023638754970":1509788624964,"1023638754973":1509788624964,"1020973888982":1478686417086,"1022079499191":1478686417061,"1024512297638":1509788625153,"1024512297637":1509788625153,"1024512297636":1509788625154,"1024512297635":1509788625154,"1024512297634":1509788625153,"1023242648301":1509788624907,"1023638753648":1509788624964,"1023242648303":1509788624907,"1023242648302":1509788624907,"1023638753650":1509788624964,"1023638753653":1509788624964,"1023242648299":1509788624907,"1022068096234":1509788624924,"1023242648298":1509788624906,"1023638753656":1509788624964,"1025560628424":1509788624344,"1023242648317":1509788624907,"1023638753633":1509788624964,"1023242648316":1509788624907,"1019761650296":1509788624315,"1023242648318":1509788624907,"1019761650302":1509788624313,"1023242648313":1509788624907,"1023242648315":1509788624906,"1023638753639":1509788624964,"1023242648314":1509788624906,"1023638753638":1509788624964,"1021251896239":1478686417100,"1023638753640":1509788624964,"1023242648311":1509788624907,"1023638753643":1509788624964,"1023242648310":1509788624907,"1023638753642":1509788624964,"1023242648305":1509788624907,"1023242648304":1509788624907,"1023638753644":1509788624964,"1023242648307":1509788624907,"1023638753647":1509788624964,"1023242648306":1509788624907,"1023638753646":1509788624964,"1229442407":1478686417020,"1016399733480":1480585069069,"1229442401":1478686417020,"1022079106146":1478686417177,"1012100702500":1509788625016,"1024625153199":1509788625163,"1024088077474":1509788624467,"1024625153198":1509788625163,"1025993303348":1514456869773,"1025593265886":1509788624929,"1023638753601":1509788624966,"1023638753600":1509788624966,"1024625153201":1509788625163,"1229442418":1478686417020,"1024625153200":1509788625163,"1024625153203":1509788625163,"1021011115476":1478686417089,"1020365313621":1478686804022,"1025796952721":1509788624537,"1024568527321":1509788625026,"1023638753589":1509788624966,"4810578675":1509788624154,"1023638753592":1509788624966,"1021965989196":1478686417262,"1023638753595":1509788624965,"1021544455276":1509788625014,"1022204413060":1509788624920,"1023638753597":1509788624965,"1023638753596":1509788624965,"1021059088254":1478686417093,"1023638753599":1509788624966,"1023638753598":1509788624965,"1020365313599":1478686804028,"1023638753570":1509788624965,"1023638753572":1509788624966,"1023638753577":1509788624966,"1020912023464":1478686417032,"1025629047026":1509788624423,"1023638753582":1509788624966,"1021345745021":1478686417005,"1022241507034":1478686417195,"1523703479":1478686804024,"1001544725554":1478686804064,"1023638753541":1509788624965,"1022646656531":1480585069087,"1025593658955":1509788625001,"1021770424877":1478686417052,"1022719007398":1509788624268,"1025593658958":1509788624428,"1023062554403":1509788625048,"1019203799329":1478686804032,"1020419576286":1478686804028,"1022185274013":1478686417278,"1022248978089":1509788624485,"1022646656540":1480585069087,"1022646656515":1480585069087,"1022646656512":1480585069087,"1020805720248":1478686417030,"1025593658972":1509788624847,"1022646656522":1480585069087,"1024161738940":1509788667562,"1022021169476":1509788624824,"1022646656524":1480585069154,"1005500995788":1478686804061,"1005500995790":1478686804061,"1005500995785":1478686804061,"1005500995784":1478686804061,"1005500995786":1478686804061,"1023043941997":1509788625048,"1760160832":1478686804024,"1005500995780":1478686804061,"1005500995782":1478686804061,"1005500995777":1478686804061,"1005500995778":1478686804061,"1018517757985":1480585069070,"1022646656547":1480585069087,"1025593659002":1509788624998,"1025593659000":1509788624998,"1025593659004":1509788624826,"1005500995797":1478686804061,"137858190":1444487341743,"1005500995795":1478686804061,"1021672514628":1509788624400,"1022442310244":1478686417214,"1022238623232":1509788624941,"1005500995773":1478686804061,"1005500995775":1478686804061,"1005500995768":1478686804061,"1005500995765":1478686804061,"1024662771359":1509788624862,"1021340502167":1465470268223,"1021191079818":1478686417098,"1025530741355":1509788624834,"1025530741353":1509788624829,"1024662771364":1509788624862,"1024662771362":1509788624862,"1024662771361":1509788624863,"1022282924230":1478686417198,"1025530741356":1509788624823,"1024662771360":1509788624862,"1021958518140":1509788624178,"1021933876252":1478686804068,"1021933876248":1478686804068,"1025710970169":1509788624307,"1021933876242":1478686804068,"1025530741364":1509788624800,"1022238885824":1509788624931,"1022238885826":1509788624933,"1023561815273":1509788624531,"1025616072325":1509788624929,"1021831900182":1478686417134,"1021831900186":1478686417134,"1022185143050":1478686417013,"1021831900193":1478686417134,"1021860474479":1478686417053,"1023638753365":1509788624965,"1020063843648":1509788625081,"1021122394726":1478686417095,"1023638753369":1509788624965,"1020444611321":1478686804066,"1023638753371":1509788624965,"1022051578563":1478686417269,"1023638753372":1509788624965,"1023638753374":1509788624965,"1023638753344":1509788624965,"1023638753347":1509788624965,"1023638753346":1509788624965,"1025628785127":1509788624186,"1023638753349":1509788624965,"1020613305491":1478686417027,"1021179283167":1478686417098,"1025628785125":1509788624197,"1024625153471":1509788624225,"1023638753355":1509788624965,"1024625153470":1509788624225,"1023638753354":1509788624965,"1023638753359":1509788624965,"1023638753358":1509788624965,"1025909283163":1509788667456,"1015231800618":1480585069068,"1024625153473":1509788624225,"1024625153472":1509788624225,"1024625153475":1509788624225,"1022518073207":1509788625065,"1023638753313":1509788624965,"1023638753312":1509788624965,"1023638753315":1509788624965,"1023638753314":1509788624965,"1023638753316":1509788624965,"1023638753319":1509788624965,"1023638753320":1509788624965,"1023638753324":1509788624965,"1022207821285":1478686417191,"1022956775797":1509788624194,"1023638753298":1509788624965,"1023638753301":1509788624965,"1024461308719":1509788625029,"1760161166":1478686804024,"1023638753305":1509788624965,"1009893091283":1491634246518,"1022956775806":1509788624816,"1023638753304":1509788624965,"1023638753309":1509788624965,"1008722336019":1478686804033,"1021014260911":1478686417089,"1024256376829":1509788625070,"1124976243":1444487341743,"1022238885823":1509788624946,"1022197856976":1478686417280,"1023638753520":1509788624965,"1023638753522":1509788624965,"1022204413256":1509788624920,"1013413671240":1478686804054,"1023638753531":1509788624965,"1024381879435":1509788624304,"1023638753505":1509788624965,"1023638753507":1509788624965,"1023638753506":1509788624965,"1023638753509":1509788624965,"1023638753513":1509788624965,"1021311405975":1478686417102,"1023638753516":1509788624965,"1023638753519":1509788624965,"1022435231917":1478686417294,"1009990610283":1491634246512,"1009990610286":1491634246520,"1009990610285":1491634246520,"1024161739149":1509788667562,"1023638753501":1509788624965,"1009990610279":1491634246520,"1023638753502":1509788624965,"149785948":1444487341705,"1009990610288":1491634246520,"1022287118426":1478686417067,"1009990610289":1491634246520,"1023946384091":1491634246531,"1025037512145":1509788624453,"1025037512144":1509788624453,"1023638753456":1509788624965,"1023638753459":1509788624965,"1020963533573":1478686417034,"1025037512146":1509788624452,"1023638753458":1509788624965,"1025037512149":1509788624452,"1023638753461":1509788624965,"1023946384094":1491634246529,"1023638753463":1509788624965,"1025037512155":1509788624452,"1024625153359":1509788624564,"1025037512154":1509788624452,"1024625153358":1509788624564,"1023638753466":1509788624965,"1025037512157":1509788624453,"1025037512159":1509788624453,"1025037512158":1509788624453,"1024625153354":1509788624564,"1024625153364":1509788624564,"1023638753440":1509788624965,"1023638753442":1509788624965,"1024625153360":1509788624564,"1023638753446":1509788624965,"1025037512137":1509788624452,"1023638753448":1509788624965,"1025037512139":1509788624453,"1023638753451":1509788624965,"1025373845566":1509788624309,"1025037512143":1509788624453,"1023638753432":1509788624965,"1023638753435":1509788624965,"1019027638209":1509788624935,"1010002144725":1491634246518,"1025037512161":1509788624452,"1025037512162":1509788624452,"1022202182374":1478686417190,"1022202182373":1478686417190,"1002077279591":1478686417024,"1012721208350":1478686804054,"1025589989144":1509788624350,"1022611136172":1509788625062,"1022448076909":1480585069079,"866760077":1491634246508,"1023132283301":1509788625144,"1022448076908":1480585069079,"1022448076911":1480585069079,"1022448076910":1480585069079,"1022392110487":1478686417291,"1303366530":1444487341723,"1025711101925":1509788624304,"1022448076920":1480585069079,"1022448076923":1480585069079,"1022448076927":1480585069079,"1022451484684":1478686416985,"1022448076912":1480585069079,"1024625153727":1509788624450,"1022448076914":1480585069079,"1024625153726":1509788624450,"1022448076918":1480585069079,"1004353052342":1444487341707,"1024625153729":1509788624450,"1024625153728":1509788624450,"1024625153730":1509788624450,"1025900370628":1509788667460,"1207550380":1491634246505,"1022282269308":1478686417014,"1021661108535":1478686804033,"1303366601":1444487341753,"1022059049458":1509788624562,"1019823781055":1509788624282,"1022059049459":1509788624562,"1022489237407":1478943089315,"1025711101856":1509788624306,"1022059049457":1509788624562,"1022059049461":1509788624562,"1016758615317":1478686804017,"1016758615319":1478686804031,"1021498445979":1478686417112,"1024662770884":1509788624442,"1022038339667":1478686417168,"1024662770882":1509788624442,"1024662770881":1509788624442,"1024662770880":1509788624442,"4959478039":1509788624154,"1021958387466":1478686417147,"1020323239551":1509788625076,"1021958387468":1478686417147,"1021958387469":1478686417147,"1024662770911":1509788625146,"1005646619519":1509788624389,"1024662770915":1509788625146,"1024662770914":1509788625146,"1024662770913":1509788625146,"1024662770912":1509788625146,"1021126982060":1478686417037,"1015868227630":1465470268264,"1024625153597":1509788624862,"1024625153596":1509788624862,"1024625153598":1509788624862,"1024625153595":1509788624862,"1024625153594":1509788624862,"1022448076937":1480585069079,"1022448076936":1480585069079,"1022448076942":1480585069079,"1004773406477":1478686804027,"1022448076932":1480585069079,"1022448076935":1480585069079,"866760057":1491634246508,"1024088077913":1509788624467,"1018509501915":1509788624426,"1022448076947":1480585069079,"1022448076946":1480585069079,"1021354527615":1465470268231,"1023927378134":1491634246529,"1025537556680":1509788624344,"1021903333422":1478686417139,"1013413671468":1478686804054,"1025849778039":1509788667458,"1024662770878":1509788624441,"1024662771021":1509788624226,"1024662771020":1509788624226,"1024662771019":1509788624226,"1024662771017":1509788624226,"1024135263432":1509788667494,"1022719007031":1509788624268,"1024135263436":1509788667494,"1024662771025":1509788624226,"1015231801212":1480585069068,"1022238623216":1509788624946,"1006492962932":1478686804028,"1022238623230":1509788624931,"1023196511376":1509788625042,"1024785849903":1509788624250,"1022069538757":1478686417301,"1022238623226":1509788624932,"1025796952558":1509788625123,"1022444538325":1478686417295,"1022240589302":1478686417065,"1020073936538":1465470268309,"1022432741894":1478686417212,"1015811343525":1480585069075,"1022646656460":1480585069087,"1015375457948":1509788624976,"1022646656507":1480585069087,"1020116665396":1509788625079,"1025797345737":1509788624455,"4786854463":1509788624153,"1021605272563":1478686417048,"1024737218688":1509788624517,"1022379789571":1478686417290,"1022646656489":1480585069087,"1023820556263":1491634246509,"1021888522974":1478686417138,"1025523663511":1509788624506,"1025523663510":1509788624506,"1025523663509":1509788624506,"1025523663508":1509788624506,"1024737218687":1509788624517,"1025628785499":1509788624832,"1021175350703":1465470268187,"1022059048976":1509788624221,"1022421863026":1478686417293,"1025523663515":1509788624506,"1024737218683":1509788624517,"1025523663514":1509788624506,"1025628785502":1509788624746,"1025523663513":1509788624506,"1024737218681":1509788624517,"1025523663512":1509788624506,"1025628785500":1509788624823,"1022059048974":1509788624221,"1021413119887":1478686417007,"1022059048972":1509788624221,"1022059048973":1509788624221,"1022069145443":1478686417271,"581674251":1478686417018,"1019816572545":1509788624282,"245205305":1444487341736,"1023154044927":1509788624325,"1022008849209":1509788624463,"1020961698124":1478686417085,"1021569359109":1478686417008,"1018017055189":1465470268235,"840414639":1478950494917,"1025009197083":1509788624330,"1021730579634":1478686417051,"1021776847246":1478686417128,"1022700657296":1509788624973,"1016661881592":1478686804042,"1018899184672":1509788624366,"1022700657295":1509788624973,"1020202389494":1478686804065,"1022081335280":1509788624924,"1022700657293":1509788624973,"1022700657292":1509788624973,"1012442938744":1478686417026,"1016661881590":1478686804063,"1021273132944":1478686417040,"1020840323548":1478686417299,"4990414485":1509788624156,"4990414488":1509788624156,"1025509114373":1509788667537,"1025509114371":1509788667537,"1022059049058":1509788624857,"1012266248407":1478686417073,"1022059049059":1509788624857,"1022059049057":1509788624857,"1024620566320":1509788624938,"1022059049061":1509788624857,"1018214324897":1478686804037,"1023638756720":1509788624962,"1018214324898":1478686804037,"1021734251764":1509788624400,"1018214324899":1478686804037,"840415764":1478950494917,"1018214324900":1478686804037,"1018214324901":1478686804037,"1018214324902":1478686804037,"1023638756727":1509788624962,"1018214324904":1478686804037,"1018214324905":1478686804037,"1018214324906":1478686804037,"1023638756731":1509788624962,"1018214324907":1478686804037,"1023638756730":1509788624962,"1018214324908":1478686804037,"1018214324909":1478686804037,"1020202385454":1465470268244,"1018214324910":1478686804037,"1018214324911":1478686804037,"1018214324912":1478686804037,"1021892453748":1478686804071,"1023638756705":1509788624962,"1020202385457":1465470268244,"1018214324913":1478686804037,"1021892453749":1478686804071,"1018214324914":1478686804037,"1021892453750":1478686804071,"1009328687189":1478686804015,"1018214324915":1478686804037,"1023638756706":1509788624962,"1020202385460":1465470268244,"1018214324916":1478686804037,"1018214324917":1478686804037,"1023638756708":1509788624962,"1018214324918":1478686804037,"1023638756711":1509788624962,"1018214324919":1478686804037,"1021892453747":1478686804071,"1018214324920":1478686804037,"1025050878269":1509788624231,"1018214324921":1478686804037,"1025050878268":1509788624231,"1020202385466":1465470268244,"1018214324922":1478686804037,"1018214324923":1478686804037,"1025050878270":1509788624232,"1018214324924":1478686804037,"1018214324925":1478686804037,"1023638756716":1509788624962,"1018214324926":1478686804037,"1023638756719":1509788624962,"1018214324927":1478686804037,"1023638756718":1509788624962,"1018214324864":1478686804036,"1018214324865":1478686804036,"1018214324866":1478686804036,"1018214324867":1478686804036,"1018214324868":1478686804036,"1018214324869":1478686804036,"1018214324870":1478686804036,"1018214324871":1478686804036,"1018214324872":1478686804036,"1018214324873":1478686804036,"1018214324874":1478686804036,"1025525108427":1509788624523,"1024688200937":1509788624901,"1018214324875":1478686804036,"1018214324876":1478686804036,"1010528534774":1478686804055,"1018214324877":1478686804036,"1025525108428":1509788624523,"1024688200942":1509788624902,"1018214324878":1478686804036,"1024688200941":1509788624902,"1018214324879":1478686804037,"1018214324880":1478686804037,"1024688200947":1509788624901,"1018214324881":1478686804037,"1024688200946":1509788624902,"1023638756672":1509788624962,"1018214324882":1478686804037,"1025373844951":1509788624309,"1018214324883":1478686804037,"1024688200944":1509788624901,"1023638756674":1509788624962,"1018214324884":1478686804037,"1018214324885":1478686804037,"1024688200950":1509788624901,"1018214324886":1478686804037,"1018214324887":1478686804037,"1024688200948":1509788624901,"1018214324888":1478686804037,"1024688200955":1509788624901,"1018214324889":1478686804037,"1018214324890":1478686804037,"1018214324891":1478686804037,"1018214324892":1478686804037,"1024688200959":1509788624901,"1018214324893":1478686804037,"1024688200958":1509788624901,"1018214324894":1478686804037,"1024688200957":1509788624901,"1018214324895":1478686804037,"1018214324960":1478686804037,"1024688200835":1509788624592,"1023638756657":1509788624962,"1018214324961":1478686804037,"1024688200834":1509788624592,"1024688200833":1509788624592,"1023638756658":1509788624962,"1023638756660":1509788624962,"1020748046840":1478686417075,"1023638756663":1509788624962,"1025103438916":1509788624281,"1009673149844":1478686804064,"1020878469560":1509788624934,"1023638756671":1509788624962,"1023638756670":1509788624962,"1022083166298":1478686417062,"1021250195452":1478686804032,"1021250195453":1478686804031,"1021250195454":1478686804034,"1023638756642":1509788624962,"1022357242246":1478686417069,"1023638756648":1509788624962,"1025053368645":1509788624945,"1025053368644":1509788624930,"1022577974999":1509788624200,"1025216690975":1509788667495,"1021040865911":1478686417232,"1025053368642":1509788624930,"1023638756655":1509788624962,"1025053368640":1509788624930,"1023638756654":1509788624962,"1018214324928":1478686804037,"1018214324929":1478686804037,"1025216690978":1509788667495,"1018214324930":1478686804037,"1025216690977":1509788667495,"1018214324931":1478686804037,"1025216690976":1509788667495,"1011344863318":1478686804022,"1018214324933":1478686804037,"1018214324934":1478686804037,"1018214324935":1478686804037,"1025216690980":1509788667495,"1018214324936":1478686804037,"1018214324937":1478686804037,"1018214324938":1478686804037,"1018214324939":1478686804037,"1025050878286":1509788624232,"1018214324940":1478686804037,"1018214324941":1478686804037,"1018214324942":1478686804037,"1025050878283":1509788624231,"1018214324943":1478686804037,"1023638756638":1509788624962,"1018214324944":1478686804037,"1022369825122":1478686417289,"1018214324945":1478686804037,"1018214324946":1478686804037,"1025050878295":1509788624232,"1018214324947":1478686804037,"1018214324948":1478686804037,"1022031527243":1478686417011,"1018214324949":1478686804037,"1018214324950":1478686804037,"1025531793133":1509788624296,"1018214324952":1478686804037,"1018214324953":1478686804037,"1018214324954":1478686804037,"1018214324955":1478686804037,"1018214324956":1478686804037,"1025050878297":1509788624232,"1018214324957":1478686804037,"1025050878299":1509788624231,"1018214324959":1478686804037,"1018214324768":1478686804035,"1018214324769":1478686804035,"1018214324770":1478686804035,"1024688200769":1509788624592,"1018214324771":1478686804035,"1018214324772":1478686804035,"1024688200775":1509788624592,"1018214324773":1478686804035,"1023638756852":1509788624962,"1021795332052":1478686417009,"1018214324774":1478686804035,"1023638756855":1509788624963,"1018214324775":1478686804035,"1023638756854":1509788624963,"1018214324776":1478686804035,"1023638756857":1509788624963,"1021257797585":1478686417237,"1018214324777":1478686804035,"1018214324778":1478686804035,"1024688200777":1509788624592,"1023638756859":1509788624963,"1018214324779":1478686804035,"1024688200776":1509788624592,"1018214324780":1478686804035,"1024840504611":1509788624972,"1018214324781":1478686804035,"1024688200782":1509788624592,"1018214324782":1478686804036,"1024688200781":1509788624592,"1023638756863":1509788624963,"1018214324783":1478686804036,"1024688200780":1509788624592,"1018214324784":1478686804036,"1015231801595":1480585069068,"1018214324785":1478686804036,"1024688200786":1509788624592,"1018214324786":1478686804036,"1018214324787":1478686804036,"1023638756834":1509788624962,"1018214324788":1478686804036,"1023638756837":1509788624962,"1018214324789":1478686804036,"1018214324790":1478686804036,"1023638756839":1509788624962,"1018214324791":1478686804036,"1023638756838":1509788624962,"1018214324792":1478686804036,"1018214324793":1478686804036,"1018214324794":1478686804036,"1018214324795":1478686804036,"1018214324796":1478686804036,"1018214324797":1478686804036,"1024688200798":1509788624592,"1018214324798":1478686804036,"1018214324799":1478686804036,"1021087266246":1478686417036,"1023638756817":1509788624962,"1022422779242":1478686417210,"1024688200802":1509788624592,"1021418232074":1509788624508,"1022422779240":1478686417210,"1025050878336":1509788624232,"1024688200806":1509788624592,"1023638756820":1509788624962,"1023638756823":1509788624962,"1024688200804":1509788624592,"1025050878351":1509788624232,"1021087266253":1478686417036,"1023638756826":1509788624962,"1025050878345":1509788624232,"1022161548753":1478686417063,"1024688200819":1509788624592,"1025050878359":1509788624232,"1024688200817":1509788624592,"1023638756803":1509788624962,"1018214324756":1478686804035,"1023638756805":1509788624962,"1018214324757":1478686804035,"1025050878352":1509788624231,"1023638756804":1509788624962,"1018214324758":1478686804035,"1018214324759":1478686804035,"1025050878354":1509788624231,"1018214324760":1478686804035,"1023638756809":1509788624962,"1018214324761":1478686804035,"1024688200826":1509788624592,"1018214324762":1478686804035,"1018214324763":1478686804035,"1018214324764":1478686804035,"1023638756813":1509788624962,"1018214324765":1478686804035,"1024688200830":1509788624592,"1018214324767":1478686804035,"1018214324832":1478686804036,"1018214324833":1478686804036,"1024688200706":1509788624259,"1018214324834":1478686804036,"1024688200705":1509788624258,"1018214324835":1478686804036,"1018214324836":1478686804036,"1024688200711":1509788624259,"1021125670909":1478686417037,"1018214324837":1478686804036,"1024688200710":1509788624259,"1018214324838":1478686804036,"1018214324839":1478686804036,"1018214324840":1478686804036,"1024688200715":1509788624259,"1020202385641":1465470268244,"1018214324841":1478686804036,"1024688200714":1509788624259,"1018214324842":1478686804036,"1018214324843":1478686804036,"1018214324844":1478686804036,"1016930848237":1478686804063,"1018214324845":1478686804036,"1009837774627":1491634246513,"1018214324846":1478686804036,"1024688200717":1509788624259,"1018214324847":1478686804036,"1018214324848":1478686804036,"1018214324849":1478686804036,"1018214324850":1478686804036,"1024688200721":1509788624259,"1018214324851":1478686804036,"1018214324852":1478686804036,"1018214324853":1478686804036,"1024688200726":1509788624259,"1018214324854":1478686804036,"1024688200725":1509788624259,"1018214324855":1478686804036,"1018214324856":1478686804036,"1024688200731":1509788624259,"1018214324857":1478686804036,"1021223456158":1478686416985,"1018214324858":1478686804036,"1018214324859":1478686804036,"1024688200728":1509788624259,"1018214324860":1478686804036,"1018214324861":1478686804036,"1024688200734":1509788624258,"1018214324862":1478686804036,"1024688200733":1509788624258,"1024597624567":1509788624939,"1018214324863":1478686804036,"1024688200732":1509788624258,"1022437721607":1478686417071,"1018214324800":1478686804036,"1024688200739":1509788624259,"1020305147617":1478686804033,"1018214324801":1478686804036,"1023638756752":1509788624962,"1022051057394":1478686417172,"1018214324802":1478686804036,"1025875596031":1509788667406,"1018214324803":1478686804036,"1024688200736":1509788624258,"1025875596030":1509788667406,"1025791712766":1509788667523,"1018214324804":1478686804036,"1024688200743":1509788624258,"1018214324805":1478686804036,"1024688200742":1509788624259,"1018214324806":1478686804036,"1024688200741":1509788624258,"1018214324807":1478686804036,"1019853798415":1509788624286,"1018214324808":1478686804036,"1018214324809":1478686804036,"1021691783575":1509788624287,"1018214324810":1478686804036,"1024688200745":1509788624258,"1018214324811":1478686804036,"1018214324812":1478686804036,"1018214324813":1478686804036,"1025791712752":1509788667523,"1018214324814":1478686804036,"1018214324815":1478686804036,"1023253395110":1509788625083,"1025791712754":1509788667523,"1018214324816":1478686804036,"1018214324817":1478686804036,"1021892453781":1478686804065,"1018214324818":1478686804036,"1018214324819":1478686804036,"1018214324820":1478686804036,"1025791712745":1509788667534,"1023638756740":1509788624962,"1025791712744":1509788667534,"1018214324822":1478686804036,"1018214324823":1478686804036,"1018214324824":1478686804036,"1025791712741":1509788667534,"1018214324825":1478686804036,"1018214324826":1478686804036,"1022450566872":1478686417296,"1018214324827":1478686804036,"1018214324828":1478686804036,"1024688200767":1509788624592,"1025791712737":1509788667575,"1018214324829":1478686804036,"1018214324830":1478686804036,"1024688200765":1509788624592,"1018214324831":1478686804036,"1025791712738":1509788667575,"1022266280509":1478686417197,"1020961570793":1478686416978,"1014429497687":1444487341759,"1003894551871":1478686417221,"1023638756450":1509788624963,"1021584036572":1478686417114,"1023638756454":1509788624963,"1023638756456":1509788624963,"1021594128951":1509788624419,"1023638756458":1509788624964,"1024244576329":1509788624949,"1023638756461":1509788624964,"1025875596033":1509788667402,"1025875596035":1509788667402,"1025875596034":1509788667402,"1023638756432":1509788624964,"1023638756434":1509788624964,"1018626155280":1465470268271,"1020202385670":1465470268244,"1023638756440":1509788624963,"1020202385678":1465470268244,"1009490822035":1480585069065,"1023638756446":1509788624963,"1023638756416":1509788624963,"1023638756418":1509788624964,"1020202385684":1465470268244,"1020961570773":1478686416978,"1025732729780":1509788624942,"1023638756425":1509788624964,"1021749587154":1478686417126,"1021749587156":1478686417126,"1023638756429":1509788624964,"1014712879179":1480585069073,"1021351249129":1478686417104,"1018990938425":1509788624391,"1024797381378":1509788625024,"1024688201092":1509788624255,"1003894551907":1478686417221,"1025343697567":1509788624293,"1003894551905":1478686417221,"1024688201100":1509788624255,"1024688201104":1509788624255,"1024688201111":1509788624254,"1013319952173":1480585069065,"1024688201109":1509788624254,"1024688201114":1509788624255,"1024688201119":1509788624255,"1024688201117":1509788624255,"1024688201123":1509788624255,"1024688201121":1509788624255,"1003894551885":1478686417221,"1024688201120":1509788624255,"1021329884553":1478686417041,"1011230964609":1480585069074,"1024688201125":1509788624254,"1022998849267":1509788624509,"1012143038945":1478686417025,"1003894551881":1478686417221,"1024204078808":1509788667509,"1024688201129":1509788624254,"1003894551877":1478686417221,"1024688201128":1509788624255,"1024985476198":1509788624279,"1024688201132":1509788624254,"1022162990128":1478686417186,"1003894551899":1478686417221,"1003894551897":1478686417221,"1003894551894":1478686417221,"1006603720658":1444487341757,"1021647607653":1509788624534,"1020991979082":1478686416978,"1003894551891":1478686417221,"1003894551888":1478686417221,"1021047681725":1478686417092,"1003894551889":1478686417221,"1024688201027":1509788624895,"1022372053872":1478686417204,"1022448076744":1480585069108,"1023638756592":1509788624962,"1022448076747":1480585069109,"1024688201025":1509788624895,"1024688201024":1509788624895,"1024607979016":1509788667589,"1024688201030":1509788624895,"1025732729607":1509788624942,"1022448076750":1480585069109,"1024688201028":1509788624895,"1022448076737":1480585069108,"1022448076736":1480585069108,"1024688201033":1509788624895,"1021619557411":1478686804028,"1024688201032":1509788624894,"1022448076741":1480585069108,"1022448076740":1480585069108,"1022448076743":1480585069108,"1022448076742":1480585069108,"1024435489890":1509788624437,"1021082940471":1478686417094,"1023638756581":1509788624962,"1023638756580":1509788624962,"1021980933044":1478686417056,"1023638756583":1509788624962,"1023638756585":1509788624962,"1021506314226":1478686417112,"1023638756590":1509788624962,"1022297738494":1478686417199,"1024688201058":1509788624255,"1024688201057":1509788624254,"1023638756563":1509788624962,"1023638756565":1509788624962,"1023638756567":1509788624962,"1021042307992":1478686417092,"1021497925440":1478686417112,"1023638756569":1509788624962,"1023638756570":1509788624962,"1022136251728":1509788624945,"1023638756572":1509788624962,"1023638756575":1509788624962,"1024688201068":1509788624255,"1024688201072":1509788624255,"1021573682129":1478686417114,"1954676023":1444487341745,"1024688201076":1509788624255,"1024688201081":1509788624255,"1024688201087":1509788624255,"1023496012876":1509788625082,"1024688200962":1509788624901,"1023638756528":1509788624962,"1022407968107":1478686417208,"1024688200964":1509788624901,"1024688200969":1509788624901,"1024688200979":1509788624902,"1024688200978":1509788624901,"1009712078527":1491634246518,"1024688200976":1509788624901,"1024688200983":1509788624902,"1023638756517":1509788624962,"1010528534799":1478686804055,"1023638756516":1509788624962,"1025319317747":1509788624182,"1024688200981":1509788624901,"1025035411945":1509788624210,"1024688200987":1509788624901,"1023638756520":1509788624962,"1024688200985":1509788624901,"1023638756523":1509788624962,"1021685753863":1478686417121,"1023638756524":1509788624962,"1021698468084":1478686417121,"1024832378315":1509788624948,"1023638756497":1509788624962,"1012126002787":1478686417073,"1023638756499":1509788624962,"1020924738261":1478686417228,"1023638756500":1509788624962,"1023638756503":1509788624962,"1023638756502":1509788624962,"1024688201001":1509788624894,"1023638756507":1509788624962,"1023638756506":1509788624962,"1024688201007":1509788624895,"1024688201006":1509788624895,"1024688201004":1509788624895,"1022448076729":1480585069108,"1022448076728":1480585069108,"1022847463274":1509788624383,"1024688201010":1509788624895,"1022448076731":1480585069108,"1025319317719":1509788624182,"1024688201009":1509788624895,"1022448076730":1480585069108,"1024688201008":1509788624895,"1022448076733":1480585069108,"1024688201015":1509788624895,"1022448076732":1480585069108,"1024688201013":1509788624895,"1024688201012":1509788624895,"1022461970029":1478686417217,"1009850226384":1478686804024,"1024688201018":1509788624895,"1020638866374":1478686416995,"1022448076723":1480585069108,"1024688201017":1509788624895,"1024688201016":1509788624895,"1022448076725":1480585069108,"1022448076724":1480585069108,"463966810":1491634246534,"1024688201022":1509788624895,"1022448076727":1480585069108,"1025319317723":1509788624182,"1013319296100":1509788625016,"4559832515":1465469681387,"1016301693615":1480585069066,"4990411618":1509788624154,"1016301693616":1480585069066,"4990411617":1509788624154,"1020878470112":1509788624934,"1021485342602":1509788624977,"1008558757888":1465470268313,"1025538608144":1509788624281,"1022896481194":1509788624299,"1009249644853":1478686804023,"1025906923031":1509788667460,"1025902728790":1509788667463,"1025902728789":1509788667460,"1022998848953":1509788624434,"1020937322073":1478686417084,"1022345970252":1478686417015,"1019137737609":1509788624366,"1022270738127":1478686417285,"1025538608138":1509788624282,"1023092047838":1509788625047,"1025538608137":1509788624311,"1372445686":1478686804024,"171278344":1444487341720,"1024688201346":1509788625212,"1021984864677":1478686417057,"1024688201344":1509788625213,"1024688201351":1509788625212,"1024688201348":1509788625212,"1024688201355":1509788625213,"1024688201354":1509788625213,"1022427498441":1478686417211,"1024688201353":1509788625213,"1024688201359":1509788625212,"1024688201360":1509788625212,"1021323985194":1465470268212,"1021323985193":1465470268212,"1021323985196":1465470268212,"1022577974498":1509788624200,"1021323985190":1465470268212,"1021323985189":1465470268212,"1021776456705":1509788624403,"1022701311781":1509788624972,"1024186514654":1509788624825,"1008969933277":1478686804064,"1021513653351":1509788624419,"1021277979270":1478686417040,"1020918053136":1478686417081,"1016866491282":1478686804018,"1025512918826":1509788624344,"1020918053133":1478686417081,"1022162859997":1509788624958,"1012338343521":1478686804022,"1016936483947":1478686804019,"1025731942440":1509788624931,"1024460786907":1509788625070,"1021894420452":1478686417138,"1024688201335":1509788625213,"1024688201334":1509788625212,"1024566429363":1509788625079,"1024688201339":1509788625213,"1024688201338":1509788625213,"1024688201336":1509788625213,"1024688201343":1509788625213,"1024688201341":1509788625213,"1021037850812":1509788624933,"1021120689577":1478686417095,"1000527724048":1444487341711,"1018644636154":1478686804026,"1022311369859":1478686417068,"1022311369858":1478686417068,"1011502876739":1480585069074,"1022311369857":1478686417068,"1021698075627":1478686417121,"1021698075625":1478686417121,"1012209362826":1509788625017,"1021323722824":1478686417005,"1020653938775":1478686804057,"1025883852946":1509788667449,"1004353049596":1444487341756,"1023638756991":1509788624961,"1021323722817":1478686417005,"1018926184281":1509788624932,"1023638756961":1509788624961,"1021962320462":1509788624982,"1025883852943":1509788667449,"1021962320463":1509788624982,"1023638756967":1509788624961,"1023638756966":1509788624961,"1021962320454":1509788624982,"1023638756971":1509788624961,"1021962320452":1509788624982,"1025791712775":1509788667523,"1021962320453":1509788624982,"1021326737440":1465470268214,"1021962320450":1509788624982,"1023638756972":1509788624961,"1021962320451":1509788624982,"1021326737436":1465470268214,"1021326737437":1465470268214,"1023638756947":1509788624961,"1023638756949":1509788624961,"1016839359376":1478686804022,"1023638756954":1509788624961,"1022601042973":1480585069140,"1023638756935":1509788624961,"1023638756937":1509788624961,"1023638756938":1509788624961,"1003320578372":1509788624372,"1023638756940":1509788624961,"1021175351577":1465470268187,"1023638756942":1509788624961,"1022467343467":1478686417072,"1022467343471":1478686417072,"1022293020363":1478686417286,"1022467343474":1478686417072,"1023638756896":1509788624963,"1842603648":1444487341711,"1005848214151":1509788624387,"1020924213351":1478686417033,"1025533496634":1509788624347,"1023638756881":1509788624962,"1021962320446":1509788624982,"1021962320445":1509788624982,"1021962320443":1509788624982,"1023638756886":1509788624962,"1022375461335":1480585172184,"1021301965270":1478686417238,"1023638756892":1509788624963,"1024384240020":1509788624329,"1025842303855":1509788667443,"1023970894589":1509788625037,"1023638756872":1509788624962,"1025892503650":1509788667466,"1023638756874":1509788624962,"1021425310240":1509788624977,"1024070509768":1491634246520,"1023638756878":1509788624962,"1021726517450":1478686417123,"1025531792669":1509788624295,"1022457381980":1480585069086,"1022457381971":1480585069086,"1024244445919":1509788624948,"1022457381970":1480585069086,"1022028644036":1478686417011,"1020294137150":1465470268292,"1022446765536":1478686417016,"1016609323495":1478686804018,"1649928699":1444487341744,"1021325951108":1478686417005,"1019309578452":1509788624317,"1022457381994":1480585069086,"1022457381992":1480585069086,"1022457381999":1480585069087,"1022701311717":1509788624972,"1022457381997":1480585069087,"1024781783703":1509788625021,"1022457381985":1480585069086,"1020294006034":1465470268280,"1023924628870":1509788624920,"1024634461137":1509788667620,"1022086312499":1478686417062,"1000053366006":1478686417021,"1022086312500":1478686417062,"1022086312501":1478686417062,"1000527724321":1444487341713,"1017165076731":1478686804019,"1022185534518":1478686417187,"1023268205754":1509788624839,"1021346924040":1478686417103,"1023638757009":1509788624961,"1023638757008":1509788624961,"1020878469654":1509788624934,"1022073729887":1478686417176,"1023638757014":1509788624961,"1023638757017":1509788624961,"1499976333":1444487341751,"1024381881071":1509788624301,"1023638757019":1509788624961,"1019915533493":1478686804034,"1649928634":1444487341738,"1023638757022":1509788624961,"1025504792518":1509788624336,"1025504792517":1509788624341,"1023638756994":1509788624961,"1020861823745":1478686417079,"1023638757000":1509788624961,"419009283":1491634246520,"1023638757002":1509788624961,"1025504792523":1509788624346,"1023638757005":1509788624961,"1025504792522":1509788624344,"1023638757004":1509788624961,"1000527724303":1444487341715,"1649928616":1444487341729,"1025504792520":1509788624337,"1023638757006":1509788624961,"1022250552843":1478686417066,"1021037852272":1509788624933,"1021049911217":1478686417232,"837402104":1444487341741,"1025487753000":1509788624927,"1021049911211":1478686417232,"1021049911205":1478686417232,"1023075006709":1509788625047,"1021040080500":1478686417092,"1025487752984":1509788624927,"1025487752989":1509788624927,"1021049911191":1478686417232,"1020045554613":1509788625020,"4891979704":1509788624155,"1024752555229":1509788667502,"1024752555230":1509788667502,"1024752555227":1509788667502,"1024752555226":1509788667502,"1020294005398":1465470268280,"1023288265838":1509788624183,"1022700786021":1509788624973,"1011663964017":1478686804061,"1011663964018":1478686804061,"1023638755617":1509788624963,"1023638755619":1509788624963,"1023638755618":1509788624963,"1023638755621":1509788624963,"1025732730587":1509788624922,"1021725208348":1478686417123,"1009004667351":1478686804023,"1023638755603":1509788624963,"1023638755602":1509788624963,"1023638755605":1509788624963,"1023638755604":1509788624963,"1023638755608":1509788624963,"1022438507153":1478686417213,"1023638755611":1509788624963,"1019704371079":1509788625077,"1019704371081":1509788625077,"1023638755597":1509788624963,"1023638755599":1509788624963,"1023638755598":1509788624963,"1021004297460":1478686417034,"1020992240525":1478686416986,"1021544584355":1478686417113,"1020596530213":1478686804057,"1018796947822":1478686804057,"1023222853823":1509788624957,"1021544584357":1478686417113,"1018796947823":1478686804057,"1018796947820":1478686804057,"1021544584361":1478686417113,"1022472854598":1478943089486,"1022472854597":1478943089486,"1021544584363":1478686417113,"1021544584364":1478686417113,"1021424131583":1478686417043,"1784145607":1444487341743,"1021885505890":1478686417044,"1018796947834":1478686804057,"1018796947835":1478686804057,"1022479932658":1478943089488,"1012628539684":1478686417026,"1018796947832":1478686804057,"1018796947833":1478686804057,"1018796947826":1478686804057,"1018796947824":1478686804057,"1021424131561":1478686417043,"1018796947825":1478686804057,"1018796947830":1478686804057,"1018796947831":1478686804057,"1020653940679":1478686804057,"1025732730401":1509788624942,"1021495826860":1478686417046,"1022075302955":1509788624924,"1022072812640":1509788624451,"1023288265869":1509788624990,"1023995012847":1491634246517,"1024403902223":1509788625100,"1015231802504":1480585069068,"1020822102453":1478686417030,"1016681282282":1478686804018,"1025295725666":1509788624946,"1024374672738":1509788625100,"1023820557417":1491634246535,"1024435489024":1509788624465,"1020878470412":1509788624934,"1019029475084":1509788624282,"1018796947694":1478686804056,"1018796947695":1478686804056,"1007660634275":1478686804030,"1022209527185":1509788624933,"1018796947704":1478686804057,"1022076482943":1478686417177,"1025893029383":1509788667405,"1018796947708":1478686804057,"1022080939327":1478686417301,"1018796947698":1478686804056,"1022209527193":1509788624938,"1018796947699":1478686804056,"1018796947696":1478686804056,"1025328363425":1509788624306,"1021611036980":1509788624397,"1022209527195":1509788624938,"1018796947697":1478686804056,"1022209527194":1509788624938,"1018796947702":1478686804056,"1018796947703":1478686804056,"1018796947700":1478686804056,"1018796947701":1478686804056,"1023638755409":1509788624963,"1023638755412":1509788624963,"1023638755414":1509788624963,"1021664252458":1478686417050,"1018889353032":1509788624932,"1022657926890":1509788625061,"1023638755392":1509788624963,"1022577974201":1509788624827,"1023638755397":1509788624963,"1023638755403":1509788624963,"1023638755404":1509788624963,"1023638755406":1509788624963,"1023638755381":1509788624963,"1023638755387":1509788624963,"1023638755386":1509788624963,"1023638755389":1509788624963,"1023638755388":1509788624963,"1024403902085":1509788624193,"1303363838":1444487341727,"1021913031551":1509788624465,"1021757188294":1509788624400,"1023638755346":1509788624963,"1023638755349":1509788624963,"1022396827154":1478686417206,"1022080939328":1478686417301,"1022080939329":1478686417301,"1024469568164":1509788624522,"1023638755328":1509788624963,"1023638755333":1509788624963,"1023638755332":1509788624963,"1023638755337":1509788624963,"1023638755341":1509788624963,"1021385851435":1478686417042,"1023638755554":1509788624963,"1023638755557":1509788624963,"1021513653121":1509788624815,"1022185272203":1478686417278,"1018683433778":1509788625018,"1021463584438":1478686417108,"1023638755539":1509788624963,"1021490321631":1478686417110,"1192479415":1444487341730,"1021700435805":1478686804046,"1023638755545":1509788624963,"1020891708583":1478686417227,"1023638755551":1509788624963,"1023638755520":1509788624963,"1023638755523":1509788624963,"1022356194416":1478686804064,"1023638755522":1509788624963,"1021121475276":1478686417037,"1023638755525":1509788624963,"1023638755528":1509788624963,"1021617328245":1478686417300,"1021340500466":1465470268222,"1019037076996":1509788624366,"1021340500465":1465470268222,"1022204808459":1480585069084,"1006617874997":1509788624386,"1023638755510":1509788624963,"1023638755513":1509788624963,"1023638755516":1509788624963,"1026223465100":1514456869766,"1025531792207":1509788624295,"1025319318721":1509788624182,"1022350558684":1478686417289,"1018989104483":1509788624313,"1021226076988":1478686417039,"1025607943185":1509788624833,"1025607943184":1509788624823,"1026223464772":1514456869766,"1025607943190":1509788624746,"1025791712016":1509788667779,"1021514307612":1509788624419,"1025791712019":1509788667778,"1015231803001":1480585069068,"1009017250021":1509788625020,"1021980802107":1478686417056,"1023480677057":1509788625082,"1022029036381":1478686417164,"1025607943183":1509788624828,"1024781129595":1509788625148,"1009017250004":1509788625020,"1024781129597":1509788625148,"1010084455287":1478686804061,"1024781129596":1509788625148,"1024781129599":1509788625148,"1024781129598":1509788625148,"1021736610555":1478686417124,"1025791712052":1509788667678,"1009017250013":1509788625020,"1021007574541":1478686417089,"1025791712048":1509788667678,"1010084455292":1478686804061,"1025791712050":1509788667678,"1024781129579":1509788624557,"1023347509918":1509788624894,"1024781129581":1509788624557,"1024781129580":1509788624557,"1025791712040":1509788667679,"1024781129583":1509788624557,"1024781129582":1509788624557,"1025791712036":1509788667691,"1025791712033":1509788667668,"962443039":1509788625020,"1025791712095":1509788667435,"1021240231944":1478686417039,"1021892453160":1478686804054,"1021240231952":1478686417039,"1021980802112":1478686417056,"1025732730082":1509788624942,"1025791712123":1509788667415,"1025082074401":1509788625007,"1025791712119":1509788667415,"1025791712118":1509788667415,"1025791712115":1509788667415,"1025791712114":1509788667415,"1025791712108":1509788667413,"1025791712107":1509788667421,"1020926049653":1478686417082,"1025791712097":1509788667435,"1021421117214":1478686417106,"1024412683693":1509788625082,"1024374673158":1509788624815,"1025883854089":1509788667452,"1021587445036":1478686417114,"1012739818894":1478686804025,"1025875596469":1509788667406,"1021814597306":1509788624394,"1008036298234":1478686804025,"1004641150741":1509788624972,"1022781402283":1509788624402,"1022031133665":1478686417165,"1019074694075":1509788624313,"1025732729924":1509788624942,"1024781129617":1509788624218,"1024781129616":1509788624218,"1024781129618":1509788624218,"1024781129620":1509788624218,"1021208251135":1478686804026,"1010084455297":1478686804061,"1010084455302":1478686804061,"1010091663385":1478686804020,"1023106464734":1509788624466,"1010084455300":1478686804061,"1024781129615":1509788624218,"176260184":1478686417023,"1010084455304":1478686804061,"1010069381851":1491634246534,"1020963534894":1478686417034,"1022291053387":1478686417198,"1009998603909":1491634246520,"1023297179477":1509788625019,"1012123380051":1478686417073,"1021018715800":1478686417090,"1021776849224":1478686417128,"1024688200641":1509788624492,"1021018715805":1478686417090,"1024688200645":1509788624492,"1021300000211":1480585069071,"1024688200651":1509788624492,"1024688200650":1509788624492,"1025732730251":1509788624942,"1024688200648":1509788624492,"518754791":1478686417019,"1024688200655":1509788624492,"518754789":1478686417019,"1024688200653":1509788624492,"1024688200652":1509788624492,"1021603173302":1478686804040,"1024688200657":1509788624492,"657696807":1444487341745,"1024688200662":1509788624492,"1025428115391":1509788624511,"1016820871364":1465470268261,"1024688200660":1509788624492,"1025428115390":1509788624510,"1024342880353":1509788625031,"1024688200664":1509788624492,"1005946517729":1480585069065,"1024688200669":1509788624492,"1024688200675":1509788624492,"1024663428479":1509788625003,"1024688200678":1509788624491,"1024663428475":1509788625003,"1022369957433":1478686417290,"1022207954832":1478686417191,"1022681125708":1509788624394,"1024688200682":1509788624491,"1024688200681":1509788624491,"1024688200680":1509788624492,"1022207954837":1478686417191,"1007394816685":1509788624374,"4959479989":1509788624154,"1181337945":1480585069060,"1022207954827":1478686417191,"1218561938":1478686417020,"1022207954826":1478686417191,"1021458603124":1478686417108,"1218561945":1478686417020,"1021906215307":1478686417140,"1022207954823":1478686417191,"1025428115432":1509788624437,"1024153746429":1509788667495,"1021594129519":1509788624817,"1024153746426":1509788667495,"1022423433866":1478686417302,"1025428115428":1509788624437,"1014686797749":1478686804016,"1024487262095":1509788624920,"1015912269487":1480585069075,"1024374673095":1509788624419,"1024153746411":1509788667495,"1000363222518":1478686804059,"1024487262091":1509788624920,"1576129190":1491634246512,"1024487262085":1509788624920,"1024153746402":1509788667495,"1022384244072":1478686417290,"1025909019519":1509788667462,"1025428115402":1509788624433,"1025428115404":1509788624432,"1025585792549":1509788624350,"1025585792548":1509788624350,"1025428115392":1509788624433,"1025428115395":1509788624424,"1025428115394":1509788624433,"1025428115397":1509788624427,"1025428115396":1509788624434,"1025428115417":1509788624432,"1024688200627":1509788624491,"1024688200630":1509788624492,"1024688200635":1509788624492,"1025115628085":1509788624970,"1024487262045":1509788624920,"1003643937471":1478686804060,"1003643937468":1478686804060,"1003643937469":1478686804060,"1009269961283":1509788624389,"1003643937467":1478686804060,"1003643937464":1478686804060,"1003643937465":1478686804060,"1021559002819":1509788624397,"1003643937462":1478686804060,"1024374672921":1509788624533,"1025901286174":1509788667788,"1024487262032":1509788624920,"1025876252062":1509788667406,"1021914603943":1478686417141,"1021888258623":1478686417137,"1018901673014":1509788624282,"1025883853825":1509788667451,"1026223464670":1514456869766,"1024487262077":1509788624920,"1022029298429":1478686417164,"1024487262079":1509788624920,"1024487262073":1509788624920,"1017311351600":1478686804019,"1024487262069":1509788624920,"1024487262068":1509788624920,"1023005532325":1509788624389,"1024487262071":1509788624920,"1024487262070":1509788624920,"1024487262065":1509788624920,"1022456856687":1509788625018,"1024487262061":1509788624920,"1024487262057":1509788624920,"1024487262052":1509788624920,"1021254518958":1478686416979,"1025791711964":1509788667606,"1020944529959":1478686417084,"1024663428510":1509788625003,"1025791711966":1509788667600,"1024663428505":1509788625003,"1025791711960":1509788667617,"1025791711962":1509788667595,"1024374672991":1509788624194,"1025791711952":1509788667649,"1024663428498":1509788625003,"1025791711954":1509788667617,"1024663428492":1509788625003,"1024663428495":1509788625003,"1025791711951":1509788667650,"1021885768221":1478686417257,"1001644734865":1444487341702,"1669852240":1478686804029,"1024663428486":1509788625003,"1021381787689":1478686417105,"1024663428480":1509788625003,"1017554363900":1465470268315,"1021941481329":1478686417143,"1021329883906":1478686417041,"1021885768225":1478686417258,"1003643937487":1478686804060,"1025035020228":1509788625023,"1025791711976":1509788667600,"1003643937480":1478686804060,"1003643937478":1478686804060,"1024663428517":1509788625003,"1003643937479":1478686804060,"1024663428516":1509788625003,"1025791711972":1509788667600,"1021309961670":1465470268202,"1024663428519":1509788625003,"1021309961671":1465470268202,"1003643937477":1478686804060,"1003643937475":1478686804060,"1022461575269":1478686417072,"1003643937472":1478686804060,"1024663428515":1509788625003,"1025791711971":1509788667600,"1021301840570":1480585069071,"1021247838200":1478686416986,"1019612755268":1509788624354,"1021623356804":1509788624404,"941729851":1491634246519,"1020257967339":1465470268311,"1025428115593":1509788625128,"1026225045261":1514456869772,"1025428115599":1509788625128,"1021994558296":1478686417156,"1025428115586":1509788625128,"1022038992516":1478686417168,"1025428115589":1509788625104,"1025428115588":1509788625128,"1025428115591":1509788625112,"1025428115590":1509788625129,"1021515089879":1509788624401,"1025428115611":1509788625136,"1025428115610":1509788625135,"1025428115612":1509788625135,"1021581412900":1509788624401,"1020667311193":1478686804022,"1025428115601":1509788625127,"1025428115600":1509788625127,"1025428115603":1509788625127,"1025428115605":1509788625127,"1024244574568":1509788624949,"1025428115606":1509788625127,"1002930508784":1478686804059,"1002930508778":1478686804059,"1023319724583":1509788625019,"1002930508779":1478686804059,"1002930508780":1478686804059,"1002930508782":1478686804059,"1023319724579":1509788624926,"1002930508783":1478686804059,"1012116174432":1478686416993,"1024847056144":1509788624969,"1023830651322":1509788625016,"1002930508773":1478686804059,"1023319724565":1509788624926,"1009710761980":1480585069062,"840409712":1478950494917,"1022092863996":1478686417180,"1023319724549":1509788624926,"1022463549196":1478686804067,"1021937148076":1478686417143,"1022089849300":1478686417062,"1023319724545":1509788624926,"1023319724559":1509788624957,"1023319724553":1509788624925,"1022240854563":1478686417283,"1023638750707":1509788624326,"1022286861676":1478686417198,"1022240854568":1478686417283,"1023638750694":1509788624326,"1021787993909":1509788624394,"1019287290427":1509788625079,"1023988070919":1509788624494,"1023638750703":1509788624326,"1025070807733":1509788624305,"1023638750674":1509788624326,"1021300005488":1480585069071,"1023638750679":1509788624326,"1021768988262":1509788624395,"1021539731656":1509788624902,"1021539731657":1509788624902,"1025216685028":1509788667495,"989309535":1478950494919,"1023638750681":1509788624326,"1021539731654":1509788624902,"1021539731655":1509788624902,"1021539731652":1509788624902,"1020925387683":1478686417082,"1023638750682":1509788624326,"1021539731653":1509788624902,"1023638750685":1509788624326,"1021539731650":1509788624902,"1023638750684":1509788624326,"1021539731651":1509788624902,"1021539731648":1509788624902,"1023638750686":1509788624326,"1021539731649":1509788624902,"1021770036838":1509788624194,"1023638750663":1509788624326,"1021033654796":1478686417091,"360285632":1444487341743,"1023638750667":1509788624326,"1023638750669":1509788624326,"1021539731664":1509788624902,"1020531772477":1480585069077,"1021539731630":1509788624902,"1020531772483":1480585069077,"1021539731628":1509788624902,"1021539731626":1509788624902,"1018674789781":1478686804024,"1020531772485":1480585069077,"1021539731625":1509788624902,"1020531772490":1480585069077,"1020531772489":1480585069077,"1020531772494":1480585069077,"1020531772492":1480585069077,"1020531772493":1480585069077,"1020531772499":1480585069077,"1023638750624":1509788624968,"1020531772496":1480585069077,"1021539731642":1509788624902,"1025428115580":1509788625245,"1023638750631":1509788624968,"1025428115583":1509788625245,"1020531772501":1480585069077,"1021539731641":1509788624902,"1023638750630":1509788624968,"1023638750632":1509788624968,"1022826624256":1509788625054,"1021363707442":1509788624433,"1022454374152":1478686417216,"1023638750608":1509788624968,"1023638750611":1509788624968,"1022454374156":1478686417216,"1023638750612":1509788624968,"1023638750615":1509788624968,"1018553677453":1478686804019,"1023638750614":1509788624968,"1023638750617":1509788624968,"1023638750620":1509788624968,"1019817222607":1509788624302,"1016301563999":1480585069066,"1022454374160":1478686417216,"1022454374163":1478686417216,"1022454374162":1478686417216,"1023638750605":1509788624968,"1023638750607":1509788624968,"1024342224502":1509788625031,"407603537":1478950494909,"1021797561872":1509788624394,"1022463549012":1478686804067,"1025592875980":1509788624930,"548385263":1478686417019,"1022352922960":1478686417203,"1022316877683":1478686417068,"1019287290852":1509788625080,"1022316877686":1478686417068,"1021076122946":1478686417093,"1022316877684":1478686417068,"1024244574218":1509788624949,"1021611953503":1509788625080,"1021793236502":1478686417129,"1020960646268":1478686417033,"1010770757434":1478950494939,"1615851826":1444487341730,"1020542520428":1509788624354,"848667398":1478950494917,"1369161740":1478686804054,"1407828593":1491634246505,"1019448511151":1478686804021,"1025400057812":1509788624293,"1022197853938":1478686417189,"1025400057814":1509788624293,"1025731937066":1509788624922,"1020462696725":1465470268260,"1021513648050":1478686416980,"1021513648051":1478686416981,"1025400057817":1509788624293,"1025400057819":1509788624293,"1021584034405":1478686417114,"1021508011977":1509788624974,"1021513648037":1478686416980,"1010091671309":1478686804046,"1020605837811":1478686417224,"1021512075256":1478686417244,"1023995149311":1491634246529,"1024953759011":1509788624269,"1021992723107":1478686417156,"1024953759010":1509788624192,"1022178455477":1509788624935,"1021530818245":1478686417244,"1021530818243":1478686417244,"1021247837738":1478686417039,"1009673143296":1478686804064,"1579798477":1444487341726,"1021175354304":1465470268188,"1021175354305":1465470268188,"1024194373560":1509788625071,"1021374455740":1478686417104,"1022045284274":1478686417171,"1022645602434":1480585069134,"1024454235348":1509788624989,"1022645602433":1480585069134,"1022645602439":1480585069134,"1022645602438":1480585069134,"1021517579737":1509788624398,"1024454235344":1509788624989,"1022645602437":1480585069134,"1022645602436":1480585069134,"1024454235357":1509788624990,"1024454235359":1509788624990,"1022645602447":1480585069134,"1024454235352":1509788624990,"1022645602445":1480585069134,"1023638751073":1509788624968,"1022645602450":1480585069134,"1023638751072":1509788624968,"1024454235334":1509788624990,"1023638751076":1509788624968,"1023638751079":1509788624968,"1023638751083":1509788624969,"1024454235342":1509788624990,"1023638751084":1509788624968,"1022076218033":1509788625019,"1022076218034":1509788625016,"1023638751061":1509788624968,"1022645602470":1480585069134,"1021982105641":1509788624821,"1023638751063":1509788624969,"1023638751062":1509788624969,"1023638751065":1509788624969,"1022645602474":1480585069134,"1023638751067":1509788624969,"1022645602472":1480585069134,"1024186639490":1509788625166,"1022645602479":1480585069134,"1022645602478":1480585069134,"1023638751068":1509788624969,"1024244706173":1509788624948,"1022645602476":1480585069134,"1023638751070":1509788624968,"1022645602483":1480585069134,"1022645733555":1509788624434,"1022645602480":1480585069134,"1022645602486":1480585069134,"1022645602485":1480585069134,"1022645602484":1480585069134,"1022645602491":1480585069134,"1022645602488":1480585069134,"1022645602495":1480585069135,"1022645602494":1480585069134,"1022645602498":1480585069135,"1022645602497":1480585069135,"1022645602496":1480585069135,"1022645602503":1480585069135,"1023638751028":1509788624968,"1022645602501":1480585069135,"1023638751031":1509788624968,"1023638751030":1509788624968,"1025050884972":1509788624457,"1022645602505":1480585069135,"1023638751034":1509788624968,"1023638751036":1509788624968,"1021965853514":1509788624536,"1022043317310":1478686417058,"1023638751013":1509788624968,"1002288828323":1478686417024,"1021925752117":1478686804065,"1025050884987":1509788624457,"1023638751023":1509788624968,"1022566827786":1509788625075,"1025050884935":1509788624457,"1023638750996":1509788624968,"1024454235315":1509788624990,"1021631745909":1478686417248,"1024454235314":1509788624990,"1023638751001":1509788624968,"1022079625782":1478686417178,"1023638751003":1509788624968,"1025050884942":1509788624458,"1023638751002":1509788624968,"1025050884937":1509788624458,"1023638751005":1509788624968,"941730382":1491634246519,"1022201916774":1478686417280,"1025050884949":1509788624457,"1025050884944":1509788624458,"1025050884957":1509788624457,"1024454235308":1509788624990,"1024454235310":1509788624990,"1023638750988":1509788624968,"1024454235307":1509788624990,"1025050884954":1509788624458,"1023638751217":1509788624966,"1023638751221":1509788624966,"1023638751225":1509788624966,"1023638751224":1509788624966,"1023638751227":1509788624966,"1025050885033":1509788624457,"1021307476168":1480585069071,"1023638751231":1509788624966,"1025050885045":1509788624457,"1022187105639":1478686417064,"1023638751205":1509788624966,"1023638751206":1509788624966,"1021483894619":1478686417046,"1021483894616":1478686417046,"1025050885054":1509788624457,"1023638751212":1509788624966,"1023638751215":1509788624966,"1022866339300":1509788624439,"1022866339291":1509788624439,"1022866339295":1509788624439,"1427228600":1444487341742,"1025050885004":1509788624457,"1025050885000":1509788624457,"1025050885015":1509788624457,"1025715553072":1509788625021,"1021700436026":1478686804046,"1024045350902":1509788624378,"1023638751154":1509788624966,"1025050885089":1509788624457,"1023638751159":1509788624966,"1025050885090":1509788624457,"1024045350909":1509788624377,"1022129170817":1478686417184,"1024045350911":1509788624378,"1024045350910":1509788624378,"1024045350905":1509788624378,"1024045350904":1509788624378,"1022054327564":1478686416977,"1024045350907":1509788624378,"1024045350906":1509788624378,"1023638751141":1509788624966,"1023638751145":1509788624966,"1021925752241":1478686804032,"1023638751144":1509788624966,"1023638751147":1509788624966,"1021549169442":1478686417008,"1008821039198":1509788624388,"1023638751121":1509788624966,"1023638751122":1509788624966,"1022645602407":1480585069134,"1023638751127":1509788624966,"1025050885058":1509788624457,"1023638751126":1509788624966,"1022645602410":1480585069134,"1023638751131":1509788624966,"1021168537701":1478686417098,"1022645602408":1480585069134,"1025050885070":1509788624457,"1023638751130":1509788624966,"1023638751132":1509788624966,"1022645602413":1480585069134,"1022645602419":1480585069134,"1022645602416":1480585069134,"1022645602423":1480585069134,"1022645602422":1480585069134,"1020646732114":1478686417028,"1022645602421":1480585069134,"1022645602420":1480585069134,"1022645602427":1480585069134,"1025050885085":1509788624457,"1022645602426":1480585069134,"1025050885087":1509788624457,"1025050885081":1509788624457,"1022645602430":1480585069134,"989309430":1478950494919,"1020896158152":1478686417079,"1016936486343":1478686804021,"1024403902687":1509788624419,"1024737477881":1509788625021,"1023319724409":1509788624925,"1023638750817":1509788624968,"1008992747356":1465470268313,"1025007498440":1509788624977,"1023638750821":1509788624968,"1023638750820":1509788624968,"1023638750823":1509788624968,"1023638750822":1509788624968,"1023638750825":1509788624968,"1023032140417":1509788667889,"1023638750827":1509788624968,"1025564957594":1509788624306,"1023638750829":1509788624968,"1020973098319":1478686417086,"1023638750830":1509788624968,"1023032140472":1509788667843,"1023638750802":1509788624968,"1023638750805":1509788624968,"1021116099723":1478686417095,"1023638750808":1509788624968,"1023638750810":1509788624968,"1020257705944":1465470268311,"1022290531993":1478686417068,"1020261900168":1478686804039,"1025278944432":1509788625002,"1025876248878":1509788667406,"1021770036719":1509788624533,"1024403902615":1509788624819,"1021317830893":1478686417041,"1014746697784":1478686804022,"1021376552302":1478686417105,"1021411148667":1478686417043,"1025278944476":1509788624999,"1025278944472":1509788624997,"1025278944474":1509788624997,"1025040530074":1509788624183,"1025040530073":1509788624183,"1025278944470":1509788624997,"1023638750737":1509788624968,"1023638750736":1509788624968,"1023638750739":1509788624968,"1021597927541":1509788624397,"1023638750741":1509788624968,"1023638750743":1509788624968,"1023638750744":1509788624968,"1025278944484":1509788625083,"1000143539888":1478686804029,"1023638750749":1509788624968,"1023638750748":1509788624968,"1025386032731":1509788624467,"1025386032730":1509788624467,"1025386032729":1509788624467,"1023638750723":1509788624968,"1025386032728":1509788624467,"1023638750724":1509788624968,"1025386032732":1509788624467,"1023638750726":1509788624968,"1025386032727":1509788624467,"1025386032726":1509788624467,"1023638750732":1509788624968,"1025386032725":1509788624467,"1023638750735":1509788624968,"1022645602563":1480585069135,"1022088800849":1478686417012,"1022645602562":1480585069135,"1022645602567":1480585069135,"1022156959269":1478686417063,"1020871254979":1478686417227,"1022645602564":1480585069135,"1023319724530":1509788624925,"1022645602571":1480585069135,"1021485073956":1509788624863,"1025278944261":1509788624999,"1021485073957":1509788624863,"1023277519728":1509788625041,"1022645602569":1480585069135,"1021485073958":1509788624863,"1021485073959":1509788624863,"1022645602573":1480585069135,"1023319724538":1509788624933,"1023319724517":1509788624957,"1022645602578":1480585069135,"1022455159918":1478686417297,"1023319724518":1509788624925,"1020604920754":1478686417075,"1025278944281":1509788624999,"1022645602584":1480585069135,"1022645602591":1480585069135,"1023319724520":1509788624925,"1022645602595":1480585069135,"1023319724501":1509788624926,"1023638750929":1509788624968,"1022645602594":1480585069135,"1025278944300":1509788625002,"1023638750930":1509788624968,"1022645602599":1480585069135,"1023638750933":1509788624968,"1022645602598":1480585069135,"1022645602597":1480585069135,"1023638750935":1509788624968,"1023319724498":1509788624925,"1021967425862":1509788624464,"1025619089645":1509788625107,"1023638750938":1509788624968,"1025619089644":1509788625124,"1025619089643":1509788625115,"1025040530030":1509788624183,"1022463548627":1478686804067,"1022471799633":1480585069127,"1022471799629":1480585069127,"1022645602609":1480585069135,"1023319724487":1509788624926,"1025278944318":1509788625084,"1025619089649":1509788625087,"1023638750918":1509788624968,"1022645602619":1480585069135,"1023088240537":1509788624439,"1022471799621":1480585069121,"1022645602617":1480585069135,"1023638750925":1509788624968,"543798231":1478950494911,"1023088240609":1509788624439,"1013285093205":1480585069065,"1022471799614":1480585069127,"1022645602626":1480585069135,"1025516983998":1509788624308,"1023638750898":1509788624968,"1022645602630":1480585069135,"1023432448632":1509788624519,"1023638750902":1509788624968,"1023638750905":1509788624968,"1022645602634":1480585069135,"1023638750907":1509788624968,"1023638750911":1509788624968,"1025793410355":1509788624519,"1023319724454":1509788624926,"1025278944350":1509788625084,"1023088240629":1509788624439,"1023319724448":1509788624925,"1021919198235":1509788624548,"1024403902477":1509788624533,"1023638750893":1509788624968,"1023319724456":1509788624925,"1023319724459":1509788624933,"1023319724458":1509788624932,"1023319724437":1509788624926,"1023319724439":1509788624926,"1023319724438":1509788624925,"1023032140415":1509788667890,"1023319724434":1509788624925,"1023319724444":1509788624925,"1025736524205":1508316495865,"1023032140392":1509788667843,"1019013747432":1478686804049,"1019013747433":1478686804049,"1019013747430":1478686804049,"1021581281769":1478686417246,"1019013747431":1478686804049,"1019013747428":1478686804049,"1019013747429":1478686804049,"1019013747427":1478686804049,"1023319724426":1509788624925,"1022438775543":1480585069099,"1021650619379":1478686417049,"1022438775542":1480585069099,"1022608772308":1509788625075,"1022438775541":1480585069099,"1023924630085":1509788624961,"1022438775540":1480585069099,"1025428116650":1509788624434,"1019977920389":1509788625018,"1022438775538":1480585069099,"1022524491742":1509788625064,"1022438775537":1480585069099,"1022438775549":1480585069099,"1022438775548":1480585069099,"1025428116642":1509788624510,"1022438775547":1480585069099,"1019977920394":1509788625018,"1025428116644":1509788624511,"1022438775545":1480585069099,"1025428116647":1509788624424,"1022438775544":1480585069099,"1025428116646":1509788624433,"1019977920407":1509788625017,"122262362":1444487341747,"1022438775522":1480585069099,"1022438775520":1480585069099,"1025428116670":1509788624432,"1001645515339":1444487341708,"1019977920411":1509788625018,"1022438775510":1480585069099,"1025869958737":1509788667582,"1025869958736":1509788667653,"1019977920418":1509788625018,"1021395426080":1509788625082,"1022438775506":1480585069099,"1022438775518":1480585069099,"1022438775517":1480585069099,"1019977920429":1509788625018,"1022438775514":1480585069099,"1021303021240":1465469681397,"1022438775503":1480585069099,"1025869958731":1509788667596,"1022438775502":1480585069099,"1025869958730":1509788667665,"1002930509698":1478686804059,"1022438775501":1480585069099,"1025869958729":1509788667674,"1002930509699":1478686804059,"1025869958728":1509788667669,"1022036107976":1478686416973,"1002930509700":1478686804059,"1022438775499":1480585069099,"1002930509701":1478686804059,"1019977920440":1509788625018,"1025869958733":1509788667593,"1025869958732":1509788667598,"1020861818038":1478686804058,"1020861818039":1478686804058,"1022438775478":1480585069099,"1020861818036":1478686804058,"1022438775477":1480585069099,"1020861818037":1478686804058,"1022438775476":1480585069099,"1020861818034":1478686804058,"1022438775475":1480585069099,"1020861818035":1478686804058,"1022438775474":1480585069099,"1016858629594":1509788624976,"1020861818040":1478686804058,"1020861818041":1478686804058,"1022438775480":1480585069099,"1022438775463":1480585069099,"1023149845701":1509788625045,"1022438775462":1480585069099,"1022438775461":1480585069098,"1025869958695":1509788667414,"1025869958698":1509788667408,"1022438775469":1480585069099,"1025869958697":1509788667412,"1025869958696":1509788667413,"1022337588385":1478686417201,"1022438775465":1480585069099,"1025428116686":1509788624432,"1025278944234":1509788625001,"1025428116672":1509788624432,"1025278944231":1509788625084,"1022438775431":1480585069098,"1025869958659":1509788667913,"1022438775429":1480585069098,"1022438775427":1480585069098,"1022438775426":1480585069098,"1025428116700":1509788624467,"1025869958662":1509788667909,"1022438775425":1480585069098,"1025278944245":1509788624999,"1025869958666":1509788667892,"1021248099255":1478686417236,"1022438775436":1480585069098,"1025869958664":1509788667917,"1022438775435":1480585069098,"1022438775434":1480585069098,"1022438775433":1480585069098,"1022438775432":1480585069098,"1023730896780":1509788624960,"1021885512050":1478686417044,"1022148044960":1509788624944,"4564026497":1465469681387,"1014743422728":1480585069067,"1025458394731":1509788624351,"1010002279577":1491634246524,"1022127075273":1509788624338,"1022127075275":1509788624338,"1024943798051":1509788624563,"1019977920290":1509788625018,"1022079495399":1478686417061,"1021263305804":1478686417004,"1022204810337":1480585069085,"1024943798063":1509788624563,"1021955630345":1509788624464,"1019977920301":1509788625018,"1024943798059":1509788624563,"1024943798057":1509788624563,"1024943798056":1509788624563,"1019977920307":1509788625018,"1019977920304":1509788625017,"1021311671998":1465470268206,"1021311671999":1465470268206,"1021311671996":1465470268206,"1021311671997":1465470268206,"1021311671994":1465470268205,"1024132376411":1509788624326,"1019977920313":1509788625018,"1002930509690":1478686804059,"1021323599752":1465470268210,"1021323599753":1465470268210,"1002930509693":1478686804059,"1002930509694":1478686804059,"1020262815821":1465470268236,"1002930509695":1478686804059,"1019977920335":1509788625018,"1019977920333":1509788625018,"1020295584378":1509788625077,"1022532618124":1509788667501,"1019977920339":1509788625020,"1016092493807":1509788624941,"1019977920350":1509788625018,"1019977920344":1509788625018,"1019977920358":1509788625018,"1022011203731":1478686417159,"1024586357265":1509788624409,"1019977920354":1509788625018,"1024586357267":1509788624409,"1019977920367":1509788625018,"1019977920364":1509788625018,"1024586357253":1509788624409,"1021734907965":1478686417051,"1019977920371":1509788625018,"1019977920368":1509788625018,"1024586357250":1509788624409,"1024586357260":1509788624409,"1024586357262":1509788624409,"1024586357256":1509788624409,"1024586357258":1509788624409,"1025050885158":1509788624568,"1021584035535":1478686417114,"1025279468170":1509788624222,"1020878464224":1509788624934,"1020878464225":1509788624934,"1025050885171":1509788624568,"1025050885124":1509788624567,"1012265990664":1478686417025,"1021770691470":1478686417009,"1016758742592":1465470268315,"1020878464222":1509788624934,"1020878464223":1509788624934,"1021242331915":1478686417236,"1015048421444":1478686804040,"1023796038437":1509788624448,"1024764349805":1509788625024,"1023796038436":1509788624448,"1023796038439":1509788624448,"1023796038438":1509788624448,"1023796038443":1509788624448,"1023110128591":1509788624299,"1025050885223":1509788624567,"1022035583928":1478686417167,"1020977161043":1478686804039,"1025050885218":1509788624568,"1025050885229":1509788624567,"1025050885228":1509788624567,"1021438019540":1478686417241,"1025050885231":1509788624567,"1008048087523":1478686804025,"1008048087522":1478686804030,"1025050885238":1509788624567,"1025050885233":1509788624567,"1025906133375":1509788667458,"1010002279789":1491634246524,"1023924630290":1509788624961,"1025050885235":1509788624568,"1025050885244":1509788624568,"1499843643":1478686417023,"1025050885243":1509788624567,"1025050885189":1509788624568,"1022438775701":1480585069100,"1025050885191":1509788624568,"1022438775697":1480585069100,"1022438775696":1480585069100,"1025050885194":1509788624568,"1022438775687":1480585069100,"1022438775686":1480585069100,"1025050885204":1509788624567,"1025050885200":1509788624567,"1024587406258":1509788625070,"1022438775695":1480585069100,"1025050885212":1509788624567,"1025050885215":1509788624567,"1022438775692":1480585069100,"1022438775691":1480585069100,"1022438775690":1480585069100,"1025050885208":1509788624567,"1022438775689":1480585069100,"1022438775688":1480585069100,"1025050885210":1509788624568,"1021646031796":1478686417248,"1022438775671":1480585069100,"1022438775670":1480585069100,"1022438775668":1480585069100,"1022053540429":1509788625075,"1025428116778":1509788625127,"1022438775667":1480585069100,"1025428116781":1509788625127,"1001385210458":1480585069061,"1022438775665":1480585069100,"1025050885290":1509788624232,"1022438775655":1480585069099,"1022438775653":1480585069099,"1025050885303":1509788624232,"1022438775651":1480585069099,"1022438775650":1480585069099,"1025428116796":1509788625135,"1025050885298":1509788624232,"1025050885309":1509788624232,"1025050885308":1509788624232,"1023988989704":1509788625037,"1021537504535":1509788624397,"1022438775659":1480585069100,"1025050885305":1509788624232,"1025050885304":1509788624232,"1025428116788":1509788625127,"1025428116791":1509788625127,"1022438775656":1480585069099,"1025050885306":1509788624232,"1022438775633":1480585069099,"1018016142137":1509788624372,"1025428116763":1509788625244,"1022438775619":1480585069099,"1025428116764":1509788625245,"1022438775616":1480585069099,"1025428116766":1509788625128,"1022438775628":1480585069099,"1022438775607":1480585069099,"1022438775612":1480585069099,"1022438775609":1480585069099,"1022438775608":1480585069099,"1020861818150":1478686804034,"1020861818151":1478686804034,"1020861818148":1478686804034,"1020861818149":1478686804034,"1020861818146":1478686804034,"1020861818147":1478686804034,"1020805331334":1478686417030,"1020861818144":1478686804034,"1020861818145":1478686804034,"1020861818152":1478686804034,"1020861818153":1478686804034,"1022438775573":1480585069099,"1021749325832":1509788624403,"1022438775570":1480585069099,"1020861818142":1478686804034,"1020861818143":1478686804034,"1020861818140":1478686804034,"1020861818141":1478686804034,"1020861818138":1478686804034,"1020861818139":1478686804034,"1022438775577":1480585069099,"1022438775559":1480585069099,"1025279468148":1509788624222,"1022438775557":1480585069099,"1022438775556":1480585069099,"1025619091122":1509788624425,"1012039890778":1478686417025,"1025619091121":1509788624428,"1025619091120":1509788624431,"1022438775567":1480585069099,"1025619091135":1509788624406,"1022438775564":1480585069099,"1025279468153":1509788624222,"1022438775562":1480585069099,"1022438775561":1480585069099,"1025279468155":1509788624222,"1022438775560":1480585069099,"1025279468154":1509788624222,"1024586356983":1509788624410,"1020987253116":1478686417088,"1022010024547":1478686417159,"1021053054315":1478686417036,"1024586356978":1509788624410,"1024586356989":1509788624410,"1009269959630":1509788624389,"1024586356988":1509788624410,"1022622404591":1480585069131,"1024586356991":1509788624410,"1022010024554":1478686417159,"1024586356985":1509788624410,"1024607984006":1509788667589,"1024586356987":1509788624410,"1001645514847":1444487341708,"1024586356986":1509788624410,"1025551192426":1509788624341,"1024586356972":1509788624410,"1024586356974":1509788624410,"1023769693084":1509788624969,"1024586356946":1509788625092,"1022386871749":1478686417290,"1024586356935":1509788625091,"1024586356928":1509788625091,"1022010024543":1478686417159,"1024586356943":1509788625091,"1025017590047":1509788624437,"1021387430333":1478686417300,"1010681235359":1480585069072,"1024586356938":1509788625091,"1024586356918":1509788625091,"1018024923562":1509788624372,"1010681235429":1480585069072,"1024586356915":1509788625091,"1021584035202":1478686417114,"1013285092060":1480585069065,"1024586356921":1509788625091,"1024586356923":1509788625091,"1022255666574":1478686417196,"1018209338558":1478686804066,"1021053054271":1478686417036,"1018209338559":1478686804066,"1025415522618":1509788624346,"1016863217533":1478686804018,"1021261861195":1478686804039,"1024586356905":1509788625091,"1024586356904":1509788625091,"1024586356906":1509788625091,"1024586356881":1509788625091,"1025585798950":1509788624350,"1023692361304":1509788624325,"1013185867799":1478686804025,"1025585798952":1509788624351,"1022071893668":1478686417176,"1024586356870":1509788625091,"1024586356864":1509788625091,"1024586356876":1509788625091,"1024586356878":1509788625091,"1021156349752":1478686417038,"1020294142167":1465470268292,"1023924629560":1509788624961,"1024586356874":1509788625091,"1024586356853":1509788625091,"1022256715092":1478686417284,"1026232378975":1514456869770,"1024586356850":1509788625091,"1011694246863":1478686804061,"1011694246860":1478686804061,"1011694246858":1478686804061,"431984433":1491634246504,"1025599429634":1509788624437,"1020961038461":1478686417033,"1009525430809":1478686804015,"1011694246867":1478686804061,"1011279323788":1480585069074,"1021574597868":1509788624492,"1024586356835":1509788625091,"1024586356834":1509788625091,"1024586356845":1509788625091,"1303370550":1444487341717,"229874476":1478950494907,"1024586356842":1509788625091,"1303370511":1444487341723,"1022190905630":1478686417188,"1021873453608":1478686417053,"1022190905628":1478686417188,"1242815670":1478686417020,"1023796037815":1509788625160,"1023796037814":1509788625160,"1023796037817":1509788625160,"1023796037816":1509788625160,"1242815673":1478686417020,"1023796037818":1509788625160,"1242815678":1478686417020,"1021249671525":1478686417100,"1022232205205":1478686417193,"1023687380702":1509788625082,"1025592876110":1509788624930,"1022065729930":1478686417175,"1023453420739":1509788625008,"1022232205208":1478686417193,"1023453420733":1509788625008,"1024953758252":1509788624192,"1023453420734":1509788625008,"1023453420728":1509788625008,"1024953758247":1509788624192,"1022847463506":1509788624392,"1023453420724":1509788625008,"1024953758245":1509788624192,"1022847463505":1509788624392,"1024953758270":1509788624192,"1024953758268":1509788624192,"1024953758267":1509788624192,"1023453420715":1509788625008,"1022059045197":1509788624816,"1024953758263":1509788624192,"1023453420711":1509788625008,"1011694246811":1478686804061,"1023453420707":1509788625008,"1022182648039":1478686416975,"1022145424017":1478686417185,"1011694246820":1478686804061,"1003492160193":1478686417220,"1020994334219":1478686417088,"1016858630008":1509788624976,"1021953402666":1509788624466,"1242815713":1478686417020,"1010681235282":1480585069072,"1024953758235":1509788624192,"1023924629683":1509788624961,"1024953758232":1509788624192,"1017230213552":1478686804065,"1023791843498":1509788624173,"1024953758227":1509788624192,"1022145424014":1478686417184,"1021491495502":1478686417111,"1024586357236":1509788624409,"1024586357238":1509788624409,"1025607687446":1509788624973,"1022866337916":1509788624439,"1024586357244":1509788624409,"288458299":1478686417023,"1016690319504":1478686804063,"1016690319499":1478686804063,"1016690319498":1478686804063,"1016690319497":1478686804063,"1016690319496":1478686804063,"1016690319503":1478686804063,"1016690319502":1478686804063,"1016690319501":1478686804063,"1016690319500":1478686804063,"1024936326402":1509788625006,"1013185868130":1478686804025,"1016690319495":1478686804063,"1019783673892":1465470268236,"1024895694714":1509788624943,"1016858629819":1509788624976,"1025146435769":1509788624414,"1023796037946":1509788624562,"4810574230":1509788624155,"1025146435775":1509788624414,"1025146435773":1509788624414,"1023796037951":1509788624563,"1023796037950":1509788624563,"1024586357189":1509788624414,"1024586357191":1509788624414,"1022238627318":1509788624946,"1021999408176":1478686417157,"1024586357185":1509788624414,"1022238627325":1509788624931,"1022238627324":1509788624930,"1024586357199":1509788624414,"1024586357198":1509788624414,"1024586357192":1509788624414,"1024586357195":1509788624414,"1024586357194":1509788624414,"1022059045029":1509788624533,"1022238627322":1509788624932,"1021049908476":1478686417232,"1022298264085":1478686417199,"1025146435793":1509788624414,"1021229093457":1478686417039,"1024586357180":1509788624414,"1022059045073":1509788624194,"1024586357182":1509788624414,"1025146435807":1509788624414,"1023891600146":1509788624377,"1024586357176":1509788624414,"1024586357179":1509788624414,"1023796037952":1509788624563,"1022196541462":1478686417280,"1023796037954":1509788624563,"1025146435785":1509788624414,"1025146435791":1509788624414,"1012495756028":1478686804064,"1025146435831":1509788624414,"1025146435830":1509788624414,"1025146435828":1509788624414,"1010010406602":1491634246530,"1024586357125":1509788624411,"1024586357127":1509788624411,"1025146435809":1509788624414,"1024586357121":1509788624411,"1025146435815":1509788624414,"1025146435814":1509788624414,"1024586357123":1509788624411,"1025146435813":1509788624414,"1025146435812":1509788624414,"1022201522277":1478686417190,"1024586357128":1509788624411,"1025146435821":1509788624414,"1021932042377":1478686417010,"1024586357111":1509788624411,"1024586357110":1509788624411,"1024586357117":1509788624411,"1024586357116":1509788624411,"1024586357118":1509788624411,"1024586357113":1509788624411,"1024586357112":1509788624411,"1020925650071":1478686417000,"1018030034986":1509788624929,"1020861818721":1478686804057,"1020925650073":1478686417000,"1023796038065":1509788624223,"1021931911340":1478686417010,"1013185868252":1478686804032,"1024586357073":1509788624411,"1012791203914":1478686417224,"1024586357063":1509788624410,"1021597666473":1478686417115,"1024586357057":1509788624410,"1024586357059":1509788624410,"1020667311065":1478686804022,"1022940134562":1509788624508,"1024586357069":1509788624411,"1023796038058":1509788624223,"1023796038061":1509788624223,"1023796038060":1509788624223,"1023796038062":1509788624223,"1014509052510":1509788625017,"1024586357047":1509788624411,"1024586357043":1509788624410,"1024586357053":1509788624411,"1025619090574":1509788624746,"1024586357055":1509788624410,"1024586357054":1509788624411,"1025619090572":1509788624833,"1024005241941":1491634246533,"1025619090571":1509788624823,"1024586357048":1509788624411,"1025619090570":1509788624828,"1024586357050":1509788624411,"1129174189":1478686804029,"1021394901225":1509788624394,"1023924629935":1509788624961,"1024586356997":1509788624410,"1025869958535":1509788667515,"1025869958534":1509788667520,"1025869958533":1509788667517,"1025869958537":1509788667487,"1024586357000":1509788624410,"1022021168600":1509788624266,"1022021168601":1509788624267,"1024055965332":1509788624928,"1008662691865":1478686804030,"1022021168592":1509788624266,"1021925750625":1478686804048,"1022021168593":1509788624266,"1021925750626":1478686804048,"1022021168594":1509788624266,"1021925750627":1478686804048,"1022811946162":1509788624535,"1021925750628":1478686804048,"1022021168596":1509788624266,"1021925750629":1478686804048,"1022021168597":1509788624266,"1022036504316":1478686417267,"1019421901477":1478686804018,"1022021168599":1509788624266,"1022811946166":1509788624535,"1022021168585":1509788624267,"1022021168586":1509788624267,"1018980050703":1509788624315,"1022021168589":1509788624267,"1022021168590":1509788624266,"1022021168591":1509788624266,"1003675006784":1478686804060,"1003675006785":1478686804060,"1022021168577":1509788624267,"1022021168578":1509788624267,"1022021168583":1509788624266,"1025609651157":1509788624845,"1025609651156":1509788624845,"1446366739":1444487341752,"1025609651152":1509788624845,"1022459090826":1478686417217,"1022459090829":1478686417217,"1025609651163":1509788624845,"1022021168617":1509788624267,"1025035415552":1509788624269,"1022292893114":1478686417198,"1021925750620":1478686804048,"1021925750621":1478686804048,"1021925750622":1478686804048,"1021295284517":1478686417238,"1022021168609":1509788624267,"1022021168610":1509788624267,"1022021168611":1509788624267,"1022021168613":1509788624267,"1025513971124":1509788624344,"1022021168536":1509788625235,"364219895":1478686804024,"1024586356407":1509788624410,"1022021168541":1509788625235,"1024586356403":1509788624410,"1024586356413":1509788624410,"1022811946225":1509788624535,"1022294203868":1478686417015,"1022811946224":1509788624535,"1022021168530":1509788625235,"1024586356414":1509788624410,"1022021168531":1509788625235,"1024586356409":1509788624410,"1022021168532":1509788625235,"1024586356411":1509788624410,"1024625150155":1509788625100,"1022021168534":1509788625235,"1022021168535":1509788625235,"1019524544728":1509788624320,"1024586356389":1509788624410,"1022021168521":1509788625235,"1024586356391":1509788624410,"1020610034081":1509788624353,"1022021168525":1509788625235,"1002155920794":1478686804023,"1024586356397":1509788624410,"1024586356396":1509788624410,"1022021168513":1509788625235,"1024586356393":1509788624410,"1022021168516":1509788625236,"1022021168517":1509788625235,"1024586356395":1509788624410,"1022021168518":1509788625235,"1022021168519":1509788625235,"1003675006776":1478686804060,"1003675006777":1478686804060,"1021925750539":1478686804048,"1021925750540":1478686804048,"1003675006780":1478686804060,"1021925750541":1478686804048,"1022021168573":1509788624266,"1024621217958":1509788624939,"1003675006768":1478686804060,"1003675006769":1478686804060,"1000526146691":1444487341710,"1025018773349":1509788624462,"1021925750532":1478686804048,"1021925750533":1478686804048,"1003675006773":1478686804060,"1000526146695":1444487341721,"1003675006760":1478686804060,"1022021168552":1509788625235,"1020770857520":1478686417225,"1003675006763":1478686804060,"1022021168555":1509788625236,"1003675006764":1478686804060,"1022021168556":1509788625235,"1003675006765":1478686804060,"1003675006766":1478686804060,"1022339551416":1478686417069,"1003675006754":1478686804060,"1022021168546":1509788625235,"1020933778676":1478686417083,"1003675006756":1478686804060,"1021938854108":1509788624986,"1022021168548":1509788625235,"1003675006757":1478686804060,"1003675006759":1478686804060,"1022152631652":1478686417185,"1022152631651":1478686417185,"1025179986197":1509788624213,"1022934496204":1509788625052,"1020436876964":1478686804033,"1021902288483":1509788624465,"1009849960385":1478686804067,"1021918410592":1509788624827,"1018199640345":1509788625080,"1024132377467":1509788624326,"1022021168506":1509788625235,"1022021168508":1509788625236,"1025628656755":1509788624433,"1022021168510":1509788625236,"1022062587885":1478686417174,"1022811945997":1509788624535,"1022455158603":1478686417297,"1022811945984":1509788624535,"1022274542619":1478686417014,"1025628656751":1509788625001,"1025628656750":1509788625001,"1007973119925":1478686804032,"1015591595474":1478686804016,"4979798042":1509788624156,"1023531013907":1509788625082,"1021850252083":1509788625078,"1025540579061":1509788624302,"1025540579062":1509788624302,"1022811946074":1509788624535,"1025540579059":1509788624302,"1020940332237":1478686417084,"1025540579068":1509788624302,"1022075822192":1509788624416,"1025540579070":1509788624302,"1020612655425":1478686416982,"1025540579064":1509788624302,"1025540579067":1509788624302,"1021681301745":1509788624396,"1022811946070":1509788624535,"1021661104036":1509788624396,"1021252558704":1478686417236,"1021252558705":1478686417237,"1025540579055":1509788624303,"1025540579051":1509788624303,"1024625150341":1509788624533,"1022811946417":1509788624819,"1024547689002":1509788625070,"1022013173084":1478686417159,"1022013173085":1478686417159,"1025540579097":1509788624303,"1022811946421":1509788624819,"1024625150344":1509788624193,"1021374453578":1478686417104,"1024586356709":1509788625090,"1024586356711":1509788625090,"1019105894031":1478686804023,"1024586356710":1509788625090,"1015242160348":1480585069068,"1019105894027":1478686804032,"1012392734396":1478686417074,"1024586356716":1509788625091,"1024586356713":1509788625090,"1022075036056":1478686417012,"1024586356715":1509788625090,"1024586356714":1509788625090,"1024586356693":1509788625090,"1024586356701":1509788625090,"1024586356703":1509788625090,"1024586356702":1509788625090,"1024586356697":1509788625090,"1024625150388":1509788624819,"1025909933349":1509788667463,"1022811946368":1509788624819,"821406132":1491634246517,"1025319313513":1509788624181,"1025319313524":1509788624182,"1022811946475":1509788624819,"1022811946474":1509788624819,"1020605184372":1478686417224,"1021113607848":1478686417233,"1021934266803":1478686417055,"1021934266800":1478686417055,"1022431302679":1478686417212,"1021589406411":1478686417114,"370773830":1491634246519,"1025319313477":1509788624181,"1025319313479":1509788624182,"1025319313473":1509788624182,"4979798453":1509788624156,"1025319313474":1509788624182,"1021784063635":1478686417255,"1025319313480":1509788624182,"1020982013650":1478686417087,"1025796952023":1509788624406,"1021477604770":1478686417242,"1010681235489":1480585069072,"1021244825487":1478686417100,"1018517765379":1480585069070,"1022240070463":1478686417283,"1025796951865":1509788624185,"1024973421653":1509788624173,"1025796951861":1509788624203,"1022811946273":1509788624535,"1024005239302":1491634246533,"1022811946267":1509788624535,"1023820560696":1491634246535,"1022469707441":1478686417219,"1024132377171":1509788624326,"1021925750443":1478686804048,"1021925750444":1478686804048,"1021925750445":1478686804048,"1021925750446":1478686804048,"1021925750447":1478686804048,"1022811946366":1509788624819,"1023220098448":1509788625042,"1025796951930":1509788624832,"1021925750448":1478686804048,"1021925750449":1478686804048,"1020653943427":1478686804057,"1021925750450":1478686804048,"1021925750451":1478686804048,"1021041255362":1478686417092,"1025301881293":1509788624932,"1022240070471":1478686417283,"1021041255372":1478686417092,"1021497921287":1478686417244,"1021918410263":1509788624916,"1021316649513":1478686417238,"1019028167638":1509788624314,"1020291258114":1465470268317,"1020438187982":1478686804031,"1021640525714":1509788624815,"1020438187981":1478686804031,"1022811946306":1509788624819,"1012120370692":1478686417025,"1022811946310":1509788624819,"1021061702935":1509788624933,"1019364101177":1509788624312,"1022811946683":1509788624820,"1023638753143":1509788624966,"1022811946686":1509788624820,"1023638753145":1509788624966,"1022146733653":1478686417185,"1023638753147":1509788624966,"1019166183919":1478686804020,"1023638753146":1509788624966,"1023638753149":1509788624966,"1023638753150":1509788624966,"1016609712212":1478686804022,"1024204074409":1509788667509,"1018447903434":1509788624933,"1009849959800":1478686804067,"1023820561079":1491634246535,"1022204812004":1480585069084,"1020951998372":1478686417085,"1024529731686":1509788624428,"1021885511620":1478686417044,"1022191822261":1478686417279,"1022029950827":1478686416985,"1016399740148":1480585069069,"1024529731691":1509788624436,"1022227356590":1478686417013,"1022524492260":1509788624413,"1023638753073":1509788624966,"1023638753072":1509788624966,"1023638753075":1509788624966,"1023638753074":1509788624966,"1022811946749":1509788624820,"1022811946751":1509788624820,"1023638753079":1509788624966,"1021558866691":1509788624397,"1022177141797":1509788624868,"1023638753080":1509788624966,"1023638753082":1509788624966,"1023638753084":1509788624966,"1022227356612":1478686417014,"1022227356615":1478686417014,"1023638753063":1509788624966,"1015599721678":1478686804016,"122264849":1444487341730,"1023638753064":1509788624966,"370773059":1491634246519,"1023638753067":1509788624966,"1023638753066":1509788624966,"1022227356623":1478686417014,"1022004260480":1478686417157,"1023638753070":1509788624966,"1021550085037":1478686417245,"1000333079293":1478686804050,"1025551850786":1509788624336,"1021597401456":1478686417048,"1024520294570":1509788625028,"610123308":1478686417017,"1021179025814":1478686417098,"1025731938547":1509788624922,"4964466073":1509788624163,"912370915":1478686416992,"1023638753267":1509788624965,"1023638753269":1509788624965,"1023638753268":1509788624965,"1023638753271":1509788624965,"1023638753270":1509788624965,"1446366396":1444487341755,"1023638753272":1509788624965,"1018135287786":1509788624298,"1022645600279":1480585069095,"1023638753253":1509788624965,"1023638753255":1509788624965,"1023638753254":1509788624965,"1023638753257":1509788624965,"1023638753256":1509788624965,"1446366383":1444487341751,"1023638753259":1509788624965,"1022645600286":1480585069095,"1023638753263":1509788624965,"1022645600284":1480585069095,"1021740416563":1478686417125,"1022645600298":1480585069095,"1022092206902":1478686417274,"1022811946517":1509788624819,"1025790267294":1509788624348,"1022645600301":1480585069095,"1022811946519":1509788624819,"1022223686428":1509788624946,"1023638753201":1509788624966,"1023638753200":1509788624966,"1023638753203":1509788624966,"1022811946618":1509788624820,"1018335691680":1478686804065,"1022811946621":1509788624820,"1023638753205":1509788624967,"1023638753207":1509788624966,"1021622962014":1509788624404,"1022309407814":1478686417199,"309692581":1491634246534,"1023638753185":1509788624967,"1023638753184":1509788624967,"1023638753187":1509788624968,"1021650617638":1478686417049,"1023638753189":1509788624967,"1023638753188":1509788624967,"1023638753191":1509788624966,"1023638753190":1509788624966,"1024625150553":1509788624419,"1022484122305":1509788624394,"1021380089076":1478686417006,"1023638753183":1509788624966,"1020927618565":1478686417082,"1023638753153":1509788624966,"1023638753152":1509788624966,"1025365452439":1509788624205,"1025365452438":1509788624201,"1023638753154":1509788624966,"1023638753157":1509788624966,"1021380089060":1478686417006,"1023638753161":1509788624966,"1021380089067":1478686417006,"1022811946560":1509788624819,"1022386999575":1478686417205,"1023638753163":1509788624966,"1023638753162":1509788624966,"1025365452441":1509788624186,"1025365452440":1509788624198,"1022811946564":1509788624820,"1021625714254":1478686417117,"1012120370425":1478686417025,"1009849959517":1478686804067,"1023730893026":1509788624960,"1021321498750":1478686804039,"1023843891747":1509788624940,"1303369402":1444487341725,"1021471182746":1478686417045,"1021471182749":1478686417045,"1022207826843":1478686417191,"1024512299647":1509788624855,"1020968644018":1478686417086,"1022058785974":1475218613699,"1649932647":1444487341720,"1024132376785":1509788624326,"1364052602":1478950494922,"1024607982768":1509788667589,"1022479141677":1478943089254,"1012618059536":1509788625017,"1021565288872":1478686417114,"1021641573673":1478686417008,"1014129460589":1478686804019,"1024194637179":1509788625034,"1019872800412":1478686804021,"1021095781815":1478686417094,"1021054623791":1478686417036,"1022811946969":1509788624195,"1025034105670":1509788624454,"1020294141390":1465470268292,"1022811946961":1509788624195,"1024983907922":1509788624924,"1024194374956":1509788624184,"4979798864":1509788624156,"1022811946809":1509788624820,"1019552069991":1480585069074,"1000333079312":1478686804051,"1019552069996":1480585069074,"1019552069998":1480585069074,"1019552069999":1480585069074,"1022811946805":1509788624820,"1019552069995":1480585069074,"1000333079301":1478686804050,"1019552070000":1480585069074,"1000333079298":1478686804050,"1019552070001":1480585069074,"1024936327564":1509788625006,"1000333079296":1478686804050,"1024195030448":1509788625034,"1000333079308":1478686804050,"1022294203912":1478686417015,"1000333079305":1478686804050,"1024586356053":1509788624410,"1024586356055":1509788624410,"1021159496337":1478686417097,"1021778820491":1478686417128,"1024586356050":1509788624410,"1020705586569":1478686416996,"1024586356058":1509788624410,"1019719972694":1509788624313,"1024586356037":1509788624410,"1024586356032":1509788624410,"1025470060959":1509788624309,"1024586356045":1509788624409,"1024586356041":1509788624410,"1022365897362":1509788624925,"4954373362":1509788624156,"1024586356042":1509788624409,"1021219266117":1478686416974,"1022074512204":1509788624213,"1021219266119":1478686416975,"1019787209512":1509788624316,"1024586356028":1509788624410,"1023821478816":1491634246536,"1020785799344":1478686417029,"1024586356027":1509788624410,"1024586356026":1509788624409,"1019787209520":1509788624312,"1021219266135":1478686416975,"1022811946858":1509788624195,"1024634457027":1509788667618,"1020785799337":1478686417029,"1446366703":1444487341754,"1002035730120":1478686417024,"1024512299653":1509788624855,"1024512299650":1509788624855,"1022811946855":1509788624195,"1024512299649":1509788624855,"1025074081821":1509788625007,"1024512299648":1509788624855,"1021500542242":1478686417046,"1021556376206":1478686417113,"1021500542244":1478686417046,"1021602645830":1478686417008,"1026225042629":1514456869772,"1016363038955":1478686804071,"1021918409743":1509788624826,"1021300004571":1480585069071,"1021091979564":1478686417036,"1023088240641":1509788624439,"1008664528345":1478686804030,"1021716692933":1509788624396,"1021468297347":1478686417108,"1021114262520":1478686417037,"1024538515346":1509788624433,"1019560853026":1509788624316,"1021539075287":1478686417007,"1021655860161":1478686417120,"1019037343741":1480585069070,"1019871357356":1478686804057,"1019871357357":1478686804057,"1019622324869":1509788624316,"1019871357358":1478686804057,"1019871357359":1478686804057,"1019871357352":1478686804057,"1019871357353":1478686804057,"1019871357354":1478686804057,"1019871357355":1478686804057,"1025301881974":1509788624932,"1022882984996":1509788625053,"1019871357351":1478686804057,"1019149014705":1509788625080,"1009849959231":1478686804067,"1025270688380":1509788625242,"1022161805819":1509788624935,"1022161805816":1509788624935,"1024030929042":1509788624517,"1021138394364":1478686417037,"1022811813939":1509788624183,"1020878466428":1509788624934,"1020878466431":1509788624934,"1022089848110":1478686417062,"1020878466426":1509788624934,"1020878466427":1509788624934,"1008713156487":1509788624283,"1022161805795":1509788624935,"1022161805793":1509788624935,"1021837145676":1509788624324,"1022161805798":1509788624935,"1022244921083":1478686416978,"1022161805797":1509788624935,"1022161805786":1509788624935,"1022161805787":1509788624935,"1022161805784":1509788624935,"1013319955164":1480585069065,"1022161805790":1509788624935,"1018283133484":1465470268271,"1022161805776":1509788624935,"1021573809869":1478686417114,"1010025346675":1491634246516,"1022161805782":1509788624935,"1022161805780":1509788624935,"1022161805781":1509788624935,"1024030929057":1509788624517,"1024375987663":1509788624858,"1024375987662":1509788624858,"1022161805771":1509788624935,"1024375987661":1509788624858,"1022161805768":1509788624935,"1024375987660":1509788624858,"1016758609873":1478686804022,"1024375987659":1509788624858,"1010025346669":1491634246527,"1010025346671":1491634246521,"1022737351602":1509788625074,"1925836403":1444487341709,"1022161805764":1509788624935,"1022161805755":1509788624935,"1022327102301":1478686417015,"1022161805753":1509788624935,"1024342614967":1509788624413,"1024774440305":1509788624473,"1023031356747":1509788625048,"1021681433798":1509788624958,"1022272837691":1478686416976,"1022079362228":1478686417301,"1016779055319":1478686804017,"1023821479062":1491634246536,"1021492414883":1478686417046,"1024194636591":1509788625071,"1024132378348":1509788624324,"1021208254754":1478686804026,"1024333832950":1509788625032,"1015242161375":1480585069068,"1021281785044":1478686417004,"1012120369891":1478686417025,"1024030929166":1509788624523,"192517722":1478686417019,"1024030929185":1509788624521,"1023638751296":1509788624966,"1021721280139":1478686804040,"1022435889204":1478686417213,"1024030929190":1509788624523,"1022204812785":1480585069084,"1023638751280":1509788624966,"1022052100775":1478686417269,"1023638751286":1509788624966,"1023638751289":1509788624966,"1023638751292":1509788624966,"1023638751295":1509788624966,"1023638751265":1509788624966,"1023638751264":1509788624966,"1023638751267":1509788624966,"1009849958919":1478686804067,"1023638751269":1509788624966,"1020604136708":1478686417027,"1023638751271":1509788624966,"1023638751277":1509788624966,"1023638751276":1509788624966,"1023638751248":1509788624966,"1013103295542":1478686804016,"1023638751236":1509788624966,"1023638751244":1509788624966,"1022278867200":1478686417014,"4999197819":1509788667392,"4999197820":1509788667392,"1744958855":1444487341722,"1022199423679":1478686417064,"1016661878958":1478686804063,"1021803066704":1478686804069,"1022707467130":1509788625057,"1021602644280":1509788624404,"1016661878962":1478686804042,"1021061702004":1478686417093,"1021338014003":1465470268220,"1021338014004":1465470268220,"1021338014005":1465470268220,"1021338014007":1465470268220,"1025447779386":1509788624455,"1021338014008":1465470268221,"1021338014009":1465470268221,"1025823558285":1509788667843,"1025115500681":1509788624373,"1025115500680":1509788624373,"1024652414765":1509788624213,"1022079231380":1478686417012,"1649934212":1444487341734,"1025115500702":1509788624392,"1002077277511":1478686417024,"1022354756645":1478686416990,"1022363800745":1480585069075,"1021265007913":1478686417237,"1020551823526":1478686804027,"1021886951474":1478686804048,"1021742119301":1478686417125,"1022196277942":1478686417280,"1025665618048":1509788625131,"1020606103090":1478686417061,"1018967204290":1480585069065,"1022091945860":1478686417180,"1025365451383":1509788624543,"1025365451382":1509788624541,"1024343269733":1509788625070,"1021385724320":1478686417300,"1022866340193":1509788624439,"1016399870160":1480585069069,"1022866340199":1509788624439,"1025365451385":1509788624524,"1025365451384":1509788624537,"1020999444106":1478686416990,"1020999444107":1478686416990,"1021007963667":1509788624921,"1022092601262":1478686417012,"1022562503587":1509788625063,"1025646613397":1509788624306,"1017124310917":1478686804018,"1016092495111":1509788624941,"1022312028199":1509788625078,"1024132378016":1509788624324,"1024030929494":1509788624521,"1025665618125":1509788624270,"1025665618127":1509788624270,"1025665618129":1509788624227,"1022811945705":1509788624534,"1025665618131":1509788624227,"1025665618130":1509788624227,"1022982336709":1509788624982,"1025665618132":1509788624199,"1020748445666":1478686417028,"1025665618134":1509788624215,"1025665618138":1509788624207,"1025665618141":1509788624207,"1022811945701":1509788624534,"1009100484006":1478686804052,"1025665618144":1509788624207,"1025665618149":1509788624207,"1021158842180":1478686417097,"1022078838318":1478686417272,"1022292368346":1478686417068,"1023988069617":1509788624257,"1020804543027":1478686417030,"1020804543020":1478686417030,"1024370089896":1509788624169,"1025665618173":1509788624230,"1025007499686":1509788624977,"343247605":1444487341726,"1023151023842":1509788624978,"1021010454172":1478686417089,"1024124906721":1509788625071,"1022501425063":1509788624211,"1022138606203":1478686417063,"1013319954654":1480585069065,"1022469575078":1478686417219,"1025365451469":1509788625089,"1025365451468":1509788625109,"1025365451467":1509788625126,"1025365451466":1509788625117,"1001673696828":1478686804029,"1019061328528":1478686804039,"1020976638121":1478686417087,"1022078576374":1478686417177,"1025616205100":1509788624929,"1021708827825":1478686417122,"1023848479802":1509788667535,"1022475865712":1478943089486,"1021483895576":1478686417046,"1025665618017":1509788625246,"4985829326":1508316495865,"1025665618019":1509788625244,"1025665618021":1509788625165,"1024481106384":1509788624294,"1022078576288":1478686417177,"1021631349752":1509788624400,"1021848417525":1509788624394,"1025665618032":1509788625165,"1025665618035":1509788625112,"1025665618034":1509788625165,"1021863097823":1478686417053,"1021770693035":1478686417009,"1025565874065":1509788624372,"1025365451628":1509788624824,"1025365451631":1509788624800,"1019434878188":1509788624390,"1019434878189":1509788624391,"1019434878190":1509788624391,"1025365451627":1509788624834,"1019434878191":1509788624391,"1025365451626":1509788624829,"1019434878192":1509788624391,"1019434878193":1509788624391,"1006867968505":1509788624388,"1019434878194":1509788624391,"1025879524563":1509788667511,"1019434878195":1509788624391,"1019434878196":1509788624391,"1019434878197":1509788624391,"1020365311353":1478686804021,"1020726687741":1509788624375,"1022811945881":1509788624535,"1022811945887":1509788624535,"1015479922832":1509788624171,"1025365451612":1509788624408,"1025365451609":1509788624429,"1025365451611":1509788624426,"1025365451610":1509788624432,"1020606103410":1478686417027,"1019704374453":1509788625077,"1024936328531":1509788625006,"1025891058779":1509788667448,"1025879524523":1509788667663,"1009832263976":1509788625081,"1024935017848":1509788624851,"1024935017850":1509788624851,"1024935017847":1509788624851,"1022811945922":1509788624535,"1024935017846":1509788624851,"1022811945925":1509788624535,"1024935017843":1509788624851,"1025879524419":1509788667907,"1021924569117":1478686417141,"1012685952935":1478686416995,"1021540124641":1478686417047,"1022185267606":1478686417064,"1022092469778":1509788624416,"1022811945769":1509788624535,"1022811945772":1509788624535,"1022185267592":1478686417064,"1025879524453":1509788667592,"1004349245606":1478686804039,"1023463511155":1509788625039,"1021476162535":1478686417109,"1022962020881":1509788624509,"1025879524471":1509788667411,"1020294009111":1465470268280,"1023946389723":1491634246531,"1012392732774":1478686417074,"1019817881291":1465470268275,"1022079362955":1478686417301,"1021901631795":1509788624420,"1021354529348":1465470268231,"1022811945833":1509788624535,"1021354529350":1465470268231,"1020806771692":1478686417030,"1022811945835":1509788624535,"1024244573831":1509788624949,"1579794928":1444487341747,"1025301882828":1509788624932,"1009965971878":1491634246523,"1022204813090":1480585069084,"1021193051328":1478686417038,"1022054328373":1478686416977,"1025618957488":1509788624848,"1025100418133":1509788624273,"1025703374918":1509788624297,"1023970757004":1509788625037,"1021578672693":1478686417008,"1024597503546":1509788624938,"1025040386512":1509788624548,"1025040386525":1509788624539,"1022231421259":1509788624931,"1025040386526":1509788624566,"1021913288246":1478686417259,"1025040386520":1509788624567,"1025040386534":1509788624544,"1025040386529":1509788624536,"1023164782997":1509788625044,"1025791718712":1509788625165,"1025791718714":1509788625165,"1009862672451":1491634246513,"1025791718708":1509788625245,"1025791718710":1509788625244,"1020744632769":1509788624322,"1021232244468":1478686417099,"1025301878806":1509788624932,"1024302374393":1509788625080,"1024132371417":1509788624327,"1021736207517":1509788624400,"1022375471853":1478686417290,"1025791718733":1509788625168,"1009862672440":1491634246514,"1021983150666":1478686417152,"1025791718731":1509788625130,"1025791718730":1509788625130,"1025040386461":1509788624612,"1025040386460":1509788624611,"1025040386463":1509788624565,"1025791718726":1509788625130,"1024607989718":1509788667589,"1025791718722":1509788625130,"1021027359092":1478686417091,"1025040386468":1509788624552,"1025040386470":1509788624548,"1025040386465":1509788624565,"1025040386467":1509788624552,"1025040386466":1509788624564,"1024211408712":1509788625032,"1016779054151":1478686804017,"1021664395120":1478686417120,"1023820415212":1509788624969,"1025040386481":1509788624548,"1025040386480":1509788624548,"1022412696605":1478686417292,"1021514053270":1509788625018,"1022457392986":1480585069111,"1025735881459":1508316495865,"1020925514636":1478686417082,"1022041216525":1478686417268,"1020744632693":1509788624322,"1020784872421":1478686417076,"1022457392981":1480585069087,"1020925514651":1478686417082,"1021638573595":1478686417119,"1025283397592":1509788624598,"1020834549252":1478686804031,"1020925514649":1478686417082,"1021054622691":1478686417036,"1025540581005":1509788624302,"1020925514643":1478686417082,"1019160423109":1480585069078,"1020925514646":1478686417082,"1020657730433":1478686804057,"1869467598":1478686417021,"1869467591":1478686417020,"1022381501177":1478686417290,"1869467606":1478686417021,"1021716284248":1509788624403,"1869467602":1478686417021,"1021042432759":1478686417092,"1025040386304":1509788624841,"1019899401877":1509788624971,"1023844925889":1491634246536,"1025040386306":1509788624841,"1025322457567":1509788624305,"1019310240702":1509788624314,"1025040386325":1509788624841,"1025040386322":1509788624841,"1025040386329":1509788624868,"1025040386330":1509788624826,"1011737636938":1478686804024,"1010093493834":1478686804055,"1016857715070":1509788624977,"1020744632599":1509788624322,"1021700555294":1478686804047,"1024132371173":1509788624327,"1023309504538":1509788624376,"1022058780305":1475218613699,"1023032529026":1509788624508,"1020595732932":1478686416972,"1020744632559":1509788624322,"1022070708706":1478686417060,"1021138395485":1478686417037,"1025100418422":1509788624173,"1021794797170":1509788624399,"1025246172329":1509788624931,"1025040386280":1509788624916,"1025040386282":1509788624916,"1025040386292":1509788624865,"1022042003370":1478686417170,"1025040386303":1509788624849,"1023820415393":1509788624960,"1025040386299":1509788624865,"1019728350508":1509788624312,"1021815245138":1509788624850,"1021815245139":1509788624850,"1021815245137":1509788624849,"1021815245141":1509788624850,"1022457917071":1478686417072,"153331784":1491634246512,"1022029681698":1478686417165,"1021460574810":1478686417044,"1019303031457":1509788624316,"1022029681700":1478686417165,"1015070717823":1478686804053,"1015070717822":1478686804053,"1015070717825":1478686804053,"1021919317583":1509788625069,"1015070717827":1478686804053,"1015070717828":1478686804053,"1023106847884":1509788624466,"1023402960617":1509788625071,"724011652":1444487341753,"1025100418554":1509788624181,"1025731949345":1509788624922,"1021733586248":1509788624395,"1016690316891":1478686804069,"1025040386053":1509788624210,"1016690316890":1478686804069,"1025040386052":1509788624210,"1021248759300":1478686416988,"1016690316889":1478686804069,"1025040386055":1509788624210,"1016690316888":1478686804069,"1021743678850":1478686417253,"1016690316895":1478686804069,"1024460138431":1509788624451,"1016690316894":1478686804069,"1016690316893":1478686804069,"1016690316892":1478686804069,"1016690316883":1478686804069,"1023020208615":1509788625083,"1016690316882":1478686804069,"1016690316887":1478686804069,"1025040386057":1509788624210,"1016690316886":1478686804069,"1016690316885":1478686804069,"1016690316884":1478686804069,"1022400506603":1478686417207,"1021828089995":1478686417133,"1025040386064":1509788624210,"1021182566924":1478686417098,"1010013538420":1491634246521,"225684626":1444487341746,"1025040386084":1509788624210,"1010013538422":1491634246521,"1025040386081":1509788624210,"1010013538419":1491634246526,"1025040386090":1509788624230,"1024270522968":1509788624340,"1025040386098":1509788624206,"1016690316896":1478686804069,"1020264656277":1509788624945,"1024270522962":1509788625019,"1024270522965":1509788624335,"1024270522964":1509788625001,"1024270522967":1509788624337,"1024270522966":1509788624336,"1025061226631":1509788624940,"1018947542253":1509788624276,"1022238630093":1509788624946,"1001385199061":1480585069061,"1016779054625":1478686804017,"1022646925411":1480585069146,"1022646925410":1480585069146,"1022646925408":1480585069146,"1022238630101":1509788624931,"1022238630100":1509788624941,"1025629974197":1509788624174,"1025629974196":1509788624174,"1025629974199":1509788624174,"1022238630098":1509788624931,"1025629974201":1509788624174,"1022238630110":1509788624931,"1025629974205":1509788624174,"1022409289380":1480585069098,"109290654":1500459286943,"1025629974207":1509788624175,"1022238630107":1509788624932,"1025212092841":1509788624269,"1025212092840":1509788624268,"1025212092843":1509788624268,"1024937624007":1509788625006,"1022646925388":1480585069146,"1025212092842":1509788624269,"1022646925387":1480585069146,"1022646925385":1480585069146,"1025212092847":1509788624268,"1024937624003":1509788625006,"1022646925384":1480585069146,"1025212092833":1509788624269,"1021776577637":1478686417128,"1025212092832":1509788624268,"1025212092835":1509788624269,"1025212092837":1509788624269,"1018665340910":1509788624377,"1024937624011":1509788625006,"1022646925407":1480585069146,"1025212092857":1509788624268,"1022646925405":1480585069146,"1021708681291":1478686417122,"1023431273372":1509788625079,"1021708681292":1478686417122,"1022646925401":1480585069146,"1025212092863":1509788624269,"1022646925400":1480585069146,"1024937624018":1509788625006,"1022646925399":1480585069146,"1025212092848":1509788624268,"1022646925397":1480585069146,"1025212092850":1509788624268,"1024906429434":1509788624938,"1025212092853":1509788624268,"1022646925394":1480585069146,"1022646925359":1480585069145,"1025212092872":1509788624268,"1025212092875":1509788624269,"1022600918382":1480585069134,"1022646925356":1480585069145,"1025791719262":1509788625165,"1022646925355":1480585069145,"1025791719259":1509788625165,"1020117328152":1465470268310,"1025791719251":1509788625244,"1025212092870":1509788624268,"1025791719250":1509788625245,"1022646925375":1480585069146,"1025212092889":1509788624268,"1025212092888":1509788624268,"1022646925373":1480585069146,"1025283396891":1509788625222,"1025773631074":1509788624289,"1025773631077":1509788624289,"1025849654237":1509788667467,"1022646925370":1480585069146,"1022646925368":1480585069146,"1024132370866":1509788624327,"1025773631081":1509788624289,"1022918232091":1509788624915,"1022646925366":1480585069146,"1025773631080":1509788624289,"1022646925365":1480585069146,"1025773631083":1509788624289,"1022646925364":1480585069146,"1025212092882":1509788624268,"1022646925363":1480585069146,"1025773631085":1509788624289,"1022933567781":1509788624311,"1025773631084":1509788624289,"1025773631087":1509788624289,"1022646925360":1480585069145,"1025629974209":1509788624175,"1022646925326":1480585069145,"1025629974208":1509788624174,"1024211801416":1509788625033,"1012152076923":1478686804022,"1022646925319":1480585069145,"1025791719285":1509788625168,"1025629974216":1509788624174,"1004243088142":1480585069072,"1025629974219":1509788624174,"1022646925316":1480585069145,"1022646925314":1480585069145,"1025791719280":1509788625130,"1025629974225":1509788624174,"1024186766550":1509788624272,"1025791719276":1509788625129,"1025791719279":1509788625129,"1004243088144":1480585069072,"1025791719274":1509788625130,"1025791719268":1509788625144,"1022646925333":1480585069145,"1025791719271":1509788625130,"1022646925332":1480585069145,"1022646925331":1480585069145,"1024840908757":1509788624174,"1022316487845":1478686417200,"1012759359307":1478686417074,"1025629318715":1509788624186,"1025061226519":1509788624932,"1025629318714":1509788624197,"1025629318713":1509788624204,"1025629318712":1509788624200,"1025616341255":1509788624929,"1022646925519":1480585069146,"1022646925516":1480585069146,"1024186766339":1509788624920,"1015237821098":1478686804053,"1021442617586":1478686417044,"1022646925511":1480585069146,"1022646925508":1480585069146,"1022646925507":1480585069146,"1022646925504":1480585069146,"1021956805380":1478686417056,"1022092204839":1478686417274,"1022646925522":1480585069146,"1022646925520":1480585069146,"1022646925487":1480585069146,"1022646925486":1480585069146,"1025791719388":1509788624227,"1022646925482":1480585069146,"1022646925480":1480585069146,"1025791719381":1509788624270,"1025485922718":1509788625136,"1022646925476":1480585069146,"1025791719382":1509788624270,"1020756691957":1478686417076,"1022646925472":1480585069146,"1017436914126":1478686804015,"1022646925496":1480585069146,"1021509334153":1509788624398,"1022646925494":1480585069146,"1022047900924":1478686417059,"1020902838462":1478686417227,"1022646925489":1480585069146,"1022646925488":1480585069146,"1024384245760":1509788624329,"1021850765575":1478686417257,"1022646925448":1480585069146,"1022646925445":1480585069146,"1021613276902":1480585069071,"1022646925470":1480585069146,"1010002660035":1491634246524,"1022646925469":1480585069146,"1022646925467":1480585069146,"109290612":1500459286943,"1025791719402":1509788624206,"1022646925463":1480585069146,"1025791719397":1509788624215,"1010002660043":1491634246524,"1025791719399":1509788624206,"1025791719398":1509788624206,"1022646925459":1480585069146,"1022646925456":1480585069146,"1023612286949":1509788624955,"1023612286951":1509788624955,"1023612286950":1509788624955,"1023612286944":1509788624955,"1023612286947":1509788624955,"1021700555256":1478686804047,"1023612286953":1509788624955,"1022416105311":1480585069075,"1023612286955":1509788624955,"1022003075011":1478686417011,"1023165569685":1509788624216,"1023165569684":1509788624216,"1022700666442":1509788624973,"1023165569687":1509788624216,"1023165569686":1509788624216,"1023165569681":1509788624216,"1022418202408":1478686417293,"1021700555245":1478686804047,"1021700555242":1478686804047,"1022418202387":1478686417293,"1016779054857":1478686804017,"1456731637":1444487341753,"1022646925640":1480585069079,"1456731643":1444487341750,"1022126151862":1478686417276,"1022646925635":1480585069079,"1023612286932":1509788624955,"1023612286935":1509788624955,"1023612286931":1509788624955,"1482423148":1478686804024,"1023612286940":1509788624955,"1023612286936":1509788624955,"1022418202383":1478686417293,"1023612286938":1509788624955,"1022646925612":1480585069079,"1022646925607":1480585069079,"1021500552585":1478686804031,"1021315475611":1465470268208,"1022646925626":1480585069079,"1021966897731":1478686417056,"1022646925621":1480585069079,"1021616422563":1478686417117,"1022646925616":1480585069079,"1022646925577":1480585069079,"1021054752797":1478686417232,"1020497181151":1478686804034,"1024186766793":1509788625248,"1024225827587":1509788625032,"1022646925596":1480585069079,"1022646925591":1480585069079,"1022646925588":1480585069079,"1022646925587":1480585069079,"1022192606208":1478686417188,"1021578148264":1478686417048,"1021934785389":1509788625069,"1020878459494":1509788624280,"1022079228891":1478686417012,"1025485922506":1509788624437,"1024132370502":1509788624327,"1022457392254":1480585069110,"1022092204598":1478686417273,"1023994349955":1491634246518,"1023612286757":1509788624955,"1023612286764":1509788624955,"1024343006375":1509788624991,"1023612286772":1509788624955,"1023612286769":1509788624955,"1024343006377":1509788624991,"1021857450049":1478686417053,"1022941957926":1509788624325,"1018509492460":1509788624214,"1007394827883":1509788624379,"1023612286732":1509788624955,"1023612286735":1509788624955,"1007840462072":1509788624376,"1023612286729":1509788624955,"1023612286728":1509788624955,"1024343006360":1509788624991,"1021869903660":1478686416983,"1023612286741":1509788624955,"1022127069337":1509788624338,"1023612286740":1509788624955,"1023932089344":1491634246530,"1023612286736":1509788624955,"1023612286749":1509788624955,"1023612286751":1509788624955,"1021541186447":1478686417007,"1018916085552":1478686804032,"1023171599657":1509788624493,"1025243943331":1509788624999,"1024688730328":1509788624199,"1022646926955":1480585069148,"1023171599662":1509788624493,"1020437541424":1478686804065,"1023171599652":1509788624493,"1020437541426":1478686804065,"1022646926945":1480585069148,"1023171599655":1509788624493,"1022415710276":1478686417209,"1024375072120":1509788625155,"1022646926969":1480585069148,"1010011442594":1491634246525,"1022037807817":1478686417011,"1024375072122":1509788625155,"1021516542932":1478686417047,"1022646926966":1480585069148,"1024375072116":1509788625155,"1022102429434":1478686417181,"1022646926965":1480585069148,"1024375072119":1509788625155,"1024375072118":1509788625155,"1023242377484":1509788624462,"1022646926961":1480585069148,"1021516542931":1478686417047,"1010011442580":1491634246525,"1022086438357":1478686417062,"1023171599626":1509788624493,"1022646926921":1480585069148,"1022724652010":1509788624998,"1025711240686":1509788625019,"1023994351127":1491634246518,"1024906429929":1509788624938,"1022646926918":1480585069148,"1010011442590":1491634246525,"1010011442591":1491634246525,"1024906429930":1509788624938,"1026226604826":1514456869770,"1021344966694":1478686804023,"1022646926915":1480585069148,"1010011442584":1491634246525,"1022921641507":1509788624293,"1025372919871":1509788624541,"193310632":1478686417019,"1021143508024":1478686417096,"1022292894137":1478686417198,"1023171599640":1509788624493,"1022646926941":1480585069148,"1022646926938":1480585069148,"1022646926937":1480585069148,"1022646926936":1480585069148,"1023171599646":1509788624493,"1022374162155":1478686417204,"1022646926933":1480585069148,"1023171599634":1509788624493,"1022646926930":1480585069148,"1023171599636":1509788624493,"1022646926928":1480585069148,"1023171599638":1509788624493,"1022154725764":1478686416975,"1022646926883":1480585069147,"1025372919875":1509788624524,"1022646926910":1480585069148,"1025372919873":1509788624537,"1022471419062":1478686417299,"1022646926908":1480585069148,"1025372919872":1509788624543,"1022646926906":1480585069147,"1025349459756":1504776656202,"1022646926902":1480585069147,"1022415710263":1478686417209,"1024132372357":1509788624324,"1023171599689":1509788624493,"1023171599691":1509788624493,"1019167109022":1509788624316,"1023171599693":1509788624493,"1023171599684":1509788624493,"1024244571429":1509788624948,"1022886120540":1509788625053,"1444278881":1444487341752,"1022646926874":1480585069147,"1023171599708":1509788624493,"1022415710255":1478686417209,"1023171599697":1509788624493,"1022646926869":1480585069147,"1022646926867":1480585069147,"1023171599700":1509788624493,"1023171599703":1509788624493,"1022502090169":1509788624330,"1444278937":1444487341754,"1024797916887":1509788625024,"1021512217263":1478686417047,"1444278922":1444487341752,"1025470719647":1509788624304,"1021597679547":1478686417048,"1022646927050":1480585069080,"1023995006608":1491634246532,"1022054323045":1478686416977,"1022646927048":1480585069080,"1022341786645":1509788625007,"1022341786644":1509788625007,"1022341786639":1509788625007,"1022020374901":1478686417266,"1022646927065":1480585069080,"1022646927061":1480585069080,"1008664542534":1478686804030,"1022646927058":1480585069080,"1444278955":1444487341751,"1022646927023":1480585069080,"1025731950157":1509788624922,"1022646927021":1480585069079,"1025791717854":1509788624837,"1025791717848":1509788624849,"1025791717846":1509788624825,"1025900378184":1509788667457,"1023596427064":1509788624519,"1025791717842":1509788624864,"1022646927039":1480585069080,"1025791717833":1509788624916,"1022646927034":1480585069080,"790334413":1444487341749,"1025791717835":1509788624916,"1022646927032":1480585069080,"1022646927027":1480585069080,"1022646927026":1480585069080,"1022444939896":1478686417214,"1022185265906":1478686417278,"1025791717887":1509788624270,"1022359219538":1478686417203,"1022444939889":1478686417214,"1025372920033":1509788625110,"1022646927001":1480585069079,"1025857387973":1509788667463,"1021256491957":1478686417040,"1022646926998":1480585069079,"1025791717863":1509788624837,"1025791717859":1509788624837,"1014741854016":1478686804022,"1025791717858":1509788624837,"1021729523260":1509788624514,"1023336638065":1509788624990,"1024343005813":1509788624991,"1025533502311":1509788624347,"1025533502310":1509788624347,"1025533502313":1509788624347,"1025616211611":1509788624929,"1025533502315":1509788624347,"590579256":1478686804024,"1024343005820":1509788624991,"1024343005819":1509788624991,"1023336638077":1509788624991,"1024343005817":1509788624991,"1025533502318":1509788624346,"1025533502320":1509788624347,"1023336638050":1509788624990,"1024343005798":1509788624991,"1021403166112":1478686417043,"1021200130491":1465470268194,"1023336638048":1509788624990,"1025533502325":1509788624347,"1025512923299":1509788624338,"1025593667539":1509788624833,"1023336638059":1509788624990,"1025593667538":1509788624829,"1024343005804":1509788624991,"1025512923302":1509788624339,"1025593667541":1509788624800,"1023994351392":1491634246518,"1025512923300":1509788624336,"1025593667540":1509788624823,"1023336638033":1509788624991,"1014208848":1444487341726,"1023336638039":1509788624990,"1020264655175":1509788624971,"1023336638018":1509788624991,"1025593667583":1509788624537,"1025593667582":1509788624542,"1025593667581":1509788624541,"1023336638031":1509788624990,"1022264583780":1478686417067,"1025784508501":1509788624349,"1023336638029":1509788624990,"1023336638000":1509788624991,"1022134279769":1478686417276,"1025593667458":1509788624407,"1025593667456":1509788624425,"1023431798007":1509788624519,"1023431798006":1509788624519,"1023336637986":1509788624990,"1022431176729":1480585069077,"1023431798005":1509788624519,"1025806398318":1509788667447,"1022431176735":1480585069077,"1023431798003":1509788624518,"1025593667475":1509788624198,"1022431176722":1480585069077,"1025593667474":1509788624204,"1021551279239":1509788624397,"1023336637994":1509788624990,"1025593667473":1509788624200,"1024384247738":1509788624329,"1025593667476":1509788624186,"1022456867492":1478686417216,"1022431176743":1480585069077,"1020233985839":1465470268316,"1021472371197":1478686417109,"1022431176740":1480585069077,"1015394586530":1465470268313,"1024030656917":1509788624853,"1021262258837":1478686417101,"1023266888223":1509788624354,"1023221406165":1509788625072,"1020774387584":1478686417029,"1024030656925":1509788624853,"1024030656924":1509788624853,"1025797354286":1509788624866,"1023336638202":1509788624992,"1020878853240":1478686417079,"1023336638207":1509788624992,"1233120498":1509788625019,"1024030656923":1509788624853,"1023336638204":1509788624992,"1020617622780":1478686804035,"1023336638189":1509788624992,"1009169683048":1478686804028,"1021981841281":1509788624996,"1025593667455":1509788624431,"416005502":1478950494909,"1025593667454":1509788624428,"1024030656930":1509788624853,"1021176670090":1478686416974,"1021738697072":1478686417252,"1022565920906":1480585069141,"1021386123900":1478686417300,"1021744333203":1478686417254,"1010091920140":1491634246522,"1010091920144":1491634246522,"1021354534982":1465470268231,"1021354534983":1465470268231,"1010091920147":1491634246522,"1010091920150":1491634246522,"1023054813160":1509788624825,"1022096399492":1478686417181,"1024030657013":1509788624444,"1024030657012":1509788624445,"1024030657015":1509788624444,"1020257708305":1465470268311,"1024030657011":1509788624444,"1009994796386":1491634246520,"1024607988320":1509788667589,"1020807547330":1478686417077,"1024343005828":1509788624991,"1024343005827":1509788624991,"1024343005825":1509788624991,"1024132371986":1509788624324,"1024343005824":1509788624991,"1024030657007":1509788624444,"1021978040243":1478686417150,"1024343005833":1509788624991,"724143394":1444487341728,"1024906430421":1509788624938,"1003504337785":1478686804017,"1025748727195":1509788624290,"1002457252325":1491634246520,"1003504337783":1478686804017,"1003504337779":1478686804017,"1025791718207":1509788624207,"1020974534680":1478686417086,"1025791718195":1509788624215,"1023995530301":1491634246532,"1024783630083":1509788625024,"1025791718188":1509788624227,"1025791718190":1509788624227,"1016689660340":1465470268266,"1025791718184":1509788624227,"1025791718183":1509788624270,"1022029157241":1478686417164,"1024005229989":1491634246533,"1025791718179":1509788624270,"4964188587":1509788624157,"1019778156832":1509788624315,"1023947689655":1491634246532,"1016911979029":1478686804031,"1025784116171":1509788624352,"1022304166051":1478686417199,"245213378":1444487341718,"1023947689656":1491634246532,"1019958779082":1478686804034,"1025791718269":1509788625130,"1019958779083":1478686804034,"1021975024889":1509788625144,"1019958779080":1478686804034,"1021309185099":1478686417102,"1019958779081":1478686804034,"1019958779086":1478686804034,"1024454238385":1509788624990,"1025791718265":1509788625130,"1019958779087":1478686804034,"1025791718264":1509788625130,"1019958779084":1478686804034,"1019958779085":1478686804034,"1024454238386":1509788624990,"1025791718260":1509788625130,"1022342835941":1478686417202,"1019958779078":1478686804034,"1025791718257":1509788625144,"1019958779079":1478686804034,"1025791718256":1509788625111,"1019958779096":1478686804034,"1019958779097":1478686804034,"1019958779103":1478686804034,"1024912066333":1509788624926,"1019958779090":1478686804034,"1025791718245":1509788625244,"1019958779088":1478686804034,"1024454238383":1509788624990,"1019958779089":1478686804034,"1025791718246":1509788625165,"1019958779094":1478686804034,"1019958779092":1478686804034,"1019958779093":1478686804034,"1025791718242":1509788625245,"1019166059883":1478686804020,"1022362234851":1478686417289,"1021460575671":1478686417045,"1023924617428":1509788624961,"1018644630918":1478686804026,"1025791718273":1509788625130,"1025791718333":1509788624207,"1020772813953":1478686417029,"1025791718334":1509788624207,"1024687420009":1509788624999,"1006742388935":1478686804032,"1025791718327":1509788624215,"1025791718323":1509788624227,"1018912021920":1509788624283,"1025791718316":1509788624270,"1009198390960":1478686804054,"1025791718318":1509788624270,"1024687420026":1509788624998,"1024687420025":1509788625001,"724143506":1444487341726,"1022711674888":1509788624466,"1025703376638":1509788624295,"1009094579350":1509788624389,"1023324316873":1509788624926,"1025791718353":1509788624230,"1009994796632":1491634246520,"1025791718344":1509788624207,"1025791718347":1509788624207,"1023324316889":1509788624925,"1022221199128":1478686417281,"1023454604444":1509788625039,"1021606591050":1509788624397,"4935614706":1509788624157,"1022191819118":1478686417013,"1021435016271":1478686417044,"1022393691499":1478686417015,"1010830670900":1478686804064,"1015299031697":1478686804064,"1022646926703":1480585069146,"1025791717917":1509788624207,"1025044844160":1509788624389,"1022646926701":1480585069146,"1022646926700":1480585069146,"1022646926699":1480585069146,"1022646926697":1480585069146,"1022966860411":1509788624996,"1022646926694":1480585069146,"1021184664766":1478686417235,"1022646926692":1480585069146,"1022966860406":1509788624996,"1025791717905":1509788624207,"1022646926689":1480585069146,"1025791717907":1509788624207,"1022966860402":1509788624996,"1021534240722":1478686417113,"1022646926718":1480585069147,"1025791717903":1509788624207,"1022966860398":1509788624996,"1022966860393":1509788624996,"1022646926714":1480585069147,"1025791717898":1509788624207,"228305539":1444487341745,"1023924617567":1509788624961,"1022646926709":1480585069146,"1025791717889":1509788624270,"1025791717891":1509788624227,"1024375072333":1509788624858,"1024375072332":1509788624858,"1021831630374":1478686417133,"1020657730622":1478686804058,"1024375072335":1509788624858,"1301539504":1491634246513,"1024375072334":1509788624858,"1023324316970":1509788624926,"1021188727889":1478686417003,"1021188727895":1478686417003,"1023324316961":1509788624926,"1023324316960":1509788624926,"1022646926687":1480585069146,"1025441359565":1509788625161,"1022646926682":1480585069146,"1025441359560":1509788625161,"1021726508144":1478686417051,"1025441359559":1509788625161,"1025441359558":1509788625161,"1022646926677":1480585069146,"1022278869828":1478686417014,"1022278869827":1478686417014,"1025441359555":1509788625161,"1024375072336":1509788624858,"1022646926673":1480585069146,"1023324316977":1509788624926,"1022073462782":1509788624280,"1025791717980":1509788625130,"1022112914691":1478686417276,"1025791717977":1509788625144,"1022378618148":1509788624300,"1025791717965":1509788625244,"1025791717967":1509788625165,"1021736207239":1509788624400,"1025791717963":1509788625245,"1023835883241":1491634246504,"1023994350946":1491634246518,"1021006520112":1509788624921,"1025791717997":1509788625130,"1025791717998":1509788625130,"1020777794688":1478686417029,"1025791717988":1509788625130,"1025791717985":1509788625130,"1018633096401":1465470268271,"1025791718045":1509788624864,"1021280218727":1478686417040,"1021096958320":1478686417094,"1020610152052":1509788624940,"1021975024914":1509788625166,"1025191515471":1509788624930,"1022025880093":1478686416975,"1025791718035":1509788624916,"1025009188910":1509788624334,"1025791718030":1509788624916,"1020117460165":1465470268321,"1024444277456":1509788624991,"1022646926798":1480585069147,"1022025880116":1478686416975,"1016444161932":1478686804023,"1016444161930":1478686804023,"1025791718067":1509788624837,"1022646926784":1480585069147,"1022646926813":1480585069147,"1022646926812":1480585069147,"1023110123840":1509788624299,"1024375072473":1509788624561,"1024375072472":1509788624561,"1016444161937":1478686804034,"1022646926809":1480585069147,"1025791718058":1509788624837,"1024375072469":1509788624561,"1022646926806":1480585069147,"1024375072471":1509788624561,"1022670519485":1509788625060,"1024375072470":1509788624561,"1021033913615":1478686417091,"1023110123827":1509788624299,"1024375072429":1509788624443,"1024375072428":1509788624443,"1022646926765":1480585069147,"1023110123825":1509788624299,"1024375072431":1509788624443,"1022646926763":1480585069147,"1025791718105":1509788624837,"1022646926762":1480585069147,"1023110123830":1509788624299,"1022646926761":1480585069147,"1024375072427":1509788624443,"1022646926760":1480585069147,"1024375072426":1509788624443,"1022646926759":1480585069147,"1022646926758":1480585069147,"1025791718100":1509788624837,"1022646926757":1480585069147,"1023110123832":1509788624299,"1025703376780":1509788624295,"1022646926752":1480585069147,"1025791718098":1509788624837,"1022646926782":1480585069147,"1013272890620":1509788624372,"1024115856693":1509788667888,"1022646926778":1480585069147,"405258224":1491634246533,"1022917447064":1509788624298,"1022646926774":1480585069147,"1022917447060":1509788624298,"1023110123823":1509788624299,"1023110123822":1509788624299,"1022646926768":1480585069147,"1022646926732":1480585069147,"1022646926730":1480585069147,"1022917447082":1509788624298,"1022646926729":1480585069147,"4899963880":1509788624156,"1022646926728":1480585069147,"1022646926727":1480585069147,"1025797353807":1509788624848,"1022646926725":1480585069147,"1022646926723":1480585069147,"1021287558779":1478686416990,"1022646926722":1480585069147,"1021735027492":1509788624997,"1022646926720":1480585069147,"1025791718125":1509788624868,"1022646926750":1480585069147,"1022646926749":1480585069147,"1022917447101":1509788624298,"1016857716335":1509788624977,"1013208531191":1478686804062,"1022646926748":1480585069147,"1022646926747":1480585069147,"1021722575984":1509788624395,"1022646926745":1480585069147,"1021097220406":1478686417232,"1022917447095":1509788624293,"1025044844155":1509788624388,"1025044844157":1509788624388,"1025044844156":1509788624388,"1025044844159":1509788624389,"1022917447088":1509788624298,"1025044844158":1509788624389,"1020748693941":1509788624440,"1025791589656":1509788624409,"1024132373480":1509788624324,"1019455599806":1478686804021,"1022390674404":1478686417015,"1024637614471":1509788667502,"1023088237673":1509788624439,"1024331732554":1509788667536,"1022286081117":1478686417198,"1023088237677":1509788624439,"1023088237676":1509788624439,"1024637614474":1509788667503,"1023088237679":1509788624439,"1023088237681":1509788624439,"1022984554015":1509788624915,"1024680082190":1509788625213,"1019455599814":1478686804021,"1021975157497":1509788624464,"1019455599820":1478686804021,"1019455599817":1478686804021,"1024818099062":1509788624929,"1024818099077":1509788624929,"1025703377091":1509788624295,"1021425187268":1478686804065,"1020966411824":1509788624369,"1021704620598":1478686417050,"1015659090306":1480585069068,"1024637614422":1509788667503,"1021983021712":1478686417152,"1015659090312":1480585069069,"1550185668":1478686417020,"1024637614433":1509788667502,"1024818099106":1509788624929,"1456733792":1444487341723,"1022098887049":1509788624190,"1022440744556":1478686417295,"1024818099122":1509788624929,"1021774876324":1478686804066,"1021551931648":1509788624405,"1024637614359":1509788667502,"1010321691623":1478686804049,"1025609917218":1509788624915,"1025376326923":1509788624305,"1021438556746":1509788624817,"1024637614360":1509788667502,"1024637614373":1509788667503,"1024637614372":1509788667503,"1021968996893":1509788624463,"1024637614381":1509788667502,"1024637614378":1509788667503,"1024637614377":1509788667503,"1024637614391":1509788667503,"1024375073177":1509788624220,"1021774089827":1478686417128,"1024375073176":1509788624220,"1024375073179":1509788624220,"1024637614385":1509788667503,"1020975718143":1478686417229,"1024375073175":1509788624220,"1024375073174":1509788624220,"1024637614395":1509788667503,"1024403385120":1509788624279,"1025477143331":1509788625248,"1024194895572":1509788625034,"1024637614392":1509788667502,"1021494393891":1509788624398,"1025429301684":1509788624433,"1025429301682":1509788624433,"1025429301681":1509788624510,"1025429301680":1509788624510,"1021175360298":1465470268188,"1020391407088":1478686804071,"1025429301691":1509788624432,"1025429301690":1509788624427,"1020064246131":1465470268277,"1022403125767":1478686417207,"1021692168298":1478686417121,"1022075818426":1509788624550,"1024680082047":1509788624597,"1025881502340":1509788667403,"1019294645102":1509788624312,"1025429301637":1509788625171,"1021774876505":1478686804066,"1025429301636":1509788625127,"1025429301634":1509788625127,"1025429301633":1509788625127,"1025881502357":1509788667403,"1023071590918":1509788624533,"1023071590917":1509788625101,"1022307577749":1478686417199,"1022478891475":1478943089487,"1025710848143":1509788624305,"1022478891476":1478943089487,"1021781036864":1509788624395,"1022074769882":1478686417271,"1021913941860":1509788624465,"1021539086792":1478686417245,"4976116219":1509788624158,"1025569546552":1509788624351,"1022069526943":1478686417301,"1025429301712":1509788624466,"1025429301724":1509788624437,"1021925606912":1478686416979,"1025429301703":1509788624432,"1025429301706":1509788624432,"1024680082143":1509788624589,"1024412691119":1509788667829,"1025710848076":1509788624306,"1024680082140":1509788624589,"1009999905216":1491634246516,"1024680082136":1509788624590,"1025428121888":1509788624359,"1024680082134":1509788624590,"1024680082133":1509788624589,"1019022797595":1480585069072,"1024680082131":1509788624590,"1024680082129":1509788624590,"1010391574908":1478686804071,"1024680082127":1509788624590,"1024680082124":1509788624590,"1024680082121":1509788624589,"1024412691123":1509788667830,"1021774876663":1478686804066,"1024412691122":1509788667456,"4649237634":1478686416965,"1025906144692":1509788667460,"1012272535918":1478686417073,"1020763112308":1478686417076,"245212991":1444487341715,"1019775272470":1509788624376,"1024412691103":1509788667465,"1021546033592":1478686417300,"1024680082151":1509788624590,"1024680082150":1509788624590,"1012321426014":1478686804062,"1024680082148":1509788624590,"1020975587250":1478686416974,"1024680082147":1509788624590,"1016244549044":1509788624309,"1024680082146":1509788624590,"1025296503103":1509788624371,"1024680082145":1509788624589,"1024680082144":1509788624589,"1024680082078":1509788624597,"1012174750585":1478686417073,"1024680082076":1509788624597,"1024680082073":1509788624597,"1024680082070":1509788624597,"1025429301629":1509788625127,"1024680082066":1509788624597,"1020673723846":1478686804022,"1025881502317":1509788667403,"1024680082062":1509788624597,"1024723730295":1509788667889,"1025429301603":1509788625128,"1024680082058":1509788624597,"1019018734341":1509788624315,"1025429301600":1509788625128,"1023946378947":1491634246531,"1025429301615":1509788625127,"1023946378946":1491634246531,"1023946378945":1491634246529,"1025710848021":1509788624305,"1024680082053":1509788624597,"1025881502329":1509788667403,"1024680082051":1509788624597,"1023946378948":1491634246531,"1014487948604":1478686804046,"1025429301590":1509788625244,"1025429301597":1509788625245,"1023110127388":1509788624299,"1024680082092":1509788624598,"1024680082091":1509788624597,"1022191818361":1478686417013,"1024680082089":1509788624597,"1024680082084":1509788624597,"1024680082082":1509788624597,"1024680082081":1509788624597,"1024680082080":1509788624597,"1016399727819":1480585069069,"1024187686077":1509788624502,"1024187686076":1509788624502,"1024187686079":1509788624502,"1024187686065":1509788624502,"1024187686071":1509788624502,"1024215864059":1509788624220,"1021793095012":1478686417129,"1024215864063":1509788624220,"1024187686060":1509788624502,"1021793095014":1478686417129,"1024215864061":1509788624220,"1024187686063":1509788624502,"1024215864060":1509788624220,"1024187686049":1509788624502,"1021928752455":1509788624974,"1021997177137":1478686417265,"1024187686053":1509788624502,"1024187686052":1509788624502,"1024215864053":1509788624220,"1024187686055":1509788624502,"1023009856211":1509788625049,"1025906144821":1509788667459,"1024187686040":1509788624502,"1024187686043":1509788624502,"1021793094995":1478686417129,"1024187686044":1509788624502,"1981144115":1478950494930,"1981144114":1478950494930,"1021793095000":1478686417129,"1519120545":1491634246505,"1024187686035":1509788624502,"1519120544":1491634246505,"1021793095004":1478686417129,"1024187686037":1509788624502,"1024187686025":1509788624502,"1024187686030":1509788624502,"1022517557277":1509788625064,"1020294145170":1465470268293,"1022251477057":1478686417196,"1024215863979":1509788624850,"1024187686136":1509788624503,"1024215863978":1509788624851,"1024215863977":1509788624851,"1021944355343":1478686417144,"1024187686138":1509788624503,"1024187686141":1509788624503,"1024215863981":1509788624850,"1519120577":1491634246505,"1024187686131":1509788624503,"1021708421168":1478686804043,"1021708421169":1478686804043,"1024215863974":1509788624850,"1021708421164":1478686804043,"1021708421165":1478686804043,"1021774875707":1478686804065,"1021708421166":1478686804043,"1021708421167":1478686804043,"1021708421160":1478686804043,"1021708421161":1478686804043,"1021708421162":1478686804043,"1021708421163":1478686804043,"1021708421156":1478686804043,"1021708421157":1478686804043,"1024187686112":1509788624503,"1021708421158":1478686804043,"1024187686115":1509788624503,"1021708421159":1478686804043,"1021708421152":1478686804043,"1024187686117":1509788624503,"1021708421153":1478686804043,"1008828762198":1478686804064,"1021708421154":1478686804043,"1021708421148":1478686804043,"1025375934373":1509788625019,"1021708421150":1478686804043,"1020933512943":1478686417083,"1021708421151":1478686804043,"1024187686106":1509788624503,"1021695445829":1509788624818,"1014742772196":1480585069062,"1024187686099":1509788624502,"1021700294804":1478686804027,"1024187686101":1509788624503,"1024187686100":1509788624503,"1021695445854":1509788624195,"1024187686080":1509788624502,"1024187686085":1509788624502,"1016399858869":1480585069069,"1025906144853":1509788667459,"1021998356925":1478686417156,"1022143321603":1480585069083,"1023979406224":1509788625017,"1022392639786":1478686417206,"1021770026101":1509788624395,"1021326352768":1478686417103,"1025671783556":1509788624943,"1001732936106":1478686417023,"1018938496822":1509788624386,"1024786509909":1509788624512,"986026097":1478686804024,"1007973107123":1478686804033,"1023071590787":1509788624194,"1018469124911":1509788624825,"1016930988001":1478686804019,"1024187686011":1509788624502,"1019552843835":1478686804015,"1024187686010":1509788624502,"1010813629187":1509788624277,"1024187686014":1509788624502,"4935617766":1509788624157,"1021020017577":1478686417001,"1024752562722":1509788667502,"1506800413":1444487341752,"1021708421288":1478686804064,"1023381466239":1509788624393,"1021708421287":1478686804064,"1023716225039":1491634246528,"1024879310238":1509788624226,"1024879310237":1509788624226,"1024879310236":1509788624226,"1024879310235":1509788624226,"1024879310232":1509788624226,"1021981579482":1478686417151,"1001732936169":1478686417023,"1024752562717":1509788667502,"1020117330343":1465470268310,"1021695445975":1509788624420,"1024752562719":1509788667502,"1024752562712":1509788667502,"1023150887576":1509788624977,"2001984595":1478686417021,"2001984593":1478686417021,"2001984597":1478686417021,"1021507894646":1509788624398,"2001984596":1478686417021,"1024688209860":1509788624895,"1024132372716":1509788624324,"1022014349097":1509788624949,"1025191516628":1509788624930,"1021338019720":1465470268221,"1021338019722":1465470268221,"1024953092101":1509788625023,"1021757705800":1478686417126,"1019128963865":1509788624298,"1023835884183":1491634246504,"1021757705798":1478686417126,"1026226603009":1514456869768,"1022461846693":1478686417298,"1022204816382":1480585069084,"1025733523880":1509788624959,"1011857571005":1478686804024,"1018517753803":1480585069070,"1003492151144":1478686417220,"1021727164428":1478686417123,"1021395952713":1478686417043,"1022288834194":1478686417286,"461746399":1444487341740,"1022282280782":1478686417014,"1022288834220":1478686417286,"1021400808379":1478686417006,"1001732935784":1478686417023,"1584133380":1491634246508,"1024786510231":1509788624466,"1024786510230":1509788624461,"1024786510229":1509788624512,"1023377403286":1509788624367,"149791641":1444487341753,"1025619091507":1509788624537,"1025619091506":1509788624542,"1025619091505":1509788624540,"1021038760242":1478686417092,"1025619091514":1509788624523,"1021648663658":1509788625082,"1016704734007":1478686804051,"1023844928141":1491634246537,"1021885499007":1478686417044,"1025856729776":1509788667459,"1025733523727":1509788624959,"1024124377571":1509788625071,"1012276730640":1478686804064,"1025246174751":1509788624931,"1024215864139":1509788625153,"1024215864138":1509788625153,"1020784607439":1509788624385,"1024215864140":1509788625153,"1020257707868":1465470268311,"1024187686161":1509788624503,"1024187686160":1509788624503,"1022429079232":1509788624177,"1024187686162":1509788624503,"1024215864134":1509788625153,"1024161734538":1509788667562,"1025619091703":1509788624204,"1024187686153":1509788624503,"1025619091702":1509788624200,"1024187686155":1509788624503,"1024187686154":1509788624503,"1024187686156":1509788624503,"1024187686158":1509788624503,"1024215864147":1509788625153,"1024187686144":1509788624503,"1023845059262":1491634246537,"1021343393694":1478686417103,"1022089318932":1478686417180,"1024187686148":1509788624503,"1025619091705":1509788624186,"1024187686151":1509788624503,"1001732935865":1478686417023,"1025619091704":1509788624197,"1024215864110":1509788624560,"1021695445738":1509788624534,"1024215864103":1509788624560,"1024215864102":1509788624560,"1024215864101":1509788624560,"1024215864100":1509788624560,"1007584490383":1478950494938,"1021698460365":1478686417121,"1010919142514":1495284743424,"1009094580667":1509788624389,"1020438068702":1478686804039,"1018990947216":1509788624392,"1022364197540":1478686417203,"1022270353178":1480585069093,"1022270353180":1480585069093,"1001897455274":1478686804029,"1022646924909":1480585069144,"1024680083291":1509788625209,"1024680083290":1509788625209,"1024461318735":1509788624852,"1024680083288":1509788625209,"1022646924903":1480585069144,"1024680083287":1509788625209,"1024680083286":1509788625209,"1022646924901":1480585069144,"1024680083285":1509788625209,"1024680083283":1509788625209,"1024680083281":1509788625209,"1022646924896":1480585069144,"1024680083280":1509788625209,"1024680083279":1509788625209,"1025906667571":1509788667459,"1024680083278":1509788625209,"1021687713194":1509788624404,"1024680083277":1509788625209,"1025906667569":1509788667462,"1025423928573":1509788624292,"1024680083275":1509788625209,"4899964955":1509788624158,"1024680083274":1509788625209,"1024680083273":1509788625209,"1025906667573":1509788667460,"1024680083272":1509788625209,"1025906667572":1509788667459,"1021979614799":1478686417263,"1024461318739":1509788624852,"1024461318738":1509788624852,"1022226050457":1478686417064,"1022646924915":1480585069144,"1024461318741":1509788624852,"1022646924914":1480585069144,"1024461318740":1509788624852,"1023612287175":1509788624956,"1022646924875":1480585069144,"1023612287171":1509788624956,"1023612287180":1509788624956,"1023612287183":1509788624956,"1025523935551":1509788624428,"1025115619685":1509788624970,"1022646924865":1480585069144,"1023612287179":1509788624956,"1022737363749":1509788624989,"1021708422739":1478686804065,"1018310931666":1478686804028,"1022646924893":1480585069144,"1022646924892":1480585069144,"1022646924888":1480585069144,"1009094581860":1509788624389,"1022646924886":1480585069144,"1001732937529":1478686417023,"1024734607904":1509788624939,"1023612287141":1509788624956,"1022646924846":1480585069144,"1021835429512":1478686416982,"1022646924841":1480585069144,"1010023630516":1491634246516,"1022646924839":1480585069144,"1021244172864":1509788624342,"1023612287145":1509788624956,"1023612287144":1509788624956,"1023612287146":1509788624956,"1025523935554":1509788624425,"1022646924861":1480585069144,"1025523935553":1509788624431,"1023612287158":1509788624956,"1023890147360":1491634246506,"1025523935557":1509788624407,"1023612287155":1509788624956,"1022646924855":1480585069144,"1023612287164":1509788624956,"1021944486932":1478686417144,"1022646924850":1480585069144,"1023612287163":1509788624956,"1023540716406":1509788625008,"1022646924813":1480585069144,"1000090465922":1478950494931,"1022646924812":1480585069144,"1021352960491":1465469681398,"1021993770770":1478686417156,"1021993770768":1478686417156,"1022646924831":1480585069144,"1023636797725":1509788624948,"1022646924825":1480585069144,"1021488364006":1478686417243,"1022646924823":1480585069144,"1022646924819":1480585069144,"1022646924818":1480585069144,"1021488364000":1478686417243,"1022646924816":1480585069144,"1023612287077":1509788624956,"1023612287076":1509788624956,"1023612287073":1509788624956,"1022646925033":1480585069144,"1022646925031":1480585069144,"1022316620470":1478686417288,"1023612287084":1509788624956,"1022646925028":1480585069144,"1022285293713":1478686417198,"1023612287081":1509788624956,"1023612287080":1509788624956,"1022646925024":1480585069144,"1023612287082":1509788624956,"1021937540166":1478686417143,"1023612287094":1509788624956,"1022096397769":1478686417181,"1023612287088":1509788624956,"1023612287091":1509788624956,"1013175896462":1478686804015,"1021937540173":1478686417143,"1023612287100":1509788624956,"1022331562951":1478686417201,"1023612287097":1509788624956,"1021937540170":1478686417143,"1023612287098":1509788624956,"1023612287043":1509788624955,"1022646924998":1480585069144,"1022646924994":1480585069144,"1022646924993":1480585069144,"1022646925023":1480585069144,"1020744631620":1509788624321,"1024781399522":1509788624472,"1022646925013":1480585069144,"1022646925011":1480585069144,"1022316489374":1478686417200,"1022646925008":1480585069144,"1021017527630":1478686417300,"1023612287013":1509788624955,"1021017527631":1478686417300,"1025711111434":1509788624306,"1022646924973":1480585069144,"1024133816075":1509788624416,"1023612287009":1509788624956,"1024518202912":1509788624219,"1022646924969":1480585069144,"1021856008055":1478686417135,"1022646924968":1480585069144,"1022646924967":1480585069144,"1021017527623":1478686417300,"1022646924966":1480585069144,"1022646924965":1480585069144,"1020234639007":1465470268316,"1022646924963":1480585069144,"1022646924962":1480585069144,"1023612287016":1509788624955,"1022646924961":1480585069144,"1023612287019":1509788624955,"1012940110795":1478686417074,"1022079227028":1478686417012,"1023612287030":1509788624955,"1023612287025":1509788624955,"1023612287024":1509788624955,"1022646924985":1480585069144,"1024133816089":1509788624416,"1023612287026":1509788624955,"1024133816085":1509788624416,"1023612287039":1509788624955,"1022646924980":1480585069144,"1021017527632":1478686417300,"1022646924976":1480585069144,"1024454109745":1509788625030,"1012320509699":1478686804062,"1023612286991":1509788624955,"1012320509702":1478686804062,"840802033":1491634246512,"1022700663223":1509788624973,"1025301877952":1509788624932,"1023612286997":1509788624956,"1022646924954":1480585069144,"1022646924952":1480585069144,"1022646924951":1480585069144,"1024518202909":1509788624219,"1024518202908":1509788624219,"1024518202911":1509788624219,"1024518202910":1509788624219,"1023612287003":1509788624956,"1021708422787":1478686804065,"1025001720627":1509788667497,"1023612287460":1509788624954,"1022086305022":1478686417179,"1001495822381":1478686417022,"1022646925182":1480585069145,"1025791719436":1509788624230,"1025001720609":1509788667497,"1023612287473":1509788624954,"1025001720615":1509788667497,"1001732937235":1478686417023,"1025001720614":1509788667497,"1022200992278":1478686417013,"1023612287475":1509788624954,"1025791719429":1509788624206,"1025001720617":1509788667497,"1025791719425":1509788624206,"1025791719424":1509788624206,"1025001720621":1509788667497,"1022238633956":1509788624947,"1022646925133":1480585069145,"1023612287431":1509788624954,"1024518203335":1509788625154,"1022646925132":1480585069145,"1022646925130":1480585069145,"1022646925128":1480585069145,"1025001720596":1509788667497,"1023612287437":1509788624954,"1022646925126":1480585069145,"1022646925124":1480585069145,"1024518203342":1509788625154,"1024518203337":1509788625154,"1025791719472":1509788624849,"1024518203336":1509788625154,"1023612287435":1509788624954,"1022646925120":1480585069145,"1024518203338":1509788625154,"1025001720604":1509788667497,"1023612287445":1509788624954,"1025791719468":1509788624864,"1024133816061":1509788624416,"1025791719471":1509788624825,"1000368719684":1478686416993,"1025791719470":1509788624864,"1025791719465":1509788624916,"1023612287441":1509788624954,"1018923159893":1509788624314,"1018923159894":1509788624311,"1024133816057":1509788624416,"1023612287443":1509788624954,"1023612287453":1509788624954,"1025791719463":1509788624916,"1023612287448":1509788624954,"1025001720590":1509788667497,"1022646925103":1480585069144,"1021554029808":1509788624397,"1021759670323":1478686417009,"1022646925102":1480585069144,"1022646925100":1480585069144,"1024680082969":1509788625213,"1012523012799":1478686417223,"1022646925096":1480585069144,"1022646925095":1480585069144,"1022646925091":1480585069144,"1023845846103":1491634246533,"1022646925117":1480585069145,"1012153779374":1478686417073,"1022646925112":1480585069145,"1021831627868":1478686417133,"1023612287421":1509788624954,"1023612287423":1509788624954,"1022646925108":1480585069145,"1021247842988":1478686417039,"1022646925107":1480585069145,"1022646925106":1480585069145,"1025791719488":1509788624837,"1021759670316":1478686417009,"1022646925105":1480585069145,"1022646925104":1480585069145,"1024535111356":1509788624436,"1023612287365":1509788624954,"1023612287367":1509788624954,"1022646925068":1480585069144,"1025791719550":1509788624611,"1025246173413":1509788624941,"1022646925066":1480585069144,"1023612287360":1509788624954,"1025791719546":1509788624612,"1021225429058":1478686417038,"1021250988745":1478686417100,"1023612287368":1509788624954,"1022646925085":1480585069144,"1022646925080":1480585069144,"1022646925077":1480585069144,"1025671783256":1509788624942,"1022646925072":1480585069144,"1022359217204":1478686417203,"1022646925294":1480585069145,"1022646925293":1480585069145,"1025902735869":1509788667464,"1022646925292":1480585069145,"1023011167578":1509788624384,"1023612287334":1509788624954,"1025902735868":1509788667461,"1022646925291":1480585069145,"1022646925290":1480585069145,"1023820549406":1491634246535,"1022646925289":1480585069145,"1025791719579":1509788624566,"1022646925288":1480585069145,"1025791719578":1509788624545,"1023612287330":1509788624953,"1023612287341":1509788624954,"1022646925286":1480585069145,"1025791719575":1509788624545,"1022646925282":1480585069145,"1023612287336":1509788624954,"1022646925281":1480585069145,"1023612287339":1509788624954,"1022646925280":1480585069145,"1025791719570":1509788624545,"1023612287338":1509788624954,"1022646925310":1480585069145,"1021698460807":1478686417121,"1023612287346":1509788624954,"1022646925303":1480585069145,"1022646925302":1480585069145,"1022646925301":1480585069145,"1022646925299":1480585069145,"1023612287353":1509788624954,"1023612287352":1509788624954,"1022646925297":1480585069145,"1022646925296":1480585069145,"1021578147713":1478686417048,"1022148563334":1478686417185,"1016301817092":1480585069065,"1022646662971":1480585069080,"1024818099885":1509788624929,"1022646925250":1480585069145,"1024818099880":1509788624929,"1022646925249":1480585069145,"1022646662972":1480585069080,"1024818099893":1509788624929,"1022646662951":1480585069094,"1016097487227":1478686804032,"1019302641278":1509788624316,"1117646631":1444487341739,"1025795259259":1509788624342,"1019166058071":1478686804020,"1024818099899":1509788624929,"1022646662956":1480585069080,"1022646662995":1480585069080,"1022646925228":1480585069145,"1024818099910":1509788624929,"1023612287265":1509788624953,"1022646662998":1480585069150,"1022646925225":1480585069145,"1024818099917":1509788624929,"1022646925222":1480585069145,"1022646925221":1480585069145,"1022646925220":1480585069145,"1022646925218":1480585069145,"1022646925217":1480585069145,"1022646925247":1480585069145,"1022646925246":1480585069145,"1024818099924":1509788624929,"1022646925245":1480585069145,"1022646925244":1480585069145,"1024818099920":1509788624929,"1024818099934":1509788624929,"1024818099929":1509788624929,"1022646925234":1480585069145,"1023612287236":1509788624953,"1020809380341":1478686417225,"1023612287238":1509788624953,"1023612287235":1509788624953,"1023612287234":1509788624953,"1023612287245":1509788624953,"1022646925190":1480585069145,"1023612287247":1509788624953,"1022646925187":1480585069145,"1022646925186":1480585069145,"1023612287240":1509788624953,"1008583014719":1509788624381,"1023612287243":1509788624953,"1022646925184":1480585069145,"1023612287242":1509788624953,"1022646925215":1480585069145,"1023612287254":1509788624953,"1022646925211":1480585069145,"1022646925207":1480585069145,"1023612287260":1509788624953,"1022646925205":1480585069145,"1022646925204":1480585069145,"1022646925202":1480585069145,"1022646925200":1480585069145,"1025671783388":1509788624942,"1023612287258":1509788624953,"1022646924398":1480585069142,"1025219435835":1509788625128,"1023612287713":1509788624954,"1001355709343":1478950494934,"1021870949034":1478686417136,"1023612287715":1509788624954,"1025219435839":1509788625113,"1015889078609":1480585069075,"1023612287724":1509788624954,"1022519131140":1509788625075,"1022646924388":1480585069142,"1025219435829":1509788625245,"1023612287720":1509788624954,"1025219435831":1509788625245,"1014730845266":1465470268256,"1023612287730":1509788624954,"1022363805520":1480585172189,"1023612287738":1509788624954,"1018246838991":1509788625020,"1024680082815":1509788624260,"1023612287684":1509788624954,"1024680082812":1509788624260,"1022646924363":1480585069142,"1024680082811":1509788624260,"1024680082810":1509788624260,"1024680082809":1509788624260,"1025040386019":1509788624269,"1021567137007":1509788624397,"1023612287693":1509788624954,"1024680082805":1509788624260,"1024680082804":1509788624260,"1022646924355":1480585069142,"1024680082802":1509788624260,"1024680082801":1509788624260,"1024680082800":1509788624260,"1025040386026":1509788624270,"1024680082799":1509788624260,"1025219435785":1509788624437,"1023612287701":1509788624954,"1025040386036":1509788624228,"1022646924381":1480585069142,"1025040386039":1509788624227,"1024680082796":1509788624260,"1022646924379":1480585069142,"1025040386033":1509788624228,"1023612287697":1509788624954,"1025219435788":1509788624437,"1024680082792":1509788624260,"1022646924375":1480585069142,"1021205113413":1478686417038,"1024680082790":1509788624260,"1023612287708":1509788624954,"1024680082789":1509788624260,"1021981711370":1509788624426,"1022646924369":1480585069142,"1025219435782":1509788624467,"1022646924334":1480585069142,"1025652122381":1509788624337,"1022646924330":1480585069142,"1022646924328":1480585069142,"1025531799772":1509788624339,"1020802957886":1509788625229,"1024809711054":1509788624925,"1021460577640":1478686417242,"1022646924321":1480585069142,"1022341785329":1509788625007,"1022116058208":1478686417183,"1018891441175":1509788624301,"1022341785324":1509788625007,"1022341785322":1509788625007,"1022341785321":1509788625008,"1022341785320":1509788625007,"1022341785319":1509788625008,"1164700466":1478686804033,"1022646924341":1480585069142,"1022341785317":1509788625007,"1017063891724":1478686804034,"1023612287678":1509788624954,"1022341785315":1509788625007,"1022646924338":1480585069142,"1022646924337":1480585069142,"1023612287675":1509788624954,"1020294013169":1465470268280,"1022646924303":1480585069142,"1022341785311":1509788625008,"1024558441214":1509788667473,"1022341785309":1509788625007,"1022341785307":1509788625007,"1025710849961":1509788624304,"1022341785305":1509788625007,"1023947294341":1491634246529,"1022646924319":1480585069142,"1022646924318":1480585069142,"1025219435848":1509788625127,"1025219435851":1509788625136,"1022646924314":1480585069142,"1024667892846":1509788625025,"1025219435843":1509788625127,"1022646924308":1480585069142,"1025219435845":1509788625127,"1025219435846":1509788625127,"1021054621172":1478686417093,"1021054621173":1478686417093,"1228924862":1478686804029,"1022646924526":1480585069142,"1025001457844":1509788625021,"1021688237877":1478686804032,"1023612287586":1509788624954,"1023612287597":1509788624954,"1025802991867":1509788667814,"1022646924512":1480585069142,"1023612287594":1509788624954,"1023612287601":1509788624954,"1022247808204":1478686417196,"1020865617454":1480585069077,"1022646924531":1480585069142,"1021992721907":1478686417265,"1022646924530":1480585069142,"1025366758124":1509788624293,"1021667790421":1509788624404,"1022646924529":1480585069142,"1022646924528":1480585069142,"1025731951634":1509788624922,"1022646924493":1480585069142,"1024518202439":1509788624443,"1024518202438":1509788624443,"1023612287558":1509788624954,"1022646924491":1480585069142,"1022646924489":1480585069142,"1021721922836":1509788624395,"1022361315122":1478686417289,"1025703378664":1509788624295,"1023612287567":1509788624954,"1024518202441":1509788624443,"1022646924482":1480585069142,"1024518202440":1509788624444,"1022646924481":1480585069142,"1024518202443":1509788624443,"1023612287562":1509788624954,"1023612287572":1509788624954,"1021688237828":1478686804032,"1022646924505":1480585069142,"1022646924504":1480585069142,"1022646924503":1480585069142,"1023612287582":1509788624954,"1022646924498":1480585069142,"1022646924496":1480585069142,"1023612287578":1509788624954,"1022646924463":1480585069142,"1015591590868":1478686804016,"1022646924461":1480585069142,"1024987171795":1509788667581,"1022057601359":1478686417173,"1022646924460":1480585069142,"1025040385798":1509788625166,"1022646924459":1480585069142,"1025040385793":1509788625243,"1025040385794":1509788625244,"1025040385804":1509788625143,"1025040385807":1509788625135,"1022385693903":1478686417205,"1025040385803":1509788625144,"1014764923535":1480585069067,"1022646924478":1480585069142,"1012410553958":1478686417223,"1023612287543":1509788624954,"1013063184765":1478686804015,"1022646924476":1480585069142,"1025618961822":1509788624847,"1022646924471":1480585069142,"1025040385821":1509788625135,"1023612287548":1509788624954,"1022646924467":1480585069142,"1023612287545":1509788624954,"1022646924465":1480585069142,"1022656492835":1509788624462,"1022646924464":1480585069142,"1024680082816":1509788624260,"1025040385830":1509788625135,"1020802957983":1509788624604,"1022646924419":1480585069142,"1025040385833":1509788625169,"1022646924417":1480585069142,"1025040385835":1509788625113,"1009746950025":1491634246512,"1021016610627":1478686417231,"1022282279639":1478686417014,"1021196069864":1478686417098,"1024680082524":1509788624905,"1025040385734":1509788625144,"1022646924651":1480585069143,"1024680082523":1509788624905,"1024680082522":1509788624905,"1024680082520":1509788624905,"1024680082519":1509788624905,"1022646924646":1480585069143,"1024680082518":1509788624905,"1024680082517":1509788624905,"1024680082516":1509788624905,"1024680082514":1509788624905,"1024680082513":1509788624905,"1008704386194":1444487341757,"1025040385738":1509788625135,"1022646924671":1480585069143,"1025040385748":1509788625135,"1022646924668":1480585069143,"1025040385750":1509788625135,"1025040385744":1509788625135,"1022646924664":1480585069143,"1022091810449":1509788624439,"1023071591464":1509788624816,"1024310235740":1509788624971,"1025040385757":1509788625167,"1022646924661":1480585069143,"1024680082501":1509788624905,"1025040385753":1509788625169,"1022646924658":1480585069143,"1025040385761":1509788625105,"1024680082554":1509788624900,"1024680082553":1509788624900,"1022646924616":1480585069143,"1024680082552":1509788624900,"1024680082551":1509788624900,"1024680082550":1509788624900,"1024680082549":1509788624900,"1023957780327":1509788625037,"1024680082548":1509788624900,"1024680082547":1509788624900,"1024680082546":1509788624900,"1022646924609":1480585069143,"1024680082545":1509788624900,"1024680082544":1509788624900,"1024680082543":1509788624899,"1024680082542":1509788624900,"1022646924637":1480585069143,"1024680082541":1509788624900,"1023306886667":1509788625072,"1024680082539":1509788624900,"1022646924634":1480585069143,"1024680082538":1509788624900,"1024680082537":1509788624899,"1021721398413":1478686804047,"1022646924632":1480585069143,"964925108":1491634246509,"1022646924628":1480585069143,"1019608025743":1509788625078,"1022646924586":1480585069143,"1022646924584":1480585069143,"1022646924582":1480585069142,"1022646924581":1480585069142,"1025040385679":1509788624454,"1025040385673":1509788624427,"1025523935811":1509788624823,"1025523935810":1509788624833,"1022646924605":1480585069143,"1025523935809":1509788624829,"1022646924604":1480585069143,"1022275726299":1478686417067,"1022646924603":1480585069143,"1021688237798":1478686804032,"1022196666385":1478686417189,"1022646924600":1480585069143,"1025523935812":1509788624800,"1025792375364":1509788625008,"1022646924597":1480585069143,"280477676":1517734758204,"1020294144501":1465470268293,"1022646924593":1480585069143,"1020975585647":1478686416974,"1009590190027":1478686804030,"1024680082492":1509788624905,"670009480":1478950494913,"1024680082488":1509788624905,"1024680082486":1509788624905,"1024680082481":1509788624905,"1024680082480":1509788624905,"1025523935843":1509788624204,"1024680082479":1509788624905,"1025523935842":1509788624201,"1025040385718":1509788625243,"1025523935845":1509788624186,"1025523935844":1509788624198,"1025040385721":1509788625244,"1022646924783":1480585069144,"1022646924782":1480585069144,"1025040385607":1509788624441,"1024680082651":1509788624900,"1022646924778":1480585069143,"1021871342380":1509788624437,"1025040385602":1509788624451,"1024680082647":1509788624900,"1025040385615":1509788624436,"1025040385614":1509788624436,"1024680082642":1509788624900,"1021906207032":1478686417140,"1025040385611":1509788624441,"1021912498649":1478686417140,"1024680082640":1509788624900,"1016780493739":1478686804022,"155428563":1478950494906,"1024680082639":1509788624900,"1024680082638":1509788624900,"1020605829030":1478686417075,"1025040385616":1509788624436,"1021871342387":1509788624437,"1025040385631":1509788624436,"1023835885098":1491634246503,"1021871342385":1509788624437,"1022646924751":1480585069143,"1025523935923":1509788624524,"1022646924750":1480585069143,"1022646924749":1480585069143,"1025040385638":1509788624436,"1025523935920":1509788624537,"1022646924746":1480585069143,"1024734607801":1509788624939,"1024734607799":1509788624939,"1022646924742":1480585069143,"1022646924739":1480585069143,"1022967251675":1509788624426,"1025040385641":1509788624436,"1024273273905":1509788624277,"1025040385643":1509788624436,"1561719482":1444487341703,"1022646924767":1480585069143,"1022646924764":1480585069143,"1024680082668":1509788624900,"1006821950493":1478686804040,"1024680082666":1509788624900,"1024680082665":1509788624900,"1024680082664":1509788624900,"1024680082663":1509788624900,"1024680082661":1509788624900,"1024680082660":1509788624900,"1025523935919":1509788624542,"1024680082659":1509788624900,"1022519131569":1509788625064,"1025523935918":1509788624541,"1024680082658":1509788624900,"1024680082657":1509788624900,"1022646924752":1480585069143,"1024680082656":1509788624900,"1022646924719":1480585069143,"1023798014003":1509788625038,"1022646924718":1480585069143,"1024518202663":1509788624855,"1022646924716":1480585069143,"1025219435770":1509788624433,"1024518202657":1509788624855,"1022646924713":1480585069143,"1024518202659":1509788624855,"1024518202658":1509788624855,"1022646924710":1480585069143,"1021973978435":1478686417056,"1025219435767":1509788624433,"1021946978292":1478686417144,"1009353075994":1478686804061,"1022646924735":1480585069143,"1025219435753":1509788624434,"1022921639389":1509788624293,"1021632803120":1509788624818,"1025714650727":1509788624828,"1022646924732":1480585069143,"1022646924730":1480585069143,"1009353075996":1478686804061,"1022646924729":1480585069143,"1022646924728":1480585069143,"1025219435758":1509788624432,"602377279":1491634246514,"1022646924726":1480585069143,"1025714650729":1509788624822,"1009353075991":1478686804061,"1022646924722":1480585069143,"1025219435748":1509788624433,"1025714650728":1509788624832,"1022646924721":1480585069143,"1021688237679":1478686804032,"1025219435750":1509788624424,"1025714650730":1509788624745,"1017124322905":1478686804031,"1022217007087":1509788624938,"1025219435736":1509788624510,"1022312032647":1478686417015,"1020831924572":1478686417078,"1022453981196":1478686417297,"1011301734735":1480585069074,"1025219435740":1509788624511,"1022646924679":1480585069143,"1022967251614":1509788624352,"1022646924676":1480585069143,"1025703378860":1509788624295,"1022646924673":1480585069143,"1022646924701":1480585069143,"1025040385590":1509788624509,"1025523935975":1509788625088,"1025523935974":1509788625125,"1021795977426":1478686417052,"1025523935973":1509788625108,"1017124322894":1478686804031,"1025523935972":1509788625117,"1024518202653":1509788624855,"1020827205919":1509788624320,"1025040385596":1509788624452,"1025040385593":1509788624510,"1021867285751":1478686417257,"1021258463044":1478686417100,"1022108191377":1478686417182,"1022097705269":1478686417275,"1020042137549":1478686804031,"1024669721561":1509788625025,"1020916466585":1509788624352,"1022203900125":1478686417280,"1022518600196":1509788625065,"1037667818":1478686417020,"1021708423753":1478686804043,"1021708423748":1478686804043,"1021708423749":1478686804043,"1021721006982":1478686417051,"1022456872953":1478686417216,"1021708423750":1478686804043,"1021708423744":1478686804043,"1022456872958":1478686417216,"1021708423745":1478686804043,"1021708423746":1478686804043,"1021708423747":1478686804043,"1021986292616":1478686417153,"1023835886069":1491634246504,"1024983897447":1509788624924,"1021986292618":1478686417153,"1021986292619":1478686417153,"1024983897449":1509788624924,"1024983897448":1509788624924,"1022255412105":1509788624280,"1024983897455":1509788624924,"1020087841092":1509788625077,"1014712889636":1480585069072,"1024983897458":1509788624924,"1020087841093":1509788625076,"1021462143836":1509788624402,"1020087841095":1509788625078,"1000977448537":1478686417021,"1025909943368":1509788667462,"1024983897465":1509788624924,"1024107069752":1509788625019,"1020294151880":1465470268293,"1009862676495":1491634246514,"1020870852667":1509788624304,"1022463426315":1478686417072,"1009077141809":1478686804023,"1024184403646":1509788624548,"1024983897507":1509788624925,"1024942871347":1509788624904,"1024983897514":1509788624924,"1021688238395":1478686804067,"1024983897512":1509788624933,"1001300922953":1478686417024,"1022511653392":1509788624434,"1024983897516":1509788624924,"1022417681577":1478686417209,"1024942871329":1509788624904,"1021994550247":1478686417057,"1024942871330":1509788624904,"1021960208868":1478686417148,"1024942871343":1509788624904,"1024942871336":1509788624904,"1024942871339":1509788624904,"1024942871338":1509788624904,"1021688238352":1478686804067,"1024942871316":1509788624904,"1024942871314":1509788624904,"1021914603166":1478686417141,"1024942871325":1509788624904,"1024983897483":1509788624924,"1024942871324":1509788624904,"1024942871327":1509788624904,"1021396746172":1478686804043,"1024942871321":1509788624904,"1021396746174":1478686804043,"1021396746175":1478686804043,"1024983897484":1509788624924,"1024942871301":1509788624904,"1024942871300":1509788624904,"1024983897493":1509788624924,"1001385203556":1480585069061,"1024942871309":1509788624904,"1024942871308":1509788624904,"1024942871311":1509788624904,"1024983897496":1509788624924,"1024942871305":1509788624904,"1024983897500":1509788624924,"1016858636631":1509788624976,"1024375075243":1509788624816,"1022196928401":1478686417189,"1021925875645":1478686804046,"1012476742752":1464448510787,"1025283393431":1509788624211,"1021967811080":1509788624434,"1021688238423":1478686804067,"1022518600409":1509788625064,"1021708423820":1478686804043,"1021708423821":1478686804043,"1021708423816":1478686804043,"1021708423817":1478686804043,"1021708423818":1478686804043,"1021708423819":1478686804043,"1021708423812":1478686804043,"1021708423813":1478686804043,"1021708423814":1478686804043,"1022366300626":1478686417069,"1021708423815":1478686804043,"1022452678398":1478686417215,"1024735520529":1509788624813,"1024735520531":1509788624813,"1022452678400":1478686417215,"1024735520533":1509788624813,"1024735520535":1509788624813,"1024735520534":1509788624813,"1024735520537":1509788624813,"1021688238267":1478686804067,"1024735520538":1509788624813,"1023820550548":1491634246535,"1025597209511":1509788624363,"1024735520515":1509788624813,"1024735520517":1509788624813,"1024735520516":1509788624813,"1025597209507":1509788624334,"1024735520519":1509788624813,"1024735520518":1509788624813,"1024735520520":1509788624813,"1024735520523":1509788624813,"1025597209513":1509788624363,"1021385866919":1478686417042,"1024735520527":1509788624813,"1024735520565":1509788624461,"1024735520566":1509788624461,"1024735520568":1509788624461,"1021995598440":1478686417156,"1025597209503":1509788624334,"1024735520571":1509788624508,"1025597209502":1509788624334,"1024735520574":1509788624508,"1020653933160":1478686804057,"1023615952280":1509788624960,"1024780347397":1509788624973,"1024942871287":1509788624904,"1024780347393":1509788624973,"872252088":1491634246514,"1024780347394":1509788624973,"1022021682330":1478686417162,"1024735520603":1509788624871,"1024942871294":1509788624904,"1023924623116":1509788624961,"1024735520605":1509788624871,"1022240863214":1478686417194,"1024735520607":1509788624915,"1024735520606":1509788624871,"1024735520577":1509788624508,"1024735520579":1509788624433,"1024735520578":1509788624433,"1021497927612":1478686417244,"1021708423976":1478686804050,"1024735520581":1509788624423,"1021708423977":1478686804050,"1020275801237":1509788624287,"1024735520582":1509788624507,"1024735520585":1509788624461,"1024735520584":1509788624426,"1024735520587":1509788624508,"1024653075355":1509788624177,"1004790825915":1480585069067,"1024653075354":1509788624177,"1025246168288":1509788624930,"1024653075353":1509788624177,"1025576368273":1509788624349,"1024653075352":1509788624177,"1024780347430":1509788624973,"1476257433":1478686804024,"1025283393068":1509788625136,"1021688238295":1478686804067,"1024780347426":1509788624973,"1024653075351":1509788624177,"1024887951753":1509788624456,"1024735520611":1509788624915,"1024735520610":1509788624915,"1024780347446":1509788624973,"1024780347441":1509788624973,"1024735520612":1509788624835,"1025576368271":1509788624349,"1000977448819":1478686417021,"1024780347448":1509788624973,"1024887951749":1509788624430,"1024341167638":1509788624518,"872252017":1491634246514,"1020275801166":1509788624287,"1020275801168":1509788624287,"1022608124238":1509788624467,"1192883850":1491634246507,"1024375075070":1509788624419,"1866456731":1478686417020,"1866456728":1478686417020,"1866456723":1478686417020,"1021409452515":1509788624437,"1020275801202":1509788624287,"1020275801204":1509788624287,"1020275801205":1509788624287,"1024341167659":1509788624518,"1022293685284":1478686417198,"220314781":1478686417019,"1021602524432":1478686804046,"1025703240191":1509788624431,"1025703240190":1509788624428,"1037667430":1478686417020,"1022091675717":1478686417012,"1021623102534":1509788624397,"1708250121":1444487341731,"1021251778156":1478686417039,"1024341167691":1509788624423,"1021702132485":1478686417250,"1024341167690":1509788624423,"1022255411742":1509788624277,"1708250124":1444487341718,"1013147850079":1478686804025,"1012476743004":1444487341761,"1024341167717":1509788624421,"1024341167716":1509788624421,"1021387964005":1478686804024,"1018990948989":1509788624393,"1017039650477":1478686804031,"1024142721357":1509788667499,"1024142721364":1509788667499,"1024142721363":1509788667499,"1024341167494":1509788624421,"1024341167493":1509788624421,"1022091807632":1509788624439,"1001338672799":1444487341729,"1025703371361":1509788624296,"1021629919020":1509788624397,"1021708423257":1478686804046,"1024142721376":1509788667499,"1021330161346":1478686416983,"1022470634811":1478686417219,"1020653932913":1478686804057,"1022049731627":1509788624434,"1021646433282":1509788624827,"1016420701626":1480585069070,"1021330161360":1478686416983,"1025053367134":1509788624932,"1025703240192":1509788624425,"1025703240198":1509788624406,"1021330161312":1478686416983,"1020271869524":1509788624353,"1021330161340":1478686416983,"4649232196":1478686416965,"1021330161328":1478686416983,"1001385203075":1480585069061,"1002264848683":1478686417017,"1025791715193":1509788624545,"1025791715195":1509788624545,"1025791715194":1509788624545,"1024341167611":1509788624421,"1025791715190":1509788624538,"1025791715185":1509788624565,"1023054938192":1509788625073,"1024341167613":1509788624421,"1021330161304":1478686416983,"1025791715180":1509788624565,"1024206554603":1509788624439,"1025791715183":1509788624565,"1024341167591":1509788624423,"1025791715177":1509788624611,"1059556690":1444487341740,"1019260822069":1509788624312,"1025791715176":1509788624612,"1025906142814":1509788667460,"1001644721202":1444487341702,"1025906142813":1509788667461,"1022003857081":1478686417157,"1024341167592":1509788624423,"1025053367140":1509788624932,"1016957597175":1478686804022,"1023791983791":1509788624174,"1024942870838":1509788624548,"1022417682110":1478686417209,"1024942870844":1509788624548,"1025791715220":1509788624566,"1003662023816":1478686417025,"1024942870846":1509788624548,"1024341167391":1509788624423,"1024341167389":1509788624423,"1022198369723":1509788624971,"1024341167365":1509788624423,"1025791715210":1509788624545,"1024942870818":1509788624552,"1022094429158":1478686417181,"1303379766":1444487341731,"1025791715206":1509788624545,"1007085406339":1478686804025,"1025791715203":1509788624545,"1021166972985":1465470268307,"4965635418":1509788624158,"1025791715263":1509788624837,"1025791715256":1509788624837,"1025791715259":1509788624837,"1023845061549":1491634246537,"1021022243818":1478686417090,"1025791715250":1509788624825,"1025791715244":1509788624916,"1023845061552":1491634246537,"1021368040479":1509788624439,"1025791715243":1509788624916,"1027718904457":1527346641968,"1012115379349":1478686417025,"1024942870796":1509788624611,"1023924622590":1509788624961,"1024942870798":1509788624565,"1024942870792":1509788624611,"1021695710176":1478686804039,"1025791715268":1509788624837,"1025791715271":1509788624837,"1020966405217":1478686417001,"1024341167439":1509788624423,"1001556640601":1478686417022,"1024341167437":1509788624423,"1025791715267":1509788624837,"1022476132953":1478943089315,"507489493":1444487341732,"1021796636114":1478686417255,"1024942870873":1509788624544,"1024607993188":1509788667589,"1024942870854":1509788624567,"1024942870860":1509788624566,"1020823674818":1478686416998,"1024942870857":1509788624539,"1019295031460":1509788625078,"1019295031461":1509788625077,"1025703240523":1509788624197,"1021708423541":1478686804027,"1025703240522":1509788624204,"1025703240521":1509788624200,"1021311285508":1465470268205,"1025703371597":1509788624295,"1025703240525":1509788624186,"1022198369336":1509788624936,"1019596494679":1509788624933,"1022198369332":1509788624933,"1022198369333":1509788624932,"349939653":1444487341755,"1009860711340":1491634246520,"1021311547693":1465470268205,"1022236930514":1478686417194,"1021907918262":1509788624465,"1003492153114":1478686417220,"507489659":1444487341744,"1017554360656":1465470268262,"1097593383":1478686804032,"1018772422697":1509788624373,"1021244175710":1509788624971,"1024906039952":1509788624938,"1024341167305":1509788624423,"1024341167304":1509788624423,"1021804370937":1478686417131,"1021903986103":1478686417054,"1019179825233":1509788624940,"1024341167359":1509788624423,"155564607":1509788625019,"1024942870734":1509788624566,"1024942870731":1509788625203,"1024341167122":1509788624423,"1024341167120":1509788624423,"1013101056745":1465470268318,"1025017844917":1509788624334,"1025219428529":1509788624543,"1025017844916":1509788624333,"1008404101874":1509788625081,"1025017844919":1509788624333,"1025017844918":1509788624334,"1025219428530":1509788624543,"1025017844913":1509788624333,"1025219428533":1509788624543,"1025017844912":1509788624332,"1025017844915":1509788624333,"1025017844914":1509788624333,"1025219428534":1509788624543,"1025219428520":1509788624544,"1025017844911":1509788624332,"1025219428523":1509788624539,"1022282282936":1478686417014,"1025017844910":1509788624332,"1020781991968":1478686417225,"1025219428513":1509788624612,"1025219428515":1509788624612,"1022004119367":1478686417157,"1025219428516":1509788624544,"1025219428519":1509788624536,"1864621187":1444487341719,"1025017844894":1509788624332,"1020817776178":1478686417078,"1021408797692":1478686804039,"1024341167163":1509788624421,"1022302074550":1478686417287,"1025703371757":1509788624295,"1024341167166":1509788624421,"1020817776184":1478686417078,"1019302371448":1509788624313,"1022080666518":1478686417061,"1021258593424":1478686417040,"1021782087132":1478686417128,"1020653932688":1478686804057,"1020447106112":1478686804054,"1022093773494":1478686417063,"1059556595":1444487341720,"1022092200518":1478686417273,"1021631884598":1509788624396,"1022302074561":1478686417287,"1022265635060":1478686417285,"1024341167182":1509788624421,"1024341167181":1509788624421,"1020888023714":1478686417299,"1001556640355":1478686417022,"1022469324014":1478686417218,"1023919510874":1509788624969,"1023453428110":1509788624517,"1024341167210":1509788624421,"1022218449893":1478686417192,"1018517886837":1480585069063,"1622004563":1478686804051,"1024341167213":1509788624421,"1022270353635":1480585069094,"1022198369066":1509788624932,"1021497926379":1478686417112,"1022270353634":1480585069094,"1022198369067":1509788624935,"1020442911710":1509788624361,"1020442911711":1509788624361,"1020442911708":1509788624361,"1020442911709":1509788624361,"1001556641169":1478686417023,"1020442911707":1509788624361,"1024341166982":1509788624421,"1024956764375":1509788624335,"1024341166987":1509788624421,"1022950742096":1509788625051,"1020442911716":1509788624361,"1020442911714":1509788624361,"1020442911715":1509788624361,"1020442911712":1509788624361,"1020442911713":1509788624361,"1023354990698":1509788624533,"1021352704387":1465470268226,"1021352704388":1465470268226,"1021352704389":1465470268226,"1021352704390":1465470268226,"1021352704391":1465470268226,"1021352704393":1465470268227,"1001556641223":1478686417023,"240237079":1478686417017,"1024479671065":1509788624437,"1024463417957":1509788625070,"1024341167043":1509788624515,"1023354990602":1509788624816,"1022436555087":1478686417213,"1024341167044":1509788624516,"1022239028927":1478686417194,"1024341167091":1509788624421,"1021646432849":1509788624200,"1023173692781":1509788625083,"1024341167092":1509788624421,"1023354990642":1509788625101,"1022934228799":1509788625051,"1024906040757":1509788624937,"1022157998533":1478686417185,"1022079880238":1478686416980,"1009270081981":1509788624384,"1025019155314":1509788625069,"1009269950907":1509788624389,"1021307879135":1478686417005,"175750911":1444487341705,"1025033051346":1509788624867,"1020486561245":1465470268302,"1021124479904":1478686417037,"1021124479905":1478686417037,"4965634920":1509788624158,"1023354990799":1509788624194,"1037666627":1478686417020,"1020801521871":1478686804040,"1020389173164":1465470268302,"1022075817004":1509788624550,"1012127699887":1478686417025,"1021040987875":1478686417092,"1016930988486":1478686804019,"1021152949616":1465470268184,"1001732935659":1478686417023,"1001556641130":1478686417023,"1022092201324":1478686417273,"1022426593607":1478686417211,"1021465944074":1478686417045,"1872485018":1478950494927,"1022646923118":1480585069142,"1022646923116":1480585069142,"1022047896357":1478686417059,"1022646923114":1480585069142,"1022646923113":1480585069142,"1010002664756":1491634246524,"1022646923109":1480585069141,"1022646923107":1480585069141,"1022646923104":1480585069141,"1022646923135":1480585069142,"1024132368118":1509788624326,"1022646923129":1480585069142,"1020847528629":1478686417226,"1022646923126":1480585069142,"1021666612708":1478686417050,"1021932427804":1478686417142,"1022646923125":1480585069142,"1022646923124":1480585069142,"1022646923122":1480585069142,"1022646923120":1480585069142,"1024886254132":1509788624436,"1022074375592":1478686417061,"1021364239302":1478686417239,"1022646923081":1480585069141,"1021362534457":1509788624977,"1021364239304":1478686417239,"1022074375591":1478686417060,"1022646923101":1480585069141,"1022646923100":1480585069141,"1022646923098":1480585069141,"1024886254112":1509788624428,"1019729271107":1509788625020,"1025003033379":1509788624866,"1022646923089":1480585069141,"1022451235711":1478686417215,"1021364239284":1478686417239,"1023065294537":1509788624553,"1023065294536":1509788624554,"1009611547706":1478686804033,"1023065294535":1509788624554,"1022429214768":1478686417071,"1023065294534":1509788624554,"1022406277533":1478686417071,"1023065294532":1509788624553,"1024463418226":1509788625029,"1024886254153":1509788624435,"1019596493087":1509788624959,"1021646433133":1509788624200,"1024886254197":1509788624424,"1024886254207":1509788624423,"1021902281625":1478686417139,"1021948937575":1478686417260,"1008183478768":1480585069074,"1020801521945":1478686804065,"1008662703465":1478686804026,"1021093021834":1478686417232,"1021344840091":1478686804023,"1023526960015":1509788624373,"1021890877449":1478686417054,"1020654065346":1478686416996,"1001556640796":1478686417023,"4562074231":1465469681386,"1022646923212":1480585069095,"134593952":1444487341749,"1022646923208":1480585069095,"1024384251718":1509788624327,"1025529049858":1509788624338,"1021992715974":1478686417011,"1012129141464":1478686417073,"1022646923205":1480585069095,"1000157309766":1478686804024,"1022646923200":1480585069095,"1022646923227":1480585069095,"1502342194":1491634246509,"1022646923221":1480585069095,"1016930988191":1478686804019,"1502342196":1491634246509,"1022646923183":1480585069094,"1022646923181":1480585069094,"1022430787762":1478686417071,"1022646923180":1480585069094,"1024185451292":1509788625035,"1023354990999":1509788624419,"1020987900582":1478686417034,"1021774877628":1478686804066,"1022646923189":1480585069095,"1021914733547":1478686417259,"1022646923186":1480585069095,"1022697121913":1509788625058,"1022646923141":1480585069142,"1021226217685":1465470268196,"1022646923139":1480585069142,"1023183654780":1509788625043,"1526984432":1491634246511,"1001556640895":1478686417023,"1022273761967":1478686417014,"1022387273195":1478686417069,"1024787688694":1509788624272,"1024787688689":1509788624273,"1025703241287":1509788624537,"1025703241286":1509788624542,"1025703241285":1509788624540,"1024787688700":1509788624272,"1025703241288":1509788624523,"187677984":1444487341704,"1024787688698":1509788624272,"1024186630329":1509788624236,"1024186630331":1509788624236,"1022446647404":1478686417214,"1022446647400":1478686417214,"1024787688684":1509788624273,"1024787688687":1509788624272,"1024787688682":1509788624272,"1025608613318":1509788625001,"1024331728935":1509788667535,"1024331728933":1509788667536,"1024331728936":1509788667536,"1008723913329":1509788625020,"872252870":1491634246514,"1024186630368":1509788624236,"1018990949935":1509788624392,"1021253611974":1478686417100,"1024186630345":1509788624236,"1024186630344":1509788624236,"1022406277797":1478686417070,"1024186630347":1509788624236,"1024186630349":1509788624236,"1024186630351":1509788624236,"1024186630350":1509788624236,"1024186630337":1509788624236,"1024186630341":1509788624236,"1024186630340":1509788624236,"1021336189666":1478686417239,"1024186630343":1509788624236,"1024186630361":1509788624236,"1024186630360":1509788624236,"1024663430188":1509788625003,"1024186630363":1509788624236,"1024186630365":1509788624236,"1024186630364":1509788624236,"1024186630367":1509788624236,"1024186630366":1509788624236,"1024186630352":1509788624236,"1024186630355":1509788624236,"2298166912":1509976385181,"1024186630358":1509788624236,"1021709735112":1509788624817,"1018468865812":1509788624825,"1022287000417":1478686417286,"1018298474808":1509788624369,"1021774876911":1478686804066,"1021735948881":1509788624216,"1021735948874":1509788624216,"1020823411625":1478686417078,"1021735948877":1509788624216,"1021735948878":1509788624216,"1021967157129":1478686417149,"1022360796930":1478686417015,"1835523015":1491634246515,"1024735518897":1509788624821,"1835523014":1491634246515,"1025270153362":1509788624559,"1024735518896":1509788624915,"1022302860211":1478686417287,"1025270153361":1509788624559,"1835523012":1491634246515,"1025270153360":1509788624559,"1025270153367":1509788624559,"1001556641569":1478686417023,"1022255412576":1509788624280,"1021709735149":1509788624534,"1024735518900":1509788624835,"1020653934077":1478686804057,"134594221":1444487341722,"1024735518909":1509788624870,"1024735518885":1509788624915,"1021604751928":1478686416977,"1022302860201":1478686417287,"1024735518891":1509788624824,"1021709735155":1509788624195,"1017124316933":1478686804018,"1025270153358":1509788624559,"1024735518895":1509788624915,"1025431926480":1509788624174,"1020985803099":1478686417088,"1025845587723":1509788667443,"1025246167894":1509788624931,"1835523006":1491634246515,"1835523005":1491634246515,"1024479670666":1509788625070,"1835523001":1491634246515,"1864620483":1444487341717,"1022402608637":1478686417015,"1022070836771":1478686417176,"1018644635131":1478686804026,"1021780644053":1509788624395,"1024886254076":1509788624337,"1022070836776":1478686417176,"1025114708867":1509788667497,"1017808636941":1478686804016,"1025908239115":1509788667460,"1020884747926":1509788624177,"1025908239112":1509788667458,"1021604752266":1478686416977,"1001556641409":1478686417023,"1020884747922":1509788624177,"1019166063843":1478686804020,"1025665628558":1509788624612,"1025665628560":1509788624611,"175750508":1444487341705,"1025665628564":1509788624565,"1018513298407":1509788624837,"1025665628572":1509788624565,"1025665628574":1509788624565,"1023710981667":1509788624444,"1023710981670":1509788624444,"1023710981669":1509788624444,"1025665628583":1509788624545,"1023710981668":1509788624444,"1025665628585":1509788624545,"1021358471794":1478686417042,"1023710981672":1509788624444,"1025665628591":1509788624545,"1021014773479":1478686417089,"1025665628594":1509788624545,"1022328025254":1478686417288,"1022021550828":1509788624179,"1008304747635":1478686804020,"1025665628605":1509788624545,"1024794373457":1509788624237,"1016857720483":1509788624977,"1025665628611":1509788624566,"1024803679397":1509788625023,"1021233295775":1478686417003,"1021233295773":1478686417003,"1025246167761":1509788624931,"1025270153575":1509788625152,"1025033051907":1509788625234,"1009480613384":1509788625017,"1023939956773":1509788667538,"1025270153578":1509788625152,"1025270153577":1509788625152,"1025270153576":1509788625152,"1025270153580":1509788625152,"1020878849682":1478686417079,"1025703241507":1509788625124,"1022282281802":1478686417014,"1021881572207":1509788624511,"1025703241506":1509788624823,"1025703241505":1509788624832,"1025703241504":1509788624828,"1025703241510":1509788625087,"1025703241509":1509788625106,"1025703241508":1509788625115,"1001556641517":1478686417023,"1021976986893":1478686417056,"1021700953477":1478686417009,"1019817477711":1509788624282,"1016845793068":1509788624367,"1020486561326":1465470268303,"1016845793065":1509788624366,"1019596493774":1509788624933,"1022008967943":1478686417158,"1025665628432":1509788624916,"1025665628436":1509788624916,"1021239587300":1478686417039,"1024555694899":1509788624972,"1001556641311":1478686417023,"1025246167581":1509788624931,"1021774877175":1478686804066,"1025665628449":1509788624864,"1024607991850":1509788667589,"1020584077506":1478686417027,"1025665628461":1509788624826,"1025665628465":1509788624838,"1020948972055":1478686417085,"1023220616165":1509788624251,"1025665628473":1509788624838,"1021831634622":1478686417133,"1025665628476":1509788624838,"1021012807222":1478686417035,"1025665628481":1509788624838,"1021831634624":1478686417134,"1024106022483":1509788667495,"1025627486991":1509788624844,"1025627486989":1509788624844,"1025665628490":1509788624838,"1025665628493":1509788624838,"4899967957":1509788624158,"1021709735339":1509788624420,"1024787688721":1509788624272,"1025791845105":1509788624532,"1021981836764":1478686417011,"1024787688708":1509788624272,"1025791845097":1509788624532,"1025791845103":1509788624532,"1024787688704":1509788624272,"1025791845101":1509788624532,"1025791845091":1509788624532,"1025791845090":1509788624532,"1022241912137":1478686417066,"1024787688718":1509788624272,"1025791845095":1509788624532,"1024787688715":1509788624272,"1037666854":1478686417020,"1025791845092":1509788624532,"1022008970391":1478686417159,"1024375863651":1509788624600,"1024375863650":1509788624600,"1024375863653":1509788624600,"1024375863652":1509788624601,"1024375863655":1509788624600,"1024375863657":1509788624600,"1022430786936":1478686417071,"1024375863656":1509788624600,"1024375863659":1509788624600,"1024375863658":1509788624600,"1024375863661":1509788624600,"1022451234359":1478686417215,"1024375863663":1509788624600,"1025219431209":1509788624437,"1024375863665":1509788624600,"1022802631478":1509788625056,"1024375863667":1509788624600,"1024375863666":1509788624600,"1024375863669":1509788624600,"1024375863670":1509788624600,"1024375863673":1509788624600,"1025219431200":1509788624432,"1024375863672":1509788624600,"1019810793857":1509788625078,"1024375863675":1509788624600,"1024375863674":1509788624600,"1024375863676":1509788624600,"1025219431207":1509788624437,"1025219431206":1509788624437,"1025219431193":1509788624432,"1020831143563":1478686416998,"1025219431196":1509788624432,"1012132814611":1478686417025,"1025219431191":1509788624432,"1025219431177":1509788624432,"1025219431176":1509788624427,"1025219431179":1509788624432,"1020657867562":1478686804071,"1025219431183":1509788624432,"1025219431169":1509788624433,"1018517757108":1480585069070,"1025219431173":1509788624433,"1022479018156":1478943089531,"1025219431175":1509788624434,"1025219431174":1509788624424,"1022239029915":1478686417194,"1021602653438":1478686417008,"1021396875085":1478686417240,"1021700430501":1478686804046,"1025791716733":1509788624837,"1021903197859":1478686417139,"1025791716729":1509788624825,"1025791716731":1509788624849,"1025791716725":1509788624864,"1022148035652":1478686417277,"1021692172569":1509788625003,"379956951":1478686417017,"1025791716710":1509788624916,"1025791716704":1509788624916,"1022289886551":1478686417198,"1010091923009":1491634246522,"1021513658009":1509788624853,"1022417679547":1478686417209,"1021513658010":1509788624853,"1010091923011":1491634246522,"1021513658011":1509788624853,"1021513658012":1509788624853,"1010091923015":1491634246527,"1023331138349":1509788624183,"1024375863789":1509788624601,"1024375863790":1509788624601,"1024375863792":1509788624601,"1024375863796":1509788624601,"1023937732362":1509788667538,"1024375863799":1509788624601,"1025791716747":1509788624837,"1024375863798":1509788624601,"1023032527108":1509788624610,"1023937732360":1509788667538,"1025009327911":1509788624330,"1024375863801":1509788624601,"1024375863800":1509788624601,"1022289886541":1478686417198,"1062045654":1478686417020,"1025791716737":1509788624837,"1024375863804":1509788624601,"1025791716739":1509788624837,"1021208394929":1478686417099,"1024798171892":1509788625069,"1017770364831":1478686804022,"1018899170136":1509788624367,"1021843690210":1478686417053,"1022375866887":1478686417204,"1022086299976":1478686417179,"1021975022118":1478686417150,"1024383203758":1509788624329,"1022023126398":1478686417266,"1007777815571":1478686804071,"1025533509291":1509788624347,"1022050782938":1478686417172,"1022039641708":1478686417268,"984318587":1491634246533,"1020116548502":1509788625076,"1020116548501":1509788625077,"1022039641723":1478686417268,"1020116548504":1509788625078,"1020116548505":1509788625076,"549165159":1444487341735,"1019819837902":1509788624934,"1346627741":1491634246505,"1021943302300":1509788624464,"1018288254651":1478686804020,"1006208024239":1478686804022,"1020116548531":1509788625076,"1020116548535":1509788625078,"1024461323966":1509788625029,"1025902732423":1509788667463,"1025902732422":1509788667459,"1025902732418":1509788667461,"1009744453984":1491634246512,"1000145380513":1478686804039,"1012127702624":1478686417025,"1021872002482":1478686417136,"1021048324806":1478686417093,"1025844404458":1509788667448,"1024764223823":1509788625025,"1021495831581":1478686417046,"1021499240418":1478686417007,"1024132500213":1509788624327,"1022285954315":1478686417014,"1022285954318":1478686417015,"4951875131":1509788624154,"1024785850382":1509788624481,"1012093099185":1509788625020,"1019802798371":1509788624317,"1308488907":1444487341755,"1022191289992":1478686417013,"1022070833539":1478686417176,"1012172526477":1478686417299,"1023970627776":1509788625071,"1019974107792":1480585069076,"1021427673205":1478686417241,"1010002661757":1491634246524,"1022459623144":1478686417217,"1021835039651":1509788624221,"1022545472975":1509788625063,"1022459623150":1478686417217,"1012129144365":1478686417073,"1023937732351":1509788667539,"1021750893717":1509788624395,"1023937732349":1509788667539,"1025791716474":1509788624545,"1021835039644":1509788624221,"1024002740946":1491634246532,"1021835039645":1509788624221,"1025791716464":1509788624538,"1021835039646":1509788624221,"1022849425171":1509788624381,"1025791716456":1509788624565,"1025791716459":1509788624565,"1025791716458":1509788624565,"810518839":1444487341733,"1025791716455":1509788624611,"1025791716454":1509788624612,"1022276517372":1478686417067,"1022315577251":1478686417068,"1021148624979":1478686417097,"1022397625051":1478686417207,"1022397625049":1478686417206,"1022397625048":1478686417206,"1025791716494":1509788624545,"1018923025909":1509788625019,"1022033349782":1478686417166,"1018620777470":1478686804065,"1025791716489":1509788624545,"355577005":1444487341735,"1021491375315":1478686417111,"1025791716540":1509788624612,"1021216652296":1478686417099,"1019344579822":1509788624376,"1019344579823":1509788624376,"1018990950867":1509788624392,"1021602653445":1478686417008,"1019344579821":1509788624376,"1025513978917":1509788624998,"1024797123562":1509788625020,"1021609338363":1478686417049,"1021951952953":1478686417261,"1025219431167":1509788624511,"1025219431166":1509788624510,"1021951952949":1478686417261,"1025791716552":1509788624538,"1025791716554":1509788624553,"1025791716548":1509788624565,"1025791716551":1509788624564,"1025791716545":1509788624611,"1025796829041":1509788624197,"1025906927073":1509788667459,"1025906927071":1509788667459,"1025906927070":1509788667458,"1021156620453":1478686417002,"1025791716597":1509788624566,"1025791716596":1509788624545,"1025791716593":1509788624545,"1021299880759":1478686417004,"1025791716591":1509788624545,"1022458312275":1478686417016,"1022191289778":1478686416979,"1037666257":1478686417020,"1024633940501":1509788624523,"1020959985416":1478686417085,"1022674577113":1509788625060,"1020959985422":1478686417085,"1025771138672":1509788624406,"1023994351637":1491634246518,"1021073884799":1478686417093,"1009862679111":1491634246513,"1023583840410":1509788625038,"1025188236076":1509788624273,"1025771138669":1509788624425,"1025771138668":1509788624431,"1025771138667":1509788624428,"1020324162271":1509788624451,"1024376388404":1509788625031,"1025533639725":1509788624370,"1025533639724":1509788624370,"1025533639723":1509788624370,"1020616448960":1478686416995,"1750061614":1444487341732,"1020969290767":1478686417086,"311535856":1478686804033,"1022628701167":1509788624842,"1025330708732":1509788624526,"1025806265425":1509788667443,"228308970":1444487341747,"1024785851235":1509788625198,"1022372982967":1478686417204,"1024624896759":1509788624819,"1020925774215":1478686417033,"1022022078255":1509788624463,"1023955423763":1509788624389,"1023955423765":1509788624389,"1750061770":1444487341745,"1023955423764":1509788624389,"1023955423767":1509788624389,"1023955423766":1509788624389,"1022323572060":1478686417288,"1018901528866":1509788624283,"1018901528864":1509788624301,"1014365132451":1465470268319,"1002327893276":1478686416993,"1020613827371":1478686416995,"1009263134392":1478686804015,"1025771138761":1509788624832,"1021680638630":1478686804028,"1012132814233":1478686417025,"1021141023478":1478686417096,"1021992847822":1478686417265,"1021680638638":1478686804028,"1021680638632":1478686804028,"1021746831000":1478686417126,"1021287428903":1478686417101,"1021680638642":1478686804028,"1023020206830":1509788625083,"1023020206829":1509788625083,"1023020206828":1509788625083,"1023825795820":1509788624940,"1025771138704":1509788625106,"1025300038275":1509788624308,"1025593667586":1509788624523,"1023825795810":1509788624939,"1023825795813":1509788624940,"1023919381602":1509788624959,"1022198498800":1509788624177,"1024867640558":1509788624325,"1021092628445":1480585069070,"1021491638201":1509788624977,"1023825795800":1509788624940,"1016538666101":1478686804046,"1023825795882":1509788624940,"1021301846458":1480585069071,"1022113562974":1478686417183,"1025771138899":1509788624523,"1021485477551":1509788624402,"1023825795886":1509788624939,"1021827699271":1509788624897,"1023825795873":1509788624940,"1023825795878":1509788624940,"1022016179978":1509788625075,"1025771138887":1509788624537,"1022253185268":1478686417014,"1024375863927":1509788624593,"1019037350062":1480585069070,"1021485739710":1509788624398,"1024375863929":1509788624594,"1024469318869":1509788624522,"1024375863930":1509788624594,"1022069523430":1478686417301,"1024375863932":1509788624594,"1024375863935":1509788624594,"1023825795850":1509788624940,"1023995531566":1491634246532,"1023825795852":1509788624940,"1022312037705":1509788625078,"1023825795844":1509788624940,"1023995531573":1491634246529,"1023995531572":1491634246532,"1024624896944":1509788624419,"421896735":1491634246510,"1023825795940":1509788624940,"1021141023490":1478686417096,"1025771138821":1509788624203,"1024839591558":1509788624304,"1023340312667":1509788624380,"1024375863809":1509788624601,"1023340312666":1509788624380,"1024375863808":1509788624601,"1023340312665":1509788624380,"1023340312664":1509788624380,"1024375863813":1509788624601,"1021099705794":1478686417095,"1023340312668":1509788624380,"1024375863814":1509788624601,"1023825795916":1509788624940,"1023340312659":1509788624380,"1024375863816":1509788624601,"1022065069140":1478686416990,"1024375863819":1509788624601,"1023825795905":1509788624940,"1023340312663":1509788624380,"1023340312662":1509788624380,"1024375863820":1509788624601,"421896779":1491634246510,"1023340312661":1509788624380,"1024375863823":1509788624601,"1022544687081":1509788625075,"1023340312660":1509788624380,"1024375863822":1509788624601,"1023825795908":1509788624940,"1024375863825":1509788624601,"1024375863824":1509788624601,"1024375863826":1509788624601,"1023825795933":1509788624940,"1023825795925":1509788624940,"1021288477211":1478686417040,"886804316":1444487341748,"1020560876865":1478686417026,"1021602522918":1478686417008,"1025798532408":1509788624818,"1024469318720":1509788624522,"1024688729931":1509788624434,"1025796828478":1509788624406,"1024688729930":1509788624434,"1012197429458":1478686417025,"1025796828477":1509788624425,"1024688729929":1509788624434,"1025796828476":1509788624428,"1025796828475":1509788624431,"1021827699431":1509788624592,"1022608515952":1509788624994,"886804336":1444487341744,"1020648560676":1478686416995,"1022608515946":1509788624994,"1024002871300":1491634246532,"1025884119077":1509788667466,"1023453426114":1509788625008,"1024375863969":1509788624593,"1025629976416":1509788624174,"1022430262963":1509788624288,"1022928195687":1509788624301,"1023453426097":1509788625008,"1025593667847":1509788625088,"1025593667846":1509788625108,"1025593667845":1509788625124,"1022393692232":1478686417015,"1025593667844":1509788625116,"1022458836084":1478686417217,"1022701971190":1509788625059,"1021257415830":1478686417004,"1021460572358":1478686417044,"1024375863937":1509788624594,"1024688729913":1509788624427,"1024624896874":1509788624533,"1024375863938":1509788624593,"1024375863941":1509788624593,"1023263736910":1509788624352,"1024375863940":1509788624594,"1024375863943":1509788624593,"1024375863947":1509788624593,"1024375863946":1509788624593,"1024375863949":1509788624593,"1022002286358":1478686804039,"1024375863954":1509788624593,"1024375863957":1509788624593,"1024375863959":1509788624593,"1022079615915":1478686417178,"1025629976409":1509788624175,"1024375863961":1509788624593,"1025679258664":1509788624351,"1024375863963":1509788624594,"1019067498033":1509788625076,"1020560876858":1478686417026,"1024375863965":1509788624593,"1024375863967":1509788624593,"1024375863966":1509788624594,"1024375864674":1509788624908,"1024375864679":1509788624908,"1025791715604":1509788624565,"1025791715607":1509788624545,"1024375864683":1509788624908,"1024375864682":1509788624908,"1025791715601":1509788624565,"1024375864685":1509788624908,"1024375864687":1509788624908,"1025791715602":1509788624565,"1024375864686":1509788624908,"1025791715599":1509788624611,"1024375864693":1509788624908,"1024375864692":1509788624908,"1025791715594":1509788624612,"1024375864694":1509788624908,"1025713073589":1509788624305,"1024375864697":1509788624908,"1024375864696":1509788624908,"1021034694296":1478686417091,"1024375864701":1509788624908,"1022279006304":1478686417197,"1024375864700":1509788624908,"1000920430454":1478686417219,"1024375864703":1509788624908,"1024375864702":1509788624908,"1024732768785":1509788624169,"1021084631456":1478686417232,"1020391532751":1478686804071,"1025791715626":1509788624566,"1025791715620":1509788624545,"1024375864667":1509788624908,"1022373508832":1478686417290,"1024375864669":1509788624908,"1025791715616":1509788624545,"1024375864671":1509788624908,"1024375864670":1509788624908,"1024375864608":1509788624261,"1024375864615":1509788624261,"1022274812150":1478686416978,"1024375864618":1509788624261,"1024375864620":1509788624261,"1024375864623":1509788624261,"1024375864622":1509788624261,"1022468141927":1478686417218,"1024375864625":1509788624261,"1024375864624":1509788624261,"1024375864627":1509788624261,"1021208262783":1478686804026,"1024375864626":1509788624261,"541826076":1509788625018,"1025536785014":1509788624869,"1020938356765":1478686417033,"1012387351113":1478686417074,"1025552120614":1509788624339,"1024375864583":1509788624261,"1023521583659":1509788625039,"1024375864582":1509788624261,"1024375864585":1509788624261,"1024375864587":1509788624261,"1024375864589":1509788624261,"1024375864588":1509788624261,"1023835889118":1491634246504,"1024375864593":1509788624261,"1025629319387":1509788624431,"1024375864592":1509788624261,"1023032528354":1509788624269,"1025629319386":1509788624428,"1024375864597":1509788624261,"1024375864599":1509788624261,"1025629319389":1509788624406,"1025629319388":1509788624425,"461744125":1444487341753,"1022848113385":1509788625018,"1024375864602":1509788624261,"1024375864604":1509788624261,"1010091921985":1491634246527,"1018546592382":1480585069070,"1022097049052":1478686417012,"1001790341920":1478686417023,"1021755742488":1478686417126,"1010091922006":1491634246527,"1025796827704":1509788624523,"1007402037668":1478686804023,"1025796827702":1509788624537,"1025796827701":1509788624542,"1020610026863":1509788624353,"1022156947773":1478686417278,"1016871616052":1478686804065,"1020673726614":1478686804047,"1022965027128":1509788624515,"1022016047273":1509788625067,"1021500549734":1478686804031,"1022965027135":1509788624272,"1022965027134":1509788624919,"1021311678122":1465470268206,"1021311678123":1465470268206,"1022553467055":1480585069118,"1022553467059":1480585069118,"1023996974754":1509788624479,"1022553467062":1480585069118,"1022553467068":1480585069118,"1011826764219":1509788624944,"1024331727562":1509788667535,"1022545602646":1509788625063,"1024331727571":1509788667536,"1024331727568":1509788667536,"1024331727572":1509788667535,"1021890351453":1478686417138,"1022965027136":1509788624615,"1024375864705":1509788624908,"1024624897131":1509788625100,"1024331727585":1509788667535,"1024331727595":1509788667535,"1021495831014":1478686417046,"1024331727597":1509788667535,"1022217010428":1509788624938,"1024331727600":1509788667535,"1024331727607":1509788667536,"1024331727606":1509788667536,"1024331727609":1509788667535,"1024375864423":1509788624261,"1024375864422":1509788624260,"1024375864424":1509788624261,"1024375864426":1509788624261,"1021854570145":1509788625013,"1022262492789":1480585069113,"1024375864432":1509788624261,"1021877899604":1478686417257,"1024375864435":1509788624261,"1024375864434":1509788624261,"1024375864437":1509788624261,"1021886288082":1509788624465,"1024781526087":1509788625021,"1024375864436":1509788624261,"1024375864439":1509788624261,"1021877899601":1478686417257,"1024375864441":1509788624261,"1024375864440":1509788624261,"1024375864443":1509788624261,"1024375864445":1509788624261,"1024375864444":1509788624261,"1023032528014":1509788624915,"1024375864446":1509788624261,"1020935211447":1478686417083,"1021948677420":1509788624354,"1021345100073":1478686804023,"1020935211449":1478686417083,"1018183003571":1465470268238,"1025582527654":1509788624837,"1020935211426":1478686417083,"1025533639490":1509788624370,"1025533639489":1509788624370,"1025533639488":1509788624370,"1025582527658":1509788624434,"1025533639487":1509788624370,"1021371577309":1478686417006,"1021371577310":1478686417006,"1012926081725":1478686804024,"1021341692168":1509788624180,"1021444845415":1478686417107,"1021341692170":1509788624179,"1020935211461":1478686417083,"1021341692172":1509788624181,"1025582527681":1509788624434,"1022448743176":1478686417215,"1021341692164":1509788624179,"1008281157513":1480585069073,"1021736868337":1478686417251,"1021341692167":1509788624179,"1021307221800":1478686417041,"1021789559532":1509788624394,"105233186":1444487341754,"1009999779114":1491634246518,"1018771377664":1509788624372,"1022155899053":1509788624958,"503686011":1478686804033,"1022236016493":1478686416985,"1025750953705":1509788624309,"1023890151923":1491634246506,"1025796827941":1509788625123,"1025796827940":1509788625114,"1001790341694":1478686417023,"1018183003415":1465470268238,"1025628664128":1509788624426,"1214510580":1478686804033,"1022263934682":1478686417067,"1025791715519":1509788624270,"1021458345698":1478686417044,"4804158462":1509788624158,"1025703374310":1509788624297,"1022849424346":1509788624381,"1025771006449":1509788624455,"1022669989541":1509788625060,"1022107797277":1478686417275,"647207740":1491634246511,"1000287066264":1478686417027,"1019166062168":1478686804020,"1021497928539":1478686417112,"518497105":1478950494910,"1019287170922":1509788625080,"1022459621895":1478686417072,"1025034884601":1509788624203,"1025034884603":1509788624230,"1024624897354":1509788624193,"1025034884604":1509788624199,"1025791715547":1509788624207,"1025034884607":1509788624211,"1025034884606":1509788624215,"1025034884592":1509788624203,"1022046981016":1478686417301,"1025034884595":1509788624203,"1025791715539":1509788624215,"1018183003474":1465470268238,"4959476298":1509788624159,"1025034884585":1509788624214,"1023071719150":1509788625072,"1025034884589":1509788624199,"1025791715529":1509788624227,"1025791715524":1509788624227,"1025791715526":1509788624227,"1025034884581":1509788624270,"1025034884582":1509788624269,"1025791715522":1509788624269,"1021869379876":1478686804047,"1024375864451":1509788624261,"1025533639581":1509788624370,"1024375864450":1509788624261,"1025533639580":1509788624370,"1024375864453":1509788624261,"1025533639579":1509788624370,"1025533639578":1509788624370,"1024375864455":1509788624261,"1024375864454":1509788624261,"1020917386856":1478686417081,"1021573818248":1509788624397,"1022155898912":1509788624958,"1025791715561":1509788624230,"1025540586464":1509788624303,"1022944448806":1509788625052,"1005662870321":1480585069065,"1018183003514":1465470268238,"1025791715557":1509788624207,"1025791715556":1509788624207,"1025791715559":1509788624207,"1011647199178":1478686804052,"1021608682097":1509788624257,"1021696892682":1478686417121,"1025166741083":1509788624999,"1021203413652":1478686417099,"1021608682082":1509788624257,"1023152981591":1509788624228,"1021608682081":1509788624257,"1021608682087":1509788624257,"1021608682084":1509788624257,"1021608682091":1509788624257,"1021608682088":1509788624257,"1021608682089":1509788624257,"1021696892688":1478686417121,"1021608682094":1509788624257,"1021608682092":1509788624257,"1021608682093":1509788624257,"1021608682066":1509788624257,"1021595706646":1478686417115,"1019344579428":1509788624374,"1021432786157":1478686417044,"1021608682065":1509788624257,"1019344579429":1509788624374,"1019344579426":1509788624374,"1019344579427":1509788624374,"1021608682068":1509788624257,"1019344579425":1509788624374,"1021608682072":1509788624257,"1025710976993":1509788624293,"1021595706649":1478686417115,"1021608682079":1509788624257,"1021608682077":1509788624257,"1021763214089":1478686417127,"1021763214091":1478686417127,"1025034884609":1509788624213,"1020363877560":1509788624931,"1019596495482":1509788624933,"1025034884608":1509788624197,"1021763214084":1478686417127,"1021432786163":1478686417044,"1020363877566":1509788624932,"1021432786161":1478686417044,"1025034884614":1509788624206,"1022409290492":1480585069098,"1021555206098":1478686417245,"1022409290473":1480585069098,"1022409290472":1480585069098,"1001790341600":1478686417023,"1021608682017":1509788625204,"1021608682022":1509788625205,"1021608682020":1509788625205,"1022058908097":1509788625065,"1021608682024":1509788625205,"1020363877595":1509788624940,"1021608682030":1509788625205,"1022044358695":1509788625066,"1022409290470":1480585069098,"1021020407555":1478686417090,"1021608682003":1509788625205,"1021608682000":1509788625205,"1019775275481":1509788624313,"1021608682006":1509788625205,"1021608682007":1509788625204,"1021034038484":1478686417091,"1021608682005":1509788625205,"1021608682010":1509788625205,"1021608682008":1509788625205,"1021608682015":1509788625205,"1023035150117":1509788624392,"1021608682013":1509788625205,"1021835039872":1509788624562,"1021835039873":1509788624561,"1025069356146":1509788624308,"1021608681998":1509788625205,"1021608681999":1509788625205,"1021608681996":1509788625204,"1025533638911":1509788624371,"1023150884582":1509788624978,"1023150884577":1509788624978,"1021698465688":1478686417121,"1021835039868":1509788624561,"1023150884587":1509788624978,"1021835039871":1509788624562,"1022273763848":1478686417014,"1022754266813":1509788624185,"1021034038279":1478686417091,"1001790341387":1478686417023,"1024780347391":1509788624973,"1024003921229":1509788624930,"1004353054259":1444487341707,"1025533638830":1509788624371,"1025533638829":1509788624371,"1025533638828":1509788624371,"1025533638827":1509788624370,"1025533638826":1509788624370,"1022754266847":1509788624185,"1025533638825":1509788624370,"1025533638824":1509788624370,"1025533638823":1509788624370,"1025533638822":1509788624370,"1023032528712":1509788625242,"1018546591767":1480585069070,"1848103108":1478950494927,"379299954":1478686417017,"1025796827202":1509788624832,"228307608":1444487341748,"1025703374675":1509788624297,"1023924623699":1509788624961,"1025533639013":1509788624370,"1025533639012":1509788624370,"1025533639011":1509788624370,"1025533639010":1509788624370,"1025533639009":1509788624370,"1025533639008":1509788624370,"1025533639007":1509788624370,"1022246239568":1478686417066,"1021575914860":1509788624397,"1001675654997":1478686804029,"1022020373246":1478686417266,"1023150884644":1509788624977,"1020477253249":1465470268318,"1020561531291":1478686417224,"1020561531293":1478686417224,"1022227365595":1478686417281,"1023150884649":1509788624977,"1021368824302":1478686417006,"1022367610471":1478686417204,"1000979804348":1478950494933,"1025796303241":1509788624273,"1021338022897":1465470268221,"1012127701001":1478686417025,"1021338022901":1465470268222,"1024944970980":1509788624531,"1023150884631":1509788624978,"1024944970982":1509788624531,"1025533638916":1509788624370,"1021338022892":1465470268221,"1025533638915":1509788624370,"1025533638914":1509788624370,"1024944970984":1509788624531,"1025533638913":1509788624371,"1021338022895":1465470268221,"1025533638912":1509788624371,"1025283393728":1509788624548,"1009385716585":1491634246510,"1012129143013":1478686417073,"1019160425924":1480585069078,"225686227":1444487341746,"1001790341138":1478686417023,"1022195744985":1478686417280,"1024444283623":1509788625030,"1020822622854":1478686417030,"1021608682434":1509788624593,"1019552849225":1478686804026,"1021608682435":1509788624593,"1022409290506":1480585069098,"1021608682438":1509788624593,"1021608682439":1509788624593,"1022409290511":1480585069098,"1021608682436":1509788624593,"1021608682437":1509788624593,"1021700300096":1478686804046,"1021608682442":1509788624593,"1021608682441":1509788624593,"1022409290502":1480585069098,"1021608682418":1509788624593,"1022406275846":1478686417070,"1021608682416":1509788624593,"1021608682417":1509788624593,"1021608682423":1509788624593,"1022045276558":1478686417059,"1021608682426":1509788624593,"1021608682427":1509788624592,"1021608682431":1509788624593,"1025533639087":1509788624370,"1025713466998":1509788624295,"1025533639086":1509788624370,"1021763214058":1478686417127,"1025533639085":1509788624370,"1025533639084":1509788624370,"1025533639083":1509788624370,"1021608682406":1509788624592,"1021354537537":1465470268231,"1022329469089":1478686417015,"1021608682414":1509788624593,"1021455068282":1509788624857,"1021455068281":1509788624857,"1021455068286":1509788624857,"1021835040023":1509788624857,"1021835040024":1509788624857,"1022045276577":1478686417059,"1021835040025":1509788624857,"1021835040027":1509788624857,"1021455068277":1509788624857,"1022255414327":1509788624311,"1021510642128":1509788624401,"1019282952466":1509788624313,"1144620088":1444487341743,"1024786782944":1509788624241,"1024786782950":1509788624241,"1021838699199":1509788624352,"1021001955473":1478686417034,"1012641236734":1478686417074,"1024786782953":1509788624241,"1022007129278":1478686417158,"1022019974595":1478686417161,"1021250176952":1478686804031,"1024786782914":1509788624241,"1024786782917":1509788624241,"1024786782916":1509788624241,"1019272597926":1478686804021,"1021716145088":1509788624448,"1024786782926":1509788624241,"1021032626836":1478686417091,"1021767657158":1509788624195,"1024786782929":1509788624241,"1021094362409":1478686417094,"1021032626835":1478686417091,"1024786782939":1509788624241,"1024786782937":1509788624241,"1021747995710":1478686416977,"1024375865633":1509788625214,"1016301576422":1480585069066,"1024375865632":1509788625214,"1024375865635":1509788625214,"1024184399496":1509788624438,"1024375865634":1509788625214,"1024375865637":1509788625214,"1001003012289":1444487341756,"1021166158487":1478686417098,"1024375865640":1509788625214,"1020233992718":1465470268316,"1024375865644":1509788625214,"1024375865649":1509788625214,"1025810306992":1509788667452,"1024375865651":1509788625214,"1021427781993":1478686417106,"1021958762947":1478686417147,"1021716145086":1509788624448,"1024375865653":1509788625214,"1024375865652":1509788625215,"1021716145084":1509788624448,"1021716145085":1509788624448,"1024375865654":1509788625215,"1019842507756":1509788625078,"1024375865657":1509788625214,"1024375865656":1509788625214,"1024528566811":1509788624183,"1024528566810":1509788624183,"1022257120245":1478686417284,"1024528566831":1509788624183,"1024926769890":1509788624415,"1024528566829":1509788624183,"1024375865611":1509788625213,"1024375865613":1509788625215,"1024375865612":1509788625215,"1021959155968":1478686417010,"1024375865614":1509788625215,"1022019974590":1478686417161,"1024375865619":1509788625215,"1024528566836":1509788624183,"1024008891189":1509788667493,"1024528566834":1509788624183,"1024375865623":1509788625214,"1024528566832":1509788624183,"1024375865625":1509788625214,"1024528566845":1509788624183,"1024375865628":1509788625214,"1021477196891":1478686417109,"1013563866481":1478686804016,"1020542410089":1509788625078,"1690412123":1444487341724,"1022978027124":1509788624548,"1021845252860":1480585069083,"1047002828":1444487341722,"950794240":1478686417023,"1022340483192":1478686417202,"1021428044187":1478686804026,"1025407024966":1509788624566,"1000528491619":1444487341710,"1022454386503":1509788624923,"1025881348880":1509788667464,"1022073452552":1509788624338,"1021941985319":1478686417143,"1021653491487":1478686417248,"1022317807309":1509788624292,"1021716144939":1509788624218,"1021716144937":1509788624218,"1025407024936":1509788624539,"1025407024942":1509788624546,"1021716144940":1509788624218,"1021716144941":1509788624218,"1025407024931":1509788624565,"1023135053758":1509788625073,"1025407024929":1509788624611,"1025407024928":1509788624612,"1021716144954":1509788624856,"1020903781031":1478686417080,"1025556154326":1509788624384,"1021716144955":1509788624856,"1047002805":1444487341742,"1025407024959":1509788624546,"1025407024957":1509788624546,"1021716144956":1509788624856,"1025407024956":1509788624546,"1021716144957":1509788624856,"1025407024947":1509788624546,"1025289189321":1509788624821,"1022293689666":1478686417199,"1021189096347":1465470268190,"1022456876847":1478686417072,"1023483939943":1509788624947,"1022229201286":1509788624938,"1021014276387":1478686417035,"1025407024873":1509788624838,"1022169923576":1478686804049,"1022396844656":1478686417291,"1008898090726":1480585069067,"1025407024882":1509788624838,"1022463430239":1478686417072,"1567988820":1444487341730,"1003913051179":1478686804060,"1003913051181":1478686804060,"1003913051182":1478686804060,"1003913051183":1478686804060,"1021767657436":1509788624817,"1025441333454":1509788624861,"1022301815859":1478686417199,"1025441333451":1509788624861,"1025441333450":1509788624861,"1025441333449":1509788624861,"187681304":1444487341705,"1003913051184":1478686804060,"1003913051185":1478686804060,"1025441333446":1509788624861,"1024926770097":1509788624189,"1025416724045":1509788624335,"1003913051187":1478686804060,"1003913051188":1478686804060,"1003913051189":1478686804060,"1025407024811":1509788624917,"1024375865376":1509788625225,"1024375865378":1509788625225,"4965656242":1509788624160,"1024375865388":1509788625226,"1024375865391":1509788625225,"1025429406181":1509788624407,"1024375865395":1509788625225,"1024375865394":1509788625226,"1001797058172":1478686804054,"1025429406177":1509788624431,"1008170400284":1478686804022,"1025429406176":1509788624428,"1024375865396":1509788625225,"1016839733732":1478686804031,"1025429406178":1509788624426,"1023947286964":1491634246517,"1025407024816":1509788624916,"1025407024823":1509788624865,"1025407024821":1509788624865,"1024375865345":1509788625226,"1024375865344":1509788625225,"1024375865346":1509788625226,"1022190632646":1478686417064,"1024375865349":1509788625226,"1003492173124":1478686417220,"1024375865351":1509788625226,"1024375865354":1509788625226,"1021425029164":1509788624978,"1024375865357":1509788625225,"1024375865356":1509788625225,"1024375865358":1509788625225,"1024375865363":1509788625225,"4969982281":1509788624159,"1024375865365":1509788625225,"1022433152091":1478686417016,"1021824018657":1478686416982,"1024375865368":1509788625225,"1024375865372":1509788625225,"1024375865375":1509788625225,"1024786783078":1509788624879,"1021767657330":1509788624533,"1024786783076":1509788624880,"1021797672585":1509788625084,"1024786783087":1509788624879,"1024786783088":1509788624880,"1021937922383":1478686804072,"4968540602":1509788624159,"1024786783043":1509788624880,"1019618239666":1509788624971,"1024786783046":1509788624879,"1019833987996":1478686804021,"1024786783045":1509788624880,"1024786783044":1509788624880,"1024786783049":1509788624880,"1016092512915":1509788624941,"1024786783048":1509788624880,"1009848934121":1491634246514,"1025441333330":1509788624224,"1016967005865":1478686804023,"1025441333327":1509788624224,"1025441333326":1509788624224,"1024786783058":1509788624880,"1025441333325":1509788624224,"1025441333324":1509788624224,"1024786783056":1509788624880,"1024786783062":1509788624879,"1024786783061":1509788624879,"1024786783060":1509788624880,"1020798397703":1478686417077,"1022428564520":1509788624363,"1024786783064":1509788624880,"1016967005861":1478686804025,"1024786783071":1509788624880,"1024786783070":1509788624879,"1016967005863":1478686804032,"1024786783069":1509788624880,"1003279833344":1478686804054,"840823761":1478686804054,"1010091945742":1491634246522,"1010091945744":1491634246522,"1693427005":1444487341747,"1024786783037":1509788624880,"1023054836698":1509788624228,"1024786782980":1509788624879,"1025722749137":1509788624308,"1023731145254":1509788624960,"1024786783000":1509788624880,"1021398290695":1478686417106,"1024786783004":1509788624880,"1021981962288":1509788624272,"1024786782433":1509788625180,"1021966627613":1509788624464,"249547993":1478686417019,"1021981962292":1509788624271,"1021981962293":1509788624271,"1021848266755":1478686417135,"1021981962297":1509788624271,"1021981962301":1509788624271,"1021981962286":1509788624272,"1021981962285":1509788624271,"1020401374820":1478686804028,"1000622865167":1478686804059,"1024786782401":1509788625180,"1024786782407":1509788625180,"1022392256923":1478686417206,"1024786782404":1509788625180,"1024786782415":1509788625180,"1000622865152":1478686804059,"1024786782419":1509788625180,"1000622865180":1478686804059,"1024253868182":1509788624948,"1024786782418":1509788625180,"1000622865183":1478686804059,"1022029412202":1478686417165,"1000622865177":1478686804059,"1000622865176":1478686804059,"1022119328212":1509788624943,"1024786782420":1509788625180,"1024786782427":1509788625180,"1024918905658":1509788624994,"1024786782426":1509788625181,"1000622865175":1478686804059,"1024786782425":1509788625180,"1024786782424":1509788625181,"1024918905663":1509788624994,"1021147939833":1478686417097,"1024918905662":1509788624994,"1024786782430":1509788625180,"1024918905661":1509788624994,"1024786782429":1509788625180,"1024918905660":1509788624994,"1024918905666":1509788624994,"1024918905665":1509788624994,"1024918905664":1509788624994,"1025911627698":1509788667466,"187681129":1444487341705,"1024786782379":1509788625180,"1024786782383":1509788625181,"1024786782382":1509788625181,"1024686380721":1509788624510,"1024786782381":1509788625181,"1021981962338":1509788624271,"1024686380719":1509788624509,"1024786782387":1509788625181,"1024954951340":1509788624924,"1021981962343":1509788624271,"1024954951339":1509788624924,"1022192336349":1478686416985,"1024786782394":1509788625181,"1022126406093":1478686417184,"1024786782392":1509788625181,"1018957659176":1509788624362,"1024786782397":1509788625180,"1024786782396":1509788625180,"1023946499450":1491634246531,"1021981962321":1509788624271,"1021981962324":1509788624271,"1022026397441":1478686417058,"1021848266851":1480585069071,"1021981962334":1509788624271,"1019618240377":1509788624971,"1021981962306":1509788624271,"169724012":1478686804024,"1021981962307":1509788624271,"1021981962304":1509788624271,"1021704872131":1478686417122,"1021981962309":1509788624271,"1021981962315":1509788624271,"1021981962312":1509788624271,"187681108":1444487341705,"1021981962316":1509788624271,"1021733709438":1509788624395,"1021329213855":1478686417041,"1021176774793":1478686417098,"1025035430583":1509788624210,"1021310077113":1478686417005,"1024664096985":1509788625026,"1021494368169":1509788624398,"1017239902787":1509788624286,"1022553085599":1480585069123,"758640535":1444487341752,"1022553085607":1480585069123,"187681165":1444487341705,"1009850506638":1478686804024,"1024254392349":1509788625017,"1021741180620":1478686417253,"1021446918323":1509788624429,"1025407024450":1509788624208,"1021316630896":1478686417041,"1025407024454":1509788624208,"1022553085618":1480585069123,"1025407024464":1509788624208,"1021992186154":1478686417155,"1022553085624":1480585069123,"1025407024468":1509788624208,"1021446918358":1509788624439,"1021094363099":1478686417094,"1025407024424":1509788624270,"1025407024428":1509788624270,"1021189882253":1478686417038,"1025407024440":1509788624199,"1023596400930":1509788624519,"1025407024438":1509788624228,"1025616185717":1509788624929,"1024926769250":1509788624189,"1024926769253":1509788624189,"1009518627298":1478686804067,"1016779079386":1478686804017,"1021238772870":1478686416979,"1021981962546":1509788624614,"1021981962544":1509788624614,"1021981962545":1509788624614,"1005447797431":1478686804061,"1022021547743":1509788624179,"1022313743687":1478686417287,"1021981962558":1509788624614,"1021981962556":1509788624614,"1020294024609":1465470268281,"1021886934743":1478686804027,"1021981962557":1509788624614,"1025593903575":1509788625125,"1021981962531":1509788624614,"1025593903574":1509788625115,"1021981962534":1509788624614,"1397461084":1444487341732,"1021981962533":1509788624614,"1022065718312":1478686417271,"1021981962538":1509788624614,"1021981962539":1509788624614,"1021981962537":1509788624614,"1021981962542":1509788624614,"1022155898573":1509788624958,"1004588312022":1444487341762,"1025593903577":1509788625088,"1021981962541":1509788624614,"1025593903576":1509788625107,"1021981962513":1509788624614,"1024527124830":1509788624930,"1025295743915":1509788624946,"1024527124826":1509788624930,"1021981962522":1509788624614,"1021981962526":1509788624614,"1021981962524":1509788624614,"1024527124814":1509788624930,"1018515679131":1509788624426,"1021595949063":1478686417115,"1181189456":1478686804033,"1024527124805":1509788624945,"1021981962510":1509788624614,"1025429406704":1509788625089,"1018918338534":1509788624353,"1021152789200":1478686417037,"1021820349086":1478686417053,"1012702841456":1478686417026,"1024527124783":1509788624972,"1024527124782":1509788624925,"1024527124778":1509788624345,"1024527124773":1509788625019,"1025429406701":1509788625125,"1025429406700":1509788625117,"1025429406702":1509788625109,"1022455434394":1478686417216,"1015132297491":1480585069067,"1021715358072":1509788624433,"1025284600888":1509788624946,"1021446918502":1509788624427,"758640198":1444487341733,"1021446918499":1509788624440,"1025513686543":1509788624511,"1024607996939":1509788667589,"1025513686542":1509788624511,"1024786782560":1509788624470,"1022963609099":1509788625050,"1009862960104":1491634246523,"1024786782565":1509788624470,"1024786782571":1509788624471,"1021680624526":1478686804028,"1024786782569":1509788624470,"1024786782568":1509788624470,"1024786782575":1509788624470,"1024206418967":1509788625034,"1024786782574":1509788624471,"1024786782572":1509788624470,"1024786782579":1509788624470,"1024786782578":1509788624470,"1024786782577":1509788624470,"1025732710675":1509788624942,"1024786782576":1509788624470,"1025513686554":1509788624507,"1021928484060":1478686417010,"1811130477":1478950494926,"1003913051817":1478686804060,"1003913051818":1478686804060,"1020063335372":1509788624386,"1022154063471":1478686417185,"1003913051820":1478686804060,"1003913051821":1478686804060,"1003913051822":1478686804060,"1003913051823":1478686804060,"1024786782532":1509788624470,"1024786782539":1509788624470,"1025513686565":1509788624455,"1024786782537":1509788624470,"1024786782543":1509788624470,"1069284374":1444487341732,"1003913051814":1478686804060,"1024786782541":1509788624471,"1024786782547":1509788624470,"1024786782550":1509788624470,"1003913051824":1478686804060,"1003913051825":1478686804060,"1003913051826":1478686804060,"1024786782552":1509788624470,"1003913051828":1478686804060,"1003913051829":1478686804060,"1024786782556":1509788624470,"1022124963916":1478686417013,"1018901690476":1509788624301,"1020954900099":1478686417085,"1025414233175":1509788624293,"1025414233174":1509788624293,"1021936349958":1509788624978,"1025414233168":1509788624293,"1020954900100":1478686417085,"1025414233171":1509788624293,"1020954900101":1478686417085,"1024896492458":1509788624303,"1021356740259":1478686417104,"1025414233159":1509788624293,"1022170316079":1478686417063,"1023018136468":1509788625073,"1021012310562":1478686417001,"1024786782525":1509788624471,"1025407024131":1509788625144,"1025407024128":1509788625165,"1021836208431":1478686417134,"1024926769510":1509788624415,"1025407024133":1509788625132,"1025407024132":1509788625132,"1021836208435":1478686417134,"1025407024152":1509788625169,"1021836208438":1478686417134,"1021270100841":1478686804027,"479321956":1478686804029,"1021836208437":1478686417134,"1024926769523":1509788624415,"1022998211686":1509788625050,"1024786782488":1509788624470,"1024786782493":1509788624471,"1838918043":1444487341748,"1838918040":1444487341726,"1014777872799":1478686804028,"1021396323089":1478686417043,"1025530462852":1509788624537,"1021396323094":1478686417043,"1025530462851":1509788624543,"1021396323095":1478686417043,"1025530462849":1509788624540,"1021396323093":1478686417043,"1021715884001":1509788624447,"1024597510692":1509788624939,"1022457662407":1478686417072,"1025407024123":1509788625244,"1025407024122":1509788625246,"1021396323085":1478686417043,"1022457662410":1478686417072,"1727111889":1478686804027,"1022784956021":1509788624554,"1022784956030":1509788624554,"1022784956025":1509788624554,"187682562":1444487341703,"1022784956024":1509788624554,"1022784956026":1509788624554,"1021618887142":1478686804067,"1021679969282":1509788624396,"1021715883998":1509788624447,"1021715883999":1509788624448,"1021715883996":1509788624447,"1021618887141":1478686804067,"1025798509185":1509788624428,"1025616187303":1509788624929,"1025798509184":1509788624425,"1025798509187":1509788624406,"1022956922965":1509788624419,"1021715883936":1509788624853,"1010812558752":1509788624300,"1025530462938":1509788625108,"1022258169825":1478686417196,"1025516044598":1509788624338,"1025516044597":1509788624336,"1020294023884":1465470268281,"1021346515061":1478686417005,"1009423073998":1478686804022,"1025407024002":1509788625132,"1021346515064":1478686417005,"1025407024005":1509788625169,"1025407024004":1509788625132,"1021715883934":1509788624853,"1021715883935":1509788624853,"1021715883932":1509788624853,"1021485584848":1478686417046,"1022307058340":1478686417199,"1025007510446":1509788624978,"1021183723473":1478686417234,"1022309942013":1478686417068,"1022457662381":1478686417072,"1025407023979":1509788625165,"1025407023978":1509788625244,"1025407023977":1509788625246,"1025530462732":1509788624800,"1021721388863":1478686804040,"1019552048751":1480585069074,"1020519866328":1509788624320,"4980206661":1509788624159,"1025407023999":1509788625132,"1025407023997":1509788625132,"1022210983164":1478686417064,"1021944476889":1478686417144,"1000526131313":1444487341714,"1019552048764":1480585069074,"1022233527722":1478686416980,"1025407023991":1509788625132,"1010023788141":1491634246516,"1025407023990":1509788625132,"1019552048762":1480585069074,"4969983140":1509788624159,"1025407023989":1509788625144,"1019552048763":1480585069074,"1022071749751":1509788624970,"1025407023948":1509788624868,"1023933916017":1491634246529,"1025407023939":1509788624839,"1022233527706":1478686416980,"1025407023941":1509788624839,"1022233527708":1478686416980,"1000526131288":1444487341714,"1010023788111":1491634246516,"1021807242328":1478686417131,"1021807242331":1478686417131,"1025530462794":1509788624198,"1025530462793":1509788624204,"1021647854288":1478686417119,"1021618886943":1478686804067,"1025798509183":1509788624431,"150850609":1444487341728,"1021465268273":1478686417300,"1021716539185":1478686417123,"1025407023929":1509788624839,"1025407023935":1509788624839,"1025407023921":1509788624839,"1023995653867":1491634246532,"1021715883790":1509788624556,"1020976788217":1478686417229,"1021715883791":1509788624556,"1021715883789":1509788624556,"1023995653868":1491634246530,"1021934121989":1509788625069,"4968541397":1509788624159,"1025407023903":1509788624916,"1021618886944":1478686804067,"1025407023901":1509788624917,"1012322105098":1478686804064,"1025732974181":1509788624957,"1014743140215":1480585069067,"1021715883792":1509788624556,"1021865045518":1509788624513,"1025407023842":1509788624546,"1022435379227":1478686417294,"1025407023858":1509788624546,"1019287017418":1509788624314,"2005512875":1491634246533,"1025407023816":1509788624565,"1025407023820":1509788624565,"1025407023815":1509788624611,"1025407023814":1509788624613,"1025407023834":1509788624546,"1021715883738":1509788624218,"1025407023839":1509788624546,"1025407023838":1509788624546,"1021715883736":1509788624218,"1021715883737":1509788624218,"1021392521832":1478686417006,"1021715883735":1509788624218,"1025407023826":1509788624565,"1021392521834":1478686417006,"1025407023831":1509788624552,"1021701335031":1478686417009,"1025372289375":1509788624305,"1021270101471":1478686804027,"1021574061863":1509788624397,"1021515862711":1478686417244,"1021272722747":1478686417101,"1025896683914":1509788667458,"1025896683912":1509788667465,"1022294212812":1478686417015,"1021157508109":1478686417097,"1021006806286":1478686417089,"1025896683910":1509788667461,"1021352675545":1465470268226,"1017124295890":1478686804018,"1022987201365":1509788624509,"1021568294829":1478686804046,"1021989697217":1478686417155,"816051679":1444487341755,"1021455963671":1509788624398,"1011395182259":1478686804061,"1021865045646":1509788624512,"1021595295413":1478686417115,"1021595295411":1478686417115,"179818285":1444487341749,"1021865045654":1509788624512,"1022330258129":1478686417288,"4969983396":1509788624161,"1022848787449":1509788624352,"1024685723981":1509788624451,"1009987740343":1491634246533,"1021865045667":1509788624512,"1021568294681":1478686804046,"1021211378136":1478686804066,"1020823693557":1478686417031,"1024688607504":1509788624229,"1020441088548":1465470268258,"1021841321822":1509788624977,"1023031112786":1509788625048,"1018515153215":1509788624426,"1024008892083":1509788667493,"1023904030836":1509788624290,"1025591283472":1509788624341,"1022331699549":1478686417288,"1021562527522":1478686417113,"1022331699533":1478686417288,"1024341162379":1509788624820,"1018918337204":1509788624353,"1024341162380":1509788624820,"1019448499478":1478686804021,"1022238639331":1509788624947,"1021235757219":1509788624930,"1024880236895":1509788625023,"1022050381873":1478686417172,"1022064013599":1478686417060,"1024987194146":1509788667581,"1024987194148":1509788667581,"598599061":1444487341728,"1017436251449":1478686804015,"1024135247257":1509788667494,"1024135247261":1509788667494,"1024135247262":1509788667494,"1006268812522":1478686804052,"1023017875007":1509788624439,"1024135247253":1509788667494,"1006268812527":1478686804052,"1022620458573":1509788625061,"1006268812526":1478686804052,"1006268812528":1478686804052,"1021037476909":1465470268183,"1006268812530":1478686804052,"1020831951080":1478686417031,"1006268812535":1478686804052,"1021763724139":1478686416991,"1022091018220":1478686417180,"1024734089304":1509788624342,"1024135247293":1509788667494,"1024135247292":1509788667494,"1022194170126":1478686417189,"1024135247281":1509788667494,"1022097702722":1478686417275,"1024135247283":1509788667494,"1024135247286":1509788667494,"1025532035300":1509788624295,"1025798508736":1509788624542,"1025532035297":1509788624295,"1024135247279":1509788667494,"1024135247278":1509788667494,"1019093286948":1509788624315,"1024135247265":1509788667494,"1024135247264":1509788667494,"1024135247267":1509788667494,"1025532035306":1509788624295,"1872210207":1444487341737,"1025532035103":1509788624295,"1024341162242":1509788624820,"1024341162240":1509788624820,"1024734613642":1509788624939,"1021769752642":1478686417052,"1024734613640":1509788624939,"1022220814189":1478686417013,"1008082448407":1478686804023,"1017808239724":1478686804016,"1021044292747":1478686417036,"1304267554":1444487341748,"1021939496472":1478686417145,"1025532035124":1509788624295,"1021298019408":1478686417041,"1022039109635":1478686417169,"1022328947146":1478686417288,"1016964120972":1478686804019,"1025532035109":1509788624295,"1024341162273":1509788624821,"1024341162276":1509788624821,"1022039109648":1478686417169,"1025532035115":1509788624295,"1025880038757":1509788667403,"1017168598485":1478686804016,"1021710640285":1478686417250,"1017168598483":1478686804016,"1018651601526":1478686804018,"4834977512":1491745484345,"1024341162307":1509788624821,"1018023624913":1478686804027,"1024341162309":1509788624821,"1017168598477":1478686804016,"1019909353824":1509788625076,"1017168598479":1478686804016,"1020073953043":1465470268308,"1024002731364":1491634246532,"1022422928148":1478686417293,"1021345467104":1465470268224,"1021345467105":1465470268224,"1024341162352":1509788624820,"4673228910":1478943089212,"1021345467108":1465470268225,"1002377290841":1478686417024,"1022998604139":1509788625049,"1012702842838":1478686417026,"1022956923629":1509788624816,"1006891149685":1478686804025,"1024341162351":1509788624820,"1021865045493":1509788624512,"1004790691291":1480585069067,"187681827":1444487341706,"1008897696025":1478686804030,"1024341162141":1509788624518,"1024341162118":1509788624821,"1024341162116":1509788624821,"1021943035769":1509788624464,"1023092716245":1509788625046,"1010295242121":1491634246528,"1018023625017":1478686804022,"1021029875151":1478686417231,"1024734613854":1509788624939,"1022784955677":1509788625147,"1024341162202":1509788624820,"1024341162200":1509788624820,"1021003005733":1478686416982,"214158222":1478686417019,"1022238901647":1509788624932,"1022238901646":1509788624946,"1022238901649":1509788624941,"1019723492349":1478686804021,"1022238901648":1509788624931,"1025530462684":1509788624431,"1024341162176":1509788624518,"1025530462683":1509788624428,"1022455957673":1478686417298,"1021510095119":1509788624398,"1009857456004":1491634246520,"1021618887348":1478686804067,"1021618887349":1478686804067,"1021618887347":1478686804067,"1025530462688":1509788624407,"1022784955681":1509788625147,"1022784955680":1509788625147,"1021387802862":1478686417239,"1024341162213":1509788624821,"1022784955683":1509788625147,"1024341162218":1509788624821,"1022784955692":1509788625147,"1021925599251":1478686417141,"1020233993532":1465470268316,"1021886933671":1478686804027,"1024943940613":1509788624977,"1025407023208":1509788624839,"1025007116354":1509788667497,"1025407023212":1509788624839,"1022453074324":1478686417296,"1024341161991":1509788624821,"1024341161990":1509788624821,"1025407023221":1509788624839,"1022643920163":1509788625102,"1025407023183":1509788624865,"1021607353295":1478686417049,"1025407023170":1509788624917,"1025407023175":1509788624916,"1016444448659":1478686804069,"1025407023194":1509788624839,"1009518628000":1478686804067,"1021609188351":1478686417116,"1025407023197":1509788624839,"1025407023186":1509788624849,"1021786529898":1509788625068,"1025565331288":1509788624337,"1021289238205":1478686417102,"1004588310784":1444487341762,"1021355821740":1478686416978,"1024341162079":1509788624820,"1024341162078":1509788624820,"1024341162051":1509788624821,"1024341162050":1509788624821,"1022415719301":1478686417209,"1021510619635":1478686417112,"1018850574089":1509788624373,"1021662271685":1509788624396,"313906504":1444487341738,"4654357862":1478686416965,"1018518695056":1480585069063,"1024186629816":1509788625250,"1024186629819":1509788625250,"1024341161863":1509788624821,"1024186629821":1509788625249,"1024186629820":1509788625249,"1024186629822":1509788625249,"207602757":1491634246513,"1015599971982":1465470268257,"1024341161864":1509788624821,"1010002288678":1491634246524,"1024186629815":1509788625248,"1024786780865":1509788624573,"1021097768677":1478686417036,"1024809718694":1509788624925,"1024786780871":1509788624573,"1024786780870":1509788624573,"1024786780869":1509788624573,"1018981222598":1509788624316,"1024786780875":1509788624573,"1024786780873":1509788624573,"1024786780872":1509788624573,"1024794382915":1509788624576,"1024794382914":1509788624576,"1024794382912":1509788624576,"1024341161898":1509788624518,"1022646932014":1480585069153,"1021235105524":1465470268196,"1024786780833":1509788624573,"1022646932011":1480585069153,"1024786780839":1509788624573,"1022646932009":1480585069153,"1024786780837":1509788624573,"1022472214718":1478943089486,"1024786780836":1509788624573,"1022646932007":1480585069153,"1024341161947":1509788624843,"1156418724":1444487341727,"1025909527646":1509788667461,"1022646932005":1480585069153,"1024786780847":1509788624573,"1019220428517":1509788625020,"1022646932000":1480585069153,"1024186629862":1509788624440,"1021838566126":1478686417009,"1024794382911":1509788624576,"1018981222591":1509788624315,"1024786780850":1509788624573,"1024794382910":1509788624576,"1024341161922":1509788624821,"1024341161921":1509788624821,"1024186629882":1509788624430,"1024786780855":1509788624573,"1024186629884":1509788624430,"1021215575434":1478686417038,"1024186629887":1509788624430,"1024786780853":1509788624573,"1024794382905":1509788624576,"1001796531976":1478686417017,"1024186629873":1509788624441,"1024186629872":1509788624441,"1024794382902":1509788624576,"1024186629875":1509788624430,"1025609761711":1509788624566,"1024786780857":1509788624573,"1024186629877":1509788624430,"1024186629876":1509788624430,"1022646932017":1480585069153,"1024786780861":1509788624573,"1023854095099":1491634246514,"1024186629833":1509788625248,"1024186629832":1509788625248,"1024186629835":1509788625248,"1024186629834":1509788625248,"1024186629837":1509788625250,"1021716540293":1478686417123,"1024186629836":1509788625248,"1021226061146":1478686417003,"1022646931977":1480585069153,"1022646931976":1480585069153,"1024186629825":1509788625250,"1024186629824":1509788625249,"1022646931973":1480585069153,"1024186629827":1509788625248,"1022646931971":1480585069153,"1024786780814":1509788624573,"1024186629828":1509788625249,"1021858096126":1478686417135,"1021399996589":1478686417240,"1024186629830":1509788625248,"1021849051758":1509788624437,"1024786780819":1509788624573,"1024186629849":1509788625248,"1021864256327":1478686417053,"1024186629848":1509788625249,"1022646931997":1480585069153,"1024186629851":1509788625248,"1025909527652":1509788667464,"1022436033909":1478686417071,"1022646931995":1480585069153,"1024786780823":1509788624573,"1025796808408":1509788625086,"1025909527648":1509788667464,"1022646931991":1480585069153,"1024786780827":1509788624573,"1024186629841":1509788625250,"1024786780825":1509788624573,"1025796808405":1509788625114,"1022002412678":1478686417157,"1024786780831":1509788624573,"1024341161967":1509788624820,"1024186629845":1509788625248,"1022646931986":1480585069153,"1024341161966":1509788624820,"1024186629844":1509788625249,"1024786780829":1509788624573,"1024341161745":1509788624820,"1024579028423":1509788624925,"1024341161744":1509788624820,"1024211140566":1509788625071,"1009840281423":1491634246520,"1025458375274":1509788624352,"1022061395940":1478686417060,"1022061395938":1478686417060,"1083410440":1444487341736,"1022307061361":1478686417199,"1024341161777":1509788624821,"1022285827254":1478686417301,"1024341161776":1509788624821,"1022469064608":1478686417218,"1024809718575":1509788624925,"1022469064612":1478686417218,"1022061395928":1478686417060,"1021996121070":1478686417156,"1022020763001":1478686417058,"1021350315375":1478686417239,"1025710823695":1509788624339,"1022646932141":1480585069117,"1024341161809":1509788624821,"1022646932133":1480585069117,"1022646932129":1480585069117,"1021025415652":1478686417001,"1022827818356":1509788624198,"1022646932155":1480585069117,"1021025415649":1478686417001,"1025567817890":1509788624936,"1022646932151":1480585069117,"1022995195764":1509788624206,"1022646932149":1480585069117,"1024341161806":1509788624821,"1024341161843":1509788624821,"1022646932109":1480585069117,"1024341161845":1509788624821,"1023829846283":1509788667494,"1022646932101":1480585069117,"1022721513201":1509788624985,"1022646932124":1480585069117,"1022646932117":1480585069117,"1022202464751":1509788624939,"1024809718406":1509788624925,"1022202464750":1509788624937,"1014508420225":1465470268246,"1022202464747":1509788624939,"1022202464746":1509788624938,"1022202464740":1509788624939,"1022202464743":1509788624939,"1022202464742":1509788624939,"1024786781166":1509788624240,"1024786781171":1509788624240,"1024786781170":1509788624241,"1024786781169":1509788624241,"1024786781175":1509788624240,"1022202464761":1509788624938,"1024341161605":1509788624518,"1024786781179":1509788624240,"407621970":1478950494909,"1024786781177":1509788624240,"1022202464759":1509788624939,"1016399884240":1480585069069,"1024786781183":1509788624240,"1024786781182":1509788624240,"1024786781181":1509788624240,"1024786781180":1509788624240,"1024341161651":1509788624919,"1022202464716":1509788624939,"1022202464718":1509788624937,"1022202464712":1509788624939,"476566849":1444487341724,"1022202464714":1509788624938,"1019463570694":1509788624314,"1008058203440":1480585069066,"1022468539930":1478686417073,"1022398808690":1478686417292,"1022578384808":1509788624539,"1008058203435":1480585069066,"595192394":1444487341718,"1022982350759":1509788624982,"1008058203438":1480585069066,"1022202464724":1509788624938,"1022202464727":1509788624937,"1008058203429":1480585069066,"1024341161647":1509788624919,"1025646724253":1509788625004,"1021756255416":1509788624400,"1022202464722":1509788624938,"1024786781091":1509788624237,"1022202464684":1509788624939,"1024786781089":1509788624237,"1022202464687":1509788624939,"1024786781095":1509788624237,"1024786781099":1509788624237,"1024786781102":1509788624237,"1022202464700":1509788624938,"1024786781105":1509788624237,"1024786781104":1509788624237,"1022202464697":1509788624939,"1024786781108":1509788624237,"1024786781114":1509788624237,"1024786781112":1509788624237,"1020865247742":1478686417079,"1024786781118":1509788624237,"1024786781117":1509788624237,"1022202464691":1509788624939,"1022202464690":1509788624939,"1020858951267":1478686417031,"1024341161714":1509788624820,"1024341161712":1509788624820,"1012315552571":1478686417223,"1023947026044":1491634246531,"1024786781069":1509788624237,"1024786781075":1509788624237,"1024786781074":1509788624237,"1024786781072":1509788624237,"1024786781077":1509788624237,"1024786781082":1509788624237,"1024786781081":1509788624237,"1024786781080":1509788624237,"1025428228572":1509788624332,"1022987200348":1509788624509,"1024786781087":1509788624237,"1024786781086":1509788624237,"1024786781085":1509788624237,"1022280060360":1478686416986,"1007384479145":1478686804023,"1001528092377":1478686417022,"1022280060353":1478686416986,"1022280060354":1478686416986,"1022850625476":1509788624434,"1019876981787":1509788624321,"1024781406407":1509788624576,"1013208919688":1478686804015,"1020616599561":1478686417027,"1022850625494":1509788624451,"1022290807808":1478686417015,"262260234":1478950494908,"1021974887221":1509788624389,"1024186629892":1509788624456,"1022280060413":1478686416986,"1022280060412":1478686416986,"1022280060415":1478686416987,"1024469323388":1509788624522,"1011783653930":1478686804062,"1020640193481":1478686417027,"1011783653931":1478686804062,"1019842771570":1509788624282,"1022457136667":1478686417072,"1011783653934":1478686804062,"1011783653932":1478686804062,"1011783653933":1478686804062,"1011783653927":1478686804062,"1022215834095":1478686417191,"1209106881":1444487341701,"1022215834099":1478686417191,"4834978300":1491745484344,"1022215834101":1478686417192,"1024453594891":1509788624992,"1023820802369":1491634246535,"1024008888986":1509788667493,"1022280060349":1478686416986,"1021006672290":1478686417035,"1017554346988":1465470268261,"1024786780391":1509788624571,"1024786780390":1509788624571,"1024786780389":1509788624571,"1024786780388":1509788624571,"1024786780394":1509788624571,"1024786780393":1509788624571,"1024633821706":1509788624299,"1024786780399":1509788624571,"1024786780398":1509788624571,"1024856642772":1509788624949,"1021995202890":1478686417057,"1024786780396":1509788624571,"1024786780403":1509788624571,"1021917865456":1509788624869,"1024786780402":1509788624571,"1024786780407":1509788624571,"1024786780406":1509788624571,"1021995202899":1478686417057,"1024786780404":1509788624571,"1024786780408":1509788624571,"1024786780415":1509788624571,"1024786780412":1509788624571,"1025890914578":1509788667456,"1016538817713":1478686804066,"1021917865434":1509788624849,"1023627730521":1509788624278,"1023627730524":1509788624278,"1023627730527":1509788624277,"1499304730":1478686804024,"1019276139314":1509788624311,"1023627730514":1509788624278,"1022280060417":1478686416987,"1023627730505":1509788624277,"1025509232546":1509788624344,"1023627730510":1509788624278,"1012204660392":1478686417223,"1022057856490":1478686417059,"1022421747614":1478686417210,"1023627730544":1509788624278,"1023627730547":1509788624278,"1023627730548":1509788624278,"1021801603718":1509788624222,"1020322334056":1465470268301,"1021801603716":1509788624222,"1028171082076":1532526019715,"1021801603717":1509788624222,"1023627730542":1509788624278,"1021801603720":1509788624222,"1347263025":1478686804032,"1024607995380":1509788667589,"1025269922999":1509788624461,"1022646931691":1480585069152,"1022646931689":1480585069152,"1019355962428":1509788624312,"1022759267159":1509788624394,"1025269923005":1509788624424,"1022849707251":1509788625054,"1022646931684":1480585069152,"1025269922983":1509788624423,"1023627730568":1509788624278,"1022646931709":1480585069152,"1022646931708":1480585069152,"1025269922980":1509788624507,"1013020169931":1478686804028,"1022646931701":1480585069152,"1023627730563":1509788624277,"378788872":1491634246507,"1025772166844":1509788625003,"1024304461631":1509788624311,"1022646931697":1480585069152,"1008898092406":1480585069067,"1025269922984":1509788624433,"1022646931662":1480585069152,"1025269922965":1509788624508,"1022336942656":1478686417201,"1019834906786":1509788624375,"1025269922968":1509788624426,"1024313243535":1509788624342,"595192269":1444487341721,"595192268":1444487341725,"1022646931673":1480585069152,"1022646931669":1480585069152,"1022646931666":1480585069152,"1021856391500":1478686417300,"1022759267099":1509788624393,"1011760454589":1478686804034,"1012289600264":1478686417026,"1022209673798":1478686417191,"595192217":1444487341725,"1020960930823":1478686417033,"1024779572123":1509788624452,"1020960930821":1478686417033,"1025269923014":1509788624508,"1025269923010":1509788624461,"1022646931823":1480585069152,"1022646931819":1480585069152,"1022646931818":1480585069152,"1024716922376":1509788624342,"1024794382698":1509788625186,"1022646931817":1480585069152,"744220508":1478686804029,"1022646931815":1480585069152,"1022646931814":1480585069152,"1022646931813":1480585069152,"1024794382691":1509788625186,"1022646931810":1480585069152,"1022646931809":1480585069152,"1020907190573":1478686416999,"1024794382688":1509788625186,"1020907190583":1478686416999,"1020907190584":1478686416999,"1020907190528":1478686416999,"1022646931786":1480585069152,"1020907190532":1478686416999,"1020907190533":1478686416999,"1022646931780":1480585069152,"1021900563910":1478686417139,"1011869242335":1509788624944,"1022646931807":1480585069152,"1022646931803":1480585069152,"1024794382683":1509788625186,"1022646931800":1480585069152,"1024794382679":1509788625186,"1022646931797":1480585069152,"1024794382676":1509788625186,"1022646931795":1480585069152,"1024794382675":1509788625186,"1024794382674":1509788625186,"1022646931793":1480585069152,"1024786780579":1509788624581,"1014687435707":1478686804019,"1024786780576":1509788624582,"1024786780582":1509788624582,"1024786780586":1509788624581,"1024786780589":1509788624582,"1022646931774":1480585069152,"1024132495538":1509788624327,"1022326459613":1478686417015,"1022646931770":1480585069152,"1024132495490":1509788624327,"1024132495488":1509788624328,"1024786780551":1509788624582,"1022646931722":1480585069152,"1024132495494":1509788624328,"1024786780549":1509788624582,"1019532782441":1509788624313,"1024132495499":1509788624327,"1024688742322":1509788624199,"1024786780554":1509788624581,"1022646931717":1480585069152,"1024786780559":1509788624581,"1022646931714":1480585069152,"1024786780558":1509788624581,"1022646931712":1480585069152,"1024786780556":1509788624581,"1024632642396":1509788625026,"1022646931741":1480585069152,"1006318880478":1478686804035,"1022646931739":1480585069152,"1024132495510":1509788624327,"1022646931736":1480585069152,"1024786780570":1509788624582,"1022646931732":1480585069152,"1020021683606":1509788624320,"1020021683607":1509788624320,"1024786780574":1509788624582,"1024786780573":1509788624581,"1020021683605":1509788624320,"1025533480417":1509788624348,"1021166160209":1465470268307,"1024132495463":1509788624328,"1025533480421":1509788624348,"1024786780519":1509788624582,"1019744986849":1509788624386,"1024786780518":1509788624581,"1025533480423":1509788624348,"1025533480427":1509788624348,"1025533480426":1509788624348,"1021000250170":1465470268305,"1025533480429":1509788624348,"1024786780526":1509788624582,"1025533480430":1509788624348,"1024786780524":1509788624582,"1022646931967":1480585069153,"1024786780531":1509788624582,"1025533480432":1509788624347,"1022759266892":1509788624393,"1022646931965":1480585069153,"1024786780528":1509788624582,"1024132495479":1509788624327,"1024186629437":1509788624469,"1024786780534":1509788624582,"1022646931961":1480585069153,"1024186629438":1509788624470,"1022646931959":1480585069153,"1024786780538":1509788624582,"1024786780536":1509788624581,"1024786780541":1509788624582,"1022155896398":1509788624957,"1004588313960":1444487341762,"1022646931919":1480585069152,"1024786780483":1509788624473,"1022827818500":1509788624199,"1022646931915":1480585069152,"1024786780486":1509788624472,"1024132495429":1509788624328,"1022646931912":1480585069152,"1022646931909":1480585069152,"1022646931908":1480585069152,"1024786780493":1509788624472,"1022646931904":1480585069152,"1020764578066":1478686417028,"1021471825706":1478686417045,"1024132495443":1509788624330,"1020800624425":1478686417030,"1022646931923":1480585069153,"1022646931885":1480585069152,"1024186629483":1509788624470,"1009857456921":1491634246520,"1024186629482":1509788624470,"1022646931883":1480585069152,"1024186629485":1509788624470,"1022646931882":1480585069152,"1024186629484":1509788624469,"1022646931881":1480585069152,"1021201026937":1478686417099,"1024186629486":1509788624469,"1022646931879":1480585069152,"1022646931878":1480585069152,"1024186629472":1509788624470,"1024786780457":1509788624472,"1022646931876":1480585069152,"1024186629477":1509788624470,"1024186629479":1509788624470,"1013171302035":1478686804017,"1024411650192":1509788624436,"1020775981505":1478686804039,"1024132495409":1509788624328,"1022646931900":1480585069152,"1024132495415":1509788624327,"1022646931897":1480585069152,"1024132495413":1509788624328,"1022646931895":1480585069152,"1024186629488":1509788624470,"1022174770539":1478686417063,"1024132495423":1509788624330,"1022646931890":1480585069152,"1013868512375":1465470268239,"1009860864848":1491634246535,"1024132495421":1509788624327,"1022646931888":1480585069152,"1024786780418":1509788624571,"1024186629451":1509788624470,"1024786780417":1509788624571,"1024786780423":1509788624571,"1024186629455":1509788624470,"1024786780421":1509788624571,"1024186629454":1509788624470,"1024186629441":1509788624470,"1021754158671":1478686417009,"1024786780426":1509788624571,"1024767251428":1509788667499,"1023534531692":1509788625083,"1021166160191":1465470268307,"1024186629444":1509788624470,"1024186629466":1509788624470,"1024186629469":1509788624470,"1024186629471":1509788624470,"1024186629457":1509788624470,"1024186629456":1509788624470,"1024186629459":1509788624470,"1024186629462":1509788624470,"1001040895558":1478686804033,"1021887717804":1478686804043,"1022460674953":1480585069075,"1021025285429":1478686417091,"1021887717805":1478686804043,"1021887717806":1478686804043,"1021887717800":1478686804043,"1021887717801":1478686804043,"1021887717802":1478686804043,"1021887717803":1478686804043,"1021887717796":1478686804043,"1021887717797":1478686804043,"1021887717798":1478686804043,"1021887717799":1478686804043,"1021887717792":1478686804043,"1021887717793":1478686804043,"1021025285434":1478686417091,"1021887717794":1478686804043,"1021887717795":1478686804043,"1013631667677":1480585069072,"519951069":1478950494910,"1008369339316":1509788624310,"1023627728954":1509788624278,"1025910837696":1509788667460,"538700862":1478686417019,"1021609316449":1478686417049,"1008369339314":1509788624310,"1021887717788":1478686804043,"1021887717789":1478686804043,"1021887717790":1478686804043,"1021502888591":1478686417112,"1021887717791":1478686804043,"1000286005615":1478686804024,"1021887717787":1478686804043,"4980204694":1509788624160,"1025405973076":1509788624276,"1022032034169":1509788624462,"1016760989457":1478686804042,"1025405973067":1509788624276,"1024997288487":1509788625020,"1016760989456":1478686804042,"1025405973071":1509788624276,"1024856642191":1509788624949,"1000977449559":1478686417021,"1008369339340":1509788624310,"1016760989467":1478686804042,"1016760989469":1478686804042,"1016760989468":1478686804042,"1016860839187":1465470268266,"1016760989471":1478686804042,"1008369339339":1509788624310,"1016760989470":1478686804042,"1016760989473":1478686804042,"1016760989475":1478686804042,"1016760989474":1478686804042,"1016760989477":1478686804042,"1016760989476":1478686804042,"1009921159024":1480585069071,"1021733709977":1509788624400,"1021098160813":1478686417095,"1021098160803":1478686417094,"1024786781795":1509788625195,"1024786781794":1509788625195,"1024786781798":1509788625195,"1022252011167":1478686416987,"1024786781796":1509788625194,"1357749351":1491634246514,"1024786781801":1509788625194,"1024786781800":1509788625195,"1024880235517":1509788624576,"1024786781807":1509788625195,"1024786781806":1509788625195,"1710336383":1444487341741,"1024786781804":1509788625195,"1024786781810":1509788625195,"1022430527974":1478686417211,"1024786781808":1509788625195,"1024786781815":1509788625195,"1024786781814":1509788625195,"1024786781813":1509788625194,"1024786781812":1509788625196,"1024786781818":1509788625194,"1024786781817":1509788625195,"1024786781816":1509788625194,"1024786781821":1509788625195,"1024786781763":1509788625195,"1024786781762":1509788625196,"1024786781761":1509788625196,"1024786781760":1509788625194,"1024055943735":1509788624928,"1020604804225":1478686416995,"1024786781766":1509788625195,"1021226846615":1478686417099,"1020437027469":1478686804051,"1021845251837":1480585069083,"1021845251833":1480585069083,"1024023830717":1509788624277,"1018153779864":1465470268308,"1022474181652":1478943089315,"1009959561852":1480585069074,"1019042697104":1509788625079,"1020953328048":1478686417033,"1012551585023":1478686417223,"1022267740125":1478686417197,"116247089":1444487341710,"1020936681628":1478686417229,"1024786781699":1509788625186,"1020936681629":1478686417229,"1024786781698":1509788625185,"1024786781696":1509788625187,"1024393825963":1509788624300,"1779017452":1491634246509,"1024786781702":1509788625186,"1020936681626":1478686417229,"1024786781707":1509788625185,"1024786781706":1509788625186,"1024786781704":1509788625186,"1024786781711":1509788625185,"1024786781709":1509788625185,"1023846362622":1491634246537,"1024786781708":1509788625185,"1016780124367":1478686804016,"1024786781713":1509788625187,"1020936681615":1478686417229,"1024786781719":1509788625185,"1024786781718":1509788625186,"1024786781717":1509788625187,"1019802402031":1509788624393,"1024786781716":1509788625185,"1024136036181":1509788625036,"1024786781723":1509788625186,"1024786781722":1509788625185,"1020437420760":1478686804027,"1024786781720":1509788625186,"407622839":1478950494909,"1021618884907":1478686804046,"1022849051292":1509788624325,"1022439179249":1478686417214,"1022311385967":1478686417302,"1025628635605":1509788625022,"1022311385966":1478686417301,"1019448497713":1478686804021,"1022454514404":1478686417297,"1024809719436":1509788624925,"1022454514408":1478686417297,"1022311385983":1478686417302,"1021234842537":1478686416985,"1022311385979":1478686417302,"1023961965844":1509788625005,"1863688718":1478686417020,"1019760976800":1509788625077,"1022454514389":1478686417297,"1022454514399":1478686417297,"4553425500":1465469681389,"1024632642825":1509788625219,"1018153780066":1465470268308,"1023765614846":1509788624958,"1021845251861":1480585069083,"1023276322218":1509788625041,"1022721512284":1509788625074,"1024786782114":1509788625176,"1021845251862":1480585069083,"1019272600782":1509788624313,"1021631205470":1509788624396,"1024786782118":1509788625176,"1021845251869":1480585069083,"1024786782121":1509788625176,"1021845251864":1480585069083,"1024786782127":1509788625176,"1021845251866":1480585069083,"1021845251867":1480585069083,"1024786782124":1509788625176,"1024786782131":1509788625176,"1024786782129":1509788625177,"1021845251847":1480585069083,"1021729517165":1509788624918,"1021845251841":1480585069083,"1021845251842":1480585069083,"1024786782133":1509788625177,"1022311385912":1478686417301,"1022658729602":1509788625059,"1024786782137":1509788625175,"1021845251848":1480585069083,"1024786782143":1509788625176,"1024786782141":1509788625175,"1021259483715":1465470268200,"1024786782086":1509788625175,"1008532659383":1478686804015,"1024786782091":1509788625177,"1024786782095":1509788625177,"1024786782093":1509788625177,"1024786782092":1509788625177,"1024786782099":1509788625176,"1024786782098":1509788625177,"1024786782096":1509788625177,"1022088524963":1478686417180,"1022472215950":1478943089486,"1024786782100":1509788625176,"1024786782104":1509788625176,"378788844":1491634246507,"1024786782108":1509788625176,"1024341160467":1509788624196,"1024341160465":1509788624196,"1002347671037":1478686417024,"1022060215028":1478686417060,"1019956934486":1509788625078,"1019956934487":1509788625076,"1021329213064":1478686417041,"1024341160449":1509788624518,"1024460934109":1509788625029,"1024809719318":1509788624925,"1020898279231":1478686417080,"1023483937052":1509788624947,"1026318219298":1514456869773,"1021153971442":1478686417038,"1021153971445":1478686417038,"1019956934488":1509788625077,"1019956934497":1509788625076,"1023483937058":1509788624947,"1019956934505":1509788625077,"1011767664470":1478686804062,"1011767664468":1478686804062,"1011767664469":1478686804062,"538701231":1478686417019,"1011767664466":1478686804061,"1024786782039":1509788624880,"1011767664467":1478686804061,"1011767664465":1478686804061,"1021856392758":1478686417300,"1024341160491":1509788624518,"1024661741519":1509788624604,"1011767664477":1478686804062,"1011767664474":1478686804062,"1011767664475":1478686804062,"1011767664473":1478686804062,"1021592671878":1478686417246,"1021592671879":1478686417246,"1008601864304":1478686804030,"1021592671876":1478686417246,"1021592671877":1478686417246,"1021592671874":1478686417246,"1025453788389":1509788624930,"1021592671875":1478686417246,"1022452810692":1509788624525,"1021592671872":1478686417246,"1021592671873":1478686417246,"1022452810697":1509788624525,"1022452810696":1509788624525,"1022452810699":1509788624525,"1022452810698":1509788624525,"1022452810701":1509788624525,"1022452810700":1509788624525,"1021592671880":1478686417246,"1022452810703":1509788624525,"1021592671881":1478686417246,"1022474312969":1478943089486,"1024341160514":1509788624196,"1022452810704":1509788624525,"1024341160513":1509788624196,"1022452810709":1509788624525,"1023092324405":1509788625046,"1022021679112":1478686417162,"1016780124640":1478686804016,"1022253846037":1509788624352,"1021251881561":1478686416990,"1020898279237":1478686417080,"1020898279259":1478686417080,"1020898279249":1478686417080,"1025585775807":1509788624349,"1021791119762":1478686417129,"1024786781409":1509788624241,"1021259352355":1465470268199,"1024786781408":1509788624241,"1022465917277":1478686417218,"1024786781415":1509788624241,"1024786781414":1509788624241,"1021815105029":1509788624553,"1022101501716":1478686417012,"1021815105030":1509788624553,"1021259352359":1465470268199,"1022465917278":1478686417218,"1021815105031":1509788624553,"1021815105032":1509788624553,"1025861162225":1509788667470,"1025861162224":1509788667470,"1025861162226":1509788667470,"1024786781423":1509788624241,"1024786781420":1509788624241,"1024786781425":1509788624241,"1025861162219":1509788667470,"1024341160320":1509788624196,"1024786781424":1509788624241,"790356239":1444487341742,"1025861162221":1509788667470,"1024341160326":1509788624196,"1025861162220":1509788667470,"1022456218075":1478686417298,"1024786781429":1509788624241,"1025861162223":1509788667470,"1022252010510":1478686416987,"1024809719186":1509788624925,"1025861162222":1509788667470,"1008532135873":1478686804025,"1024786781434":1509788624241,"1024786781433":1509788624241,"1024786781439":1509788624241,"1024786781438":1509788624241,"1024786781437":1509788624241,"1024786781436":1509788624241,"1022238641383":1509788624932,"1023626811941":1509788625144,"1024727799875":1509788624279,"1025295742633":1509788624946,"1022238641379":1509788624947,"1024727799882":1509788624278,"1022238641387":1509788624931,"1024727799880":1509788624279,"1024786781393":1509788624241,"1317634236":1444487341747,"1024786781398":1509788624241,"1020896443632":1478686417032,"1024786781403":1509788624241,"1024786781402":1509788624241,"1024786781407":1509788624241,"1022465917284":1478686417218,"1024786781406":1509788624241,"1024786781405":1509788624241,"1024786781404":1509788624241,"1024786781347":1509788624239,"1018532850661":1478686804043,"1024786781345":1509788624239,"1020673747533":1478686417075,"1024786781350":1509788624239,"1021301949692":1478686417102,"1024786781348":1509788624239,"1024786781355":1509788624240,"1024341160410":1509788624196,"1024786781354":1509788624240,"1025485770000":1509788624437,"1024341160409":1509788624196,"1024786781353":1509788624239,"1024727799853":1509788624279,"1024786781352":1509788624240,"1024786781359":1509788624239,"1024727799851":1509788624278,"1024727799849":1509788624279,"1024786781356":1509788624239,"1024727799863":1509788624278,"1024341160386":1509788624518,"1025861162152":1509788667470,"1024786781360":1509788624240,"1025485769997":1509788624436,"1018651468514":1509788625019,"519950507":1478950494910,"1024727799856":1509788624279,"1025485769998":1509788624436,"1024727799871":1509788624279,"1025861162145":1509788667470,"1025861162144":1509788667470,"1025861162147":1509788667470,"1025861162146":1509788667470,"1025861162149":1509788667470,"1025445007354":1509788624369,"1025861162148":1509788667470,"1024727799865":1509788624278,"1025861162151":1509788667470,"1024727799864":1509788624278,"1025861162150":1509788667470,"1025861162143":1509788667470,"1024786781327":1509788624240,"1024786781326":1509788624240,"1024786781325":1509788624239,"1024786781331":1509788624240,"1024786781328":1509788624240,"1024786781335":1509788624240,"1024786781339":1509788624239,"1024341160426":1509788624518,"1024786781337":1509788624240,"1024786781343":1509788624239,"1024786781342":1509788624239,"1016098413245":1478686804034,"1024786781341":1509788624239,"1024786781340":1509788624239,"1083411985":1444487341744,"1023094029123":1509788625047,"935328044":1491634246512,"1022412571385":1478686417292,"1024341160204":1509788624211,"1022183682216":1509788624554,"1022183682217":1509788624554,"1022183682223":1509788624554,"1022183682208":1509788624554,"1007588562614":1478686804030,"1025874793636":1509788667834,"1020122712670":1509788624300,"1025407021355":1509788624839,"1006807393356":1478686804025,"1024341160279":1509788624197,"1024341160278":1509788624197,"1025407021358":1509788624839,"1021901742131":1478686417054,"1022269573670":1478686417197,"1025407021370":1509788624868,"1022280977037":1478686417286,"1024444418969":1509788625030,"1024341160261":1509788624196,"1021647589578":1509788624396,"1024341160260":1509788624196,"1025407021363":1509788624839,"1025407021360":1509788624839,"1025407021366":1509788624839,"1018820950086":1478686804029,"1025407021365":1509788624839,"1025798510676":1509788624200,"1021595162077":1509788624433,"1024786781185":1509788624240,"1024786781184":1509788624240,"1024184268846":1509788625035,"1022083413728":1478686417272,"1024786781189":1509788624240,"1024786781192":1509788624240,"1024786781198":1509788624241,"1024786781197":1509788624240,"1024786781203":1509788624240,"1025909920481":1509788667460,"1024786781202":1509788624240,"1024786781201":1509788624240,"1025407021336":1509788624865,"1024786781206":1509788624240,"1021700811782":1478686417122,"1024786781204":1509788624240,"1020390496791":1478686804016,"1024786781210":1509788624240,"1024786781209":1509788624240,"1025407021335":1509788624916,"1025407021332":1509788624917,"1025216707651":1509788667495,"1025533479264":1509788624347,"1025533479267":1509788624348,"1023995520265":1491634246532,"1025216707655":1509788667495,"1018988171141":1509788624316,"1025533479268":1509788624348,"1021632385505":1509788624971,"1020437027106":1478686804050,"1025216707653":1509788667495,"1022064015401":1478686417174,"1025533479270":1509788624347,"1025216707652":1509788667495,"1024973957842":1509788624288,"1022897022606":1509788625084,"1025216707657":1509788667495,"1024973957840":1509788624288,"1022897022603":1509788624973,"1024973957834":1509788624288,"1024973957832":1509788624288,"1024786781680":1509788625185,"1024786781686":1509788625187,"1024973957837":1509788624288,"1024786781685":1509788625187,"1023833386688":1491634246536,"1024341160075":1509788624196,"1024786781690":1509788625187,"1024341160073":1509788624196,"1024973957825":1509788624288,"1024786781689":1509788625187,"4943112636":1509788624160,"1024973957829":1509788624288,"1024786781693":1509788625187,"1024973957828":1509788624288,"1025533479232":1509788624348,"1025533479234":1509788624348,"1001962440272":1478686417024,"1025533479236":1509788624348,"1025533479241":1509788624348,"1021337863103":1478686417239,"1008639088720":1478686804030,"1000038406445":1478686417021,"1019386763240":1509788625076,"1025533479242":1509788624348,"1022036097496":1478686417167,"1025533479244":1509788624347,"1020838764921":1478686417031,"1025533479248":1509788624348,"1025533479253":1509788624348,"1021420183227":1478686417043,"1025533479252":1509788624347,"1025533479255":1509788624348,"1021420183225":1478686417043,"1025533479257":1509788624348,"1025533479259":1509788624348,"1025533479258":1509788624348,"1021869892576":1478686416983,"1021374562682":1478686417104,"1012158391936":1478686417223,"1024322810315":1509788667508,"1021491092019":1478686417046,"1021965844044":1478686417056,"1025533479221":1509788624347,"1012647528898":1478686804024,"1021337863105":1478686417239,"1024341160143":1509788624196,"1024341160141":1509788624196,"1021831882338":1478686417134,"1004787154545":1480585069067,"1021668044707":1509788624817,"1021831882344":1478686417134,"476566284":1444487341748,"1022012242732":1478686417184,"1024341160166":1509788624196,"1024341160165":1509788624196,"1021732269161":1478686417251,"1021887717932":1478686804044,"1021887717933":1478686804044,"1021668044613":1509788624534,"1021887717934":1478686804044,"1023738877179":1491634246528,"1021887717935":1478686804044,"1000038406531":1478686417021,"1021887717928":1478686804043,"1021887717929":1478686804044,"1021887717930":1478686804044,"1024144686255":1509788667472,"1021887717931":1478686804044,"1002626203203":1491634246534,"1538888753":1444487341703,"1024341159963":1509788624196,"1024263566779":1509788624327,"1024341159962":1509788624196,"1024780359372":1509788625004,"1013058834531":1478686417074,"1021887717927":1478686804043,"1024780359368":1509788625004,"1021944479681":1478686417144,"1024008889550":1509788667493,"1021887717944":1478686804044,"1021887717945":1478686804044,"1021887717946":1478686804044,"961935043":1509788625020,"1021887717940":1478686804044,"1021887717941":1478686804044,"1022065719466":1478686417175,"1021887717942":1478686804044,"1021887717943":1478686804044,"1021887717936":1478686804044,"1021887717937":1478686804044,"1021887717938":1478686804044,"1021887717939":1478686804044,"1022418994085":1478686417302,"1009883410162":1478686804052,"1024633823142":1509788624299,"1020294152448":1465470268293,"1025407021123":1509788624208,"1021607089091":1509788624369,"4968540041":1509788624159,"1022386881600":1478686417290,"1024458705187":1509788624437,"1021329212585":1478686417041,"1710336582":1444487341741,"1021668044667":1509788624195,"1000977449422":1478686417021,"1024615727350":1509788624860,"1012145285026":1478950494940,"1024615727357":1509788624860,"1024615727356":1509788624860,"1024615727353":1509788624860,"1024341160030":1509788624196,"1024615727355":1509788624860,"1021374562697":1478686417104,"1024341160028":1509788624196,"1022020368917":1478686417266,"1024780359316":1509788625004,"1022451237355":1478686417215,"1024780359313":1509788625004,"1227982564":1478950494921,"1024780359327":1509788625004,"1023092718118":1509788625047,"1010025358598":1491634246521,"1018888582478":1509788624283,"1024780359322":1509788625004,"1024469321775":1509788624522,"1025861162265":1509788667470,"1021848266219":1480585069071,"1024786781442":1509788624241,"1025861162264":1509788667470,"1025861162266":1509788667470,"1021492271780":1478686417046,"1020925279465":1478686417000,"1024462375344":1509788625150,"1024780359343":1509788625004,"1022028757679":1478686417267,"1015696831288":1478686804063,"1025407021060":1509788624208,"1020984916076":1478686804043,"1024780359349":1509788625004,"1020984916077":1478686804043,"1020984916078":1478686804043,"1024462375339":1509788625149,"1020984916079":1478686804043,"1024780359350":1509788625004,"1022112773554":1478686416974,"1024462375341":1509788625150,"1022112773555":1478686416974,"4969981903":1509788624159,"1020940221404":1478686417084,"1020984916074":1478686804043,"1024462375343":1509788625150,"1020984916075":1478686804043,"1024780359346":1509788625004,"1024462375342":1509788625150,"1024780359357":1509788625004,"1024780359359":1509788625004,"1018988171131":1509788624316,"1015393920288":1478686804053,"1024780359355":1509788625004,"1022194036590":1478686417064,"1022194036591":1478686417064,"1021084659087":1509788624975,"1025407021039":1509788624228,"1025407021030":1509788624270,"1025407021028":1509788624270,"1025407021049":1509788624215,"1028517210":1478686417020,"1025407021043":1509788624228,"1024341159818":1509788624196,"1024341159817":1509788624196,"1025407021041":1509788624228,"1021692162411":1478686417300,"1025890913068":1509788667456,"1010002688022":1491634246524,"1018923445336":1509788624302,"1025007122404":1509788667497,"1025530730157":1509788625022,"1021161443635":1478686417038,"1021084659107":1509788624975,"1024341159869":1509788624197,"1024341159868":1509788624197,"1011593729908":1478686417220,"1019126716531":1509788624932,"1024341159846":1509788624196,"1024341159845":1509788624196,"1021907386044":1509788624465,"1223792846":1444487341739,"1024341159898":1509788624196,"1022367357299":1478686417204,"1024341159897":1509788624196,"1022094551337":1478686417181,"1021283867129":1465469681396,"1022461337542":1478686417298,"866640893":1478950494918,"1022052083644":1509788625066,"1021084659153":1509788624975,"1025407020939":1509788624546,"1025407020943":1509788624546,"1025407020942":1509788624546,"1025407020929":1509788624552,"1025407020935":1509788624546,"1021084659170":1509788624975,"1024341159907":1509788624196,"1021084659198":1509788624975,"1025407020953":1509788624546,"1024341159908":1509788624196,"1021052021735":1478686417093,"1025890913096":1509788667456,"1025407020951":1509788624546,"1083412498":1444487341747,"1022037403201":1509788624899,"1025407020911":1509788624611,"1022037403204":1509788624899,"187685802":1444487341703,"1022646930153":1480585069151,"4974835715":1509788624160,"1025407020908":1509788624613,"1022037403207":1509788624899,"1022646930151":1480585069151,"1022037403208":1509788624899,"1022035961459":1478686417167,"1022646930148":1480585069151,"1022037403211":1509788624899,"1022646930147":1480585069151,"1022646930146":1480585069151,"1022646930145":1480585069151,"1021742626022":1478686417253,"1025407020923":1509788624565,"1022208364578":1478686804046,"1022037403217":1509788624899,"1022037403219":1509788624899,"1022646930169":1480585069151,"1022646930168":1480585069151,"1022646930167":1480585069151,"1022037403224":1509788624899,"1022037403225":1509788624899,"1022037403226":1509788624899,"1025407020919":1509788624565,"1021854563125":1509788624394,"1025407020916":1509788624565,"1025407020865":1509788625132,"1025407020864":1509788625132,"1022247555824":1478686417284,"1016882074296":1478686804063,"1022518215297":1509788625075,"1020962235966":1478686417000,"1022079871132":1478686417178,"4879020555":1509788624161,"1021881564360":1478686417137,"1024341159771":1509788624196,"1024341159770":1509788624196,"1021602892896":1478686804046,"1025524962856":1509788667890,"1022079871124":1478686417178,"1009848930196":1491634246514,"1025407020859":1509788625133,"1025407020858":1509788625133,"1025407020857":1509788625133,"1025407020863":1509788625132,"1025407020861":1509788625133,"1022079871119":1478686417178,"1025407020850":1509788625144,"1022037403163":1509788624899,"1019718384578":1478686804039,"1022079871109":1478686417178,"1021736072199":1509788624395,"1022037403165":1509788624899,"1021668044837":1509788624420,"1021344160978":1478686417005,"1022037403172":1509788624899,"1021084659051":1509788624975,"1022037403175":1509788624899,"1022037403176":1509788624899,"1013029997897":1478686804066,"1022037403177":1509788624899,"1024192915104":1509788625071,"1024615735260":1509788625159,"1022037403179":1509788624899,"1024615735257":1509788625159,"1024615735256":1509788625159,"1024341159805":1509788624272,"1024615735259":1509788625159,"1021900570119":1478686417139,"1024341159804":1509788624272,"1024615735258":1509788625159,"1084854361":1444487341718,"1223792640":1444487341740,"1025577523504":1509788624343,"1022079871148":1478686417178,"1022037403188":1509788624899,"1025407020831":1509788625244,"1022037403189":1509788624899,"1025407020828":1509788625246,"1022037403193":1509788624899,"1022037403199":1509788624899,"1022646930287":1480585069152,"1025216700995":1509788667495,"1022646930286":1480585069152,"1025216700994":1509788667495,"1022646930285":1480585069151,"1022646930284":1480585069151,"1024938963698":1509788625202,"1025216700992":1509788667495,"1021455041180":1509788624817,"1025216700997":1509788667495,"1020969314153":1478686804039,"1024283356642":1509788624960,"1025216700996":1509788667495,"1022646930277":1480585069151,"1022646930272":1480585069151,"1018559723294":1478686804015,"1022646930301":1480585069152,"1022646930299":1480585069152,"1024938963685":1509788625201,"1024938963684":1509788625201,"1022646930297":1480585069152,"1024938963687":1509788625201,"1024938963686":1509788625201,"1022646930295":1480585069152,"1024938963689":1509788625201,"1022646930294":1480585069152,"1024938963691":1509788625201,"1024938963690":1509788625201,"1024938963693":1509788625201,"1022646930290":1480585069152,"1024938963692":1509788625201,"1024938963694":1509788625201,"1024938963671":1509788625202,"1024938963670":1509788625201,"1020949128331":1478686417085,"1024938963672":1509788625202,"1022297887863":1478686417068,"1022646930245":1480585069151,"1024938963675":1509788625201,"1022457798398":1478686416977,"1022065714716":1478686417271,"1016947873553":1478686804053,"1024938963677":1509788625201,"1021993493071":1478686417156,"1022238774254":1509788624931,"1022238774253":1509788624941,"1024938963679":1509788625201,"1022238774252":1509788624947,"1024938963648":1509788624252,"1024938963650":1509788624252,"1024461330298":1509788624556,"1025512641673":1509788624341,"1024461330288":1509788624556,"1024461330293":1509788624556,"1024461330295":1509788624556,"1024461330294":1509788624556,"367641769":1444487341750,"1021283866863":1465469681396,"1022646930222":1480585069151,"1019717597771":1509788625078,"1022646930221":1480585069151,"1019717597768":1509788625078,"1022646930220":1480585069151,"1025445007588":1509788624369,"1022646930216":1480585069151,"1024938963638":1509788624252,"1019717597773":1509788625078,"1024938963640":1509788624252,"1022646930213":1480585069151,"1024938963643":1509788624252,"1022646930211":1480585069151,"1024938963644":1509788624252,"1022284780875":1478686417067,"1022646930209":1480585069151,"1024938963647":1509788624252,"1024938963646":1509788624252,"1024938963619":1509788624253,"1024938963621":1509788624252,"1022646930234":1480585069151,"1025284597250":1509788624946,"1024938963623":1509788624252,"1025126924266":1509788624306,"1020294029302":1465470268282,"1016159487591":1478686804031,"1024938963625":1509788624252,"1019717597779":1509788625078,"1022646930229":1480585069151,"1024938963629":1509788624252,"1024938963628":1509788624252,"1022646930225":1480585069151,"1024938963631":1509788624252,"1025906511173":1509788667464,"1025906511181":1509788667462,"1024938963611":1509788624252,"1022646930180":1480585069151,"1024938963613":1509788624253,"1025906511179":1509788667458,"1013631668388":1480585069072,"1022435253373":1478686417071,"1021550594229":1478686804071,"1022646930206":1480585069151,"1021550594230":1478686804071,"1022827427039":1509788625054,"1021550594231":1478686804071,"1025909132654":1509788667458,"1025909132651":1509788667464,"1021550594236":1478686804071,"1025216700987":1509788667495,"1021550594237":1478686804071,"1021550594238":1478686804071,"1024442323985":1509788624926,"1021550594232":1478686804071,"1021550594233":1478686804071,"1021550594234":1478686804071,"4974836218":1509788624161,"1021550594235":1478686804071,"1020925272718":1478686417033,"1025890912944":1509788667456,"1007972482741":1478686804025,"1006088089319":1509788624369,"1013029997618":1478686804066,"1024938963557":1509788624588,"1023143045480":1509788625046,"1024938963559":1509788624588,"1024938963558":1509788624588,"1025890912932":1509788667455,"1024938963561":1509788624588,"1024938963560":1509788624588,"1024938963563":1509788624588,"1024938963565":1509788624588,"1022816286187":1509788625055,"1025890912943":1509788667456,"1025890912942":1509788667455,"1025890912941":1509788667456,"1022646930383":1480585069084,"1018271876343":1509788624354,"1022646930380":1480585069084,"1024938963541":1509788624588,"1024938963542":1509788624588,"1024938963545":1509788624588,"1022646930374":1480585069084,"1024938963547":1509788624588,"1024273787451":1509788624327,"1024938963549":1509788624588,"1022770016404":1509788624267,"1024938963548":1509788624588,"1022646930369":1480585069084,"1024938963550":1509788624588,"4995151883":1509788667396,"1025890912903":1509788667455,"1025890912901":1509788667455,"1021895589102":1509788624465,"1024055951145":1509788624969,"1024938963533":1509788624588,"1022646930351":1480585069084,"1025732051790":1509788624942,"1024002734713":1491634246532,"1022215836145":1478686417192,"1022215836144":1478686417192,"1022215836146":1478686417192,"1022646930364":1480585069084,"1022215836149":1478686417192,"1022646930362":1480585069084,"1022646930361":1480585069084,"1022646930360":1480585069084,"1022646930359":1480585069084,"1023364928635":1509788625163,"1023364928634":1509788625163,"1022646930357":1480585069084,"1023364928633":1509788625163,"1023364928639":1509788625163,"1020990678777":1478686417230,"1022646930354":1480585069084,"1010024708895":1491634246521,"1023364928636":1509788625163,"1022270625044":1478686417067,"1024938963484":1509788624588,"1022646930304":1480585069152,"1024938963464":1509788624588,"1025647124411":1509788624364,"1021037471871":1465470268183,"1025647124410":1509788624364,"1021177303046":1478686417234,"1025647124409":1509788624364,"1015902722666":1480585069075,"1025647124408":1509788624364,"1025647124415":1509788624364,"1025647124414":1509788624364,"1025647124413":1509788624364,"1015902722670":1480585069075,"1025647124412":1509788624364,"1015902722658":1480585069069,"1015902722660":1480585069063,"1015902722662":1480585069063,"1021052021129":1478686417093,"1015902722673":1480585069069,"1015902722674":1480585069075,"1015902722677":1480585069063,"1020241205741":1478686804039,"1024055950476":1509788624969,"1021471164067":1478686417242,"1023569396656":1509788624516,"1021471164068":1478686417242,"1015902722636":1480585069062,"1025606883369":1509788625083,"816046735":1444487341725,"1021440491611":1478686417107,"1015902722648":1480585069075,"1015902722650":1480585069069,"1022628580276":1509788624462,"1024938963396":1509788624891,"1334681018":1491634246519,"1015902722643":1480585069075,"1021828086628":1509788624940,"1015902722644":1480585069075,"1015902722646":1480585069075,"1024938963378":1509788624891,"1022438268091":1478686417071,"1025439765074":1509788624293,"1024938963380":1509788624891,"1020581072372":1478686417027,"1024938963382":1509788624891,"1024938963387":1509788624891,"1020437283950":1480585069097,"1025439765080":1509788624293,"1022065059182":1478686417174,"1022519263322":1509788624507,"1024938963365":1509788624891,"1801304331":1444487341729,"1021501703300":1478686804022,"1024938963369":1509788624891,"1024938963371":1509788624891,"1023765614490":1509788624958,"726006043":1478686417023,"1024938963351":1509788624891,"1024577593108":1509788624925,"1021471164144":1478686417242,"1025647124427":1509788624364,"1025647124426":1509788624364,"1025647124425":1509788624364,"1021471164147":1478686417242,"1025647124424":1509788624364,"1022069648000":1478686417271,"1024938963332":1509788624891,"1024938963335":1509788624891,"1025647124419":1509788624364,"1025647124418":1509788624364,"1025647124417":1509788624364,"1024938963339":1509788624891,"1025647124416":1509788624364,"1022452817018":1509788624525,"1025647124423":1509788624364,"1025647124422":1509788624364,"1025647124421":1509788624364,"1025647124420":1509788624364,"1022519263371":1509788624441,"1024938963312":1509788624891,"1024938963316":1509788624891,"1024938963319":1509788624891,"1022402615704":1478686417207,"1024127115481":1509788624363,"1024938963325":1509788624891,"1001351804751":1444487341700,"1019934386856":1478686804015,"1018335710194":1478686804065,"1019934386857":1478686804015,"1018335710195":1478686804065,"1019934386854":1478686804015,"1019934386855":1478686804015,"1024938963307":1509788624891,"1025533482239":1509788624325,"1022455307612":1478686417216,"1018088511625":1478686804053,"1014129478804":1478686804019,"1021618884474":1478686804057,"1021618884475":1478686804057,"1021618884472":1478686804057,"1021618884473":1478686804057,"1850719476":1444487341717,"1010057346636":1491634246534,"1019963877573":1478686804021,"1021626355584":1478686417117,"1021626355587":1478686417117,"1021626355589":1478686417119,"1020391540279":1478686804071,"1025042381681":1509788624254,"1012918322325":1478686417074,"1021618884360":1478686804069,"1022052345116":1478686417172,"1025445008195":1509788624369,"1021928750518":1509788624974,"1021928750516":1509788624974,"1021928750517":1509788624974,"1021928750514":1509788624974,"1021618884408":1478686804069,"1021928750512":1509788624974,"1021928750513":1509788624974,"1021928750511":1509788624974,"1023751720519":1509788624281,"1021928750508":1509788624974,"1021983924451":1509788624536,"1021928750509":1509788624974,"1021928750507":1509788624974,"1021597256161":1509788624405,"1022543251381":1509788625063,"1020977964259":1478686417087,"1024576675427":1509788624462,"1021514286338":1509788624405,"1021471426447":1478686417045,"1025592859094":1509788624352,"1021952991969":1478686417146,"1024895316824":1509788624439,"1021729517578":1509788624919,"1019860068284":1509788625079,"1020437415194":1478686804027,"1010002688777":1491634246524,"1021599354817":1478686417115,"1021964001821":1478686417148,"1024781797999":1509788625024,"1018330073746":1478686804053,"1016620474605":1478686804063,"1018330073744":1478686804053,"1018330073745":1478686804053,"1016620474606":1478686804063,"1022050379084":1478686417172,"1021694915197":1480585069064,"1000490607196":1444487341712,"1004588316048":1444487341763,"1021601320859":1478686804065,"1022257123569":1478686417067,"1024688211868":1509788624492,"1021618884278":1478686804069,"1021709332755":1509788624918,"1016231186327":1478686804017,"1024055950833":1509788624969,"1022092192500":1509788625020,"4995152594":1509788667396,"1012124054730":1478686417073,"1024782453326":1509788625019,"1024782453322":1509788625021,"1021876322055":1478686417136,"927327295":1478950494918,"398836804":1478686804029,"1022461991959":1509788624243,"1022461991958":1509788624243,"1022461991953":1509788624243,"1022461991952":1509788624243,"1024886928238":1509788624571,"1022461991955":1509788624243,"1022461991954":1509788624242,"1022461991965":1509788624243,"1021471164169":1478686417242,"1022461991967":1509788624243,"1025445007917":1509788624369,"1024608001024":1509788667590,"156883669":1478686417019,"1022461991961":1509788624243,"1022461991960":1509788624243,"1017337023841":1478686804065,"1022461991962":1509788624243,"1021084659228":1509788624975,"1022461991949":1509788624243,"1022461991948":1509788624242,"1022461991951":1509788624243,"1022491869707":1478943089254,"1801304304":1444487341736,"1022461991973":1509788624243,"1108578722":1491634246517,"1022461991972":1509788624243,"1022461991975":1509788624243,"1022461991974":1509788624242,"1022461991968":1509788624243,"1021084659259":1509788624975,"1022461991970":1509788624242,"1022461991977":1509788624243,"1021084659250":1509788624975,"1022461991976":1509788624243,"1025773733809":1509788624288,"1021084659278":1509788624975,"1021084659274":1509788624975,"1021983924694":1509788624552,"1021831625411":1478686417133,"1021084659268":1509788624975,"1021951418924":1478686417056,"1021698323157":1478686417250,"1025485770888":1509788625135,"1018330073612":1478686804053,"1018330073610":1478686804053,"1018330073611":1478686804053,"1018330073609":1478686804053,"1020254443734":1509788625077,"1025485770887":1509788625135,"1020294159735":1465470268294,"1025485770886":1509788625135,"1020294028623":1465470268281,"1016780124124":1478686804016,"1021960725136":1478686417056,"1025509234202":1509788624340,"1025509234206":1509788624344,"1025911492116":1509788667404,"519949587":1478686417017,"1022021281332":1509788624463,"810673060":1444487341742,"1022090619457":1478686417062,"1024678510721":1509788625025,"1026226601158":1514456869770,"1021881040840":1478686417053,"1021425026368":1509788624978,"1021425026369":1509788624978,"1021425026371":1509788624978,"1021425026372":1509788624978,"1021425026373":1509788624978,"1021981566514":1478686417151,"1021425026375":1509788624978,"1025902446699":1509788667444,"1022215836712":1478686417192,"1022107004599":1478686417275,"1025902446698":1509788667442,"1021425026381":1509788624978,"1022107004592":1478686417275,"1021425026382":1509788624978,"1021425026383":1509788624978,"1025902446700":1509788667443,"1020117342023":1465470268310,"1025313041821":1509788624385,"1025313041820":1509788624385,"1023364927930":1509788624450,"1025313041823":1509788624385,"1025313041822":1509788624385,"1009571191767":1478686804030,"1023364927934":1509788624450,"1025313041819":1509788624385,"1023364927933":1509788624450,"1025313041818":1509788624385,"1023364927932":1509788624450,"1848097287":1444487341725,"1025313041825":1509788624385,"1025313041824":1509788624385,"1025313041837":1509788624385,"1025313041836":1509788624385,"1025313041838":1509788624385,"1022044873311":1478686417171,"1025313041835":1509788624385,"1025313041845":1509788624385,"1022329606984":1478686417201,"1025313041844":1509788624385,"1025313041847":1509788624385,"1004588315387":1444487341762,"1025313041846":1509788624385,"1025313041841":1509788624385,"1025313041840":1509788624385,"1025313041843":1509788624385,"1025313041842":1509788624385,"1025313041848":1509788624385,"1021975668397":1478686417150,"1025732052660":1509788624942,"1021786796945":1509788624395,"1009965855243":1491634246523,"1022700931359":1509788624973,"1021765038417":1478686417127,"1022238906001":1509788624932,"1022238906000":1509788624946,"1022238906002":1509788624933,"1022238906004":1509788624941,"1003492175988":1478686417220,"1022827819461":1509788624825,"1022850626088":1509788625080,"1022219769217":1478686417281,"1023364927943":1509788624450,"1017364548396":1480585069151,"1021514810240":1478686417112,"1020073956772":1465470268309,"1000920440580":1478686417220,"1022850626086":1509788625078,"1013029997006":1478686804066,"1023890141210":1491634246506,"1086690485":1480585069071,"1021514810265":1478686417112,"1021514810270":1478686417112,"1013644645754":1458304307281,"1013644645759":1458304307281,"1021425026366":1509788624978,"1013644645758":1458304307281,"1021425026367":1509788624978,"1013644645762":1458304307281,"1020979798858":1478686417087,"1025890914229":1509788667456,"1025050901922":1509788624232,"1012124054314":1478686417073,"1018898018169":1509788624367,"1025445008701":1509788624369,"1084855351":1444487341718,"1020657629090":1478686804043,"1020657629091":1478686804043,"1020657629089":1478686804043,"1020657629094":1478686804043,"1020657629092":1478686804043,"1020657629093":1478686804043,"1024107587031":1509788625036,"1020052745123":1509788624280,"1019596484850":1509788624298,"1022156941594":1478686417013,"1017337023059":1478686804065,"1020657629119":1478686804065,"4998823245":1509788667397,"1543866568":1491634246505,"1023020885244":1509788624382,"1023020885243":1509788624382,"1023413165098":1509788624386,"1022029406644":1478686417165,"1020294027842":1465470268281,"1023413165101":1509788624292,"1013043104268":1478686804066,"1020117342126":1465470268311,"4995153216":1509788667397,"1021603678274":1478686417115,"1021888247972":1478686417054,"1021888247975":1478686417054,"1024341158555":1509788624536,"1022199278135":1478686417189,"1021888247976":1478686417054,"1024341158556":1509788624536,"1020160988072":1465470268316,"1024341158537":1509788624536,"1022922063634":1509788624926,"1024341158541":1509788624536,"1008644325929":1478686804030,"1024341158577":1509788624518,"1024794382155":1509788624237,"1022306931700":1478686417199,"1021988120314":1478686417264,"1024794382147":1509788624237,"1024183083987":1509788624923,"1022185253693":1478686417064,"1024183083981":1509788624923,"1020073956604":1465470268309,"1018867084524":1509788625077,"1018867084525":1509788625078,"1022478894501":1478943089487,"1024183083977":1509788624923,"1024183083969":1509788624923,"1021599353276":1478686417115,"1024794382127":1509788624237,"1024341158610":1509788624536,"1024183083966":1509788624923,"1020911773370":1478686416975,"1024341158609":1509788624536,"1274781368":1480585069071,"1024183083958":1509788624923,"1024183083955":1509788624923,"1024183083952":1509788624923,"1024794382143":1509788624237,"1021599353263":1478686417115,"1024794382138":1509788624237,"1024794382135":1509788624237,"1021272857903":1478686417101,"1023020885375":1509788624382,"1024794382132":1509788624237,"1024794382128":1509788624237,"1020824352850":1509788624945,"1021420963046":1478686417106,"1024316123253":1509788625016,"1012512418813":1444487341761,"1021599353243":1478686417115,"1021599353235":1478686417115,"1024341158633":1509788624536,"1024341158632":1509788624536,"1025407019627":1509788624546,"1019940023366":1509788624393,"1025407019630":1509788624546,"137092515":1444487341743,"1025407019617":1509788624546,"1008538813694":1478686804030,"1025407019622":1509788624546,"1024116631396":1509788624215,"1024341158402":1509788624518,"137092541":1444487341752,"1025890913961":1509788667456,"1025407019637":1509788624566,"1025407019595":1509788624611,"1022155892848":1509788624959,"1025407019593":1509788624613,"1025407019599":1509788624565,"1020776513088":1478686417076,"1024341158434":1509788624518,"1021956137996":1509788624464,"1025407019603":1509788624539,"451923793":1491634246504,"1025407019604":1509788624552,"1024341158483":1509788624535,"4998822964":1509788667397,"1013631669251":1480585069072,"1024341158488":1509788624536,"1021958628441":1478686417147,"1024341158466":1509788624536,"1023020885495":1509788624379,"1009007802544":1509788624368,"1024341158468":1509788624536,"1022700669063":1509788624973,"137092598":1444487341752,"1023020885496":1509788624379,"4980210998":1509788624161,"1022147373492":1478686417277,"1024055950198":1509788624969,"1025732052832":1509788624942,"1009250412829":1478686804055,"1009250412828":1478686804054,"836494369":1491634246515,"1022248212398":1478686417066,"1024341158290":1509788624536,"1025417898308":1509788667581,"1025890913585":1509788667456,"1024341158288":1509788624536,"1023162576852":1509788624977,"1020553939766":1478686417026,"1023162576841":1509788624977,"1023162576845":1509788624977,"1021439706239":1478686417107,"1021951682524":1478686417146,"1025407019467":1509788624208,"1024341158323":1509788624536,"1021727159648":1478686417123,"1025407019465":1509788624208,"187686152":1444487341704,"1024341158324":1509788624536,"1025407019459":1509788624208,"1023364928395":1509788624564,"1024107587415":1509788625036,"1023364928394":1509788624564,"1025732052130":1509788624942,"1025407019457":1509788624208,"1023364928393":1509788624564,"1023364928392":1509788624564,"1025407019462":1509788624208,"1023364928396":1509788624564,"1025890913537":1509788667456,"1021880908291":1478686417137,"1022311387224":1478686417302,"1024134325759":1509788625036,"1022311387221":1478686417302,"1022311387219":1478686417287,"1022311387217":1478686417302,"1022311387216":1478686417302,"1021681284698":1478686417120,"1006559006009":1480585069065,"1025407019439":1509788624228,"1025407019438":1509788624228,"1025407019436":1509788624270,"1024341158367":1509788624535,"1024341158366":1509788624535,"1025407019429":1509788624270,"1022325150184":1478686417288,"1025407019453":1509788624208,"1020073957279":1465470268310,"1025407019443":1509788624228,"1022490691459":1478943089490,"1025407019445":1509788624199,"1005501008397":1478686804061,"1023162576819":1509788624977,"1025445009350":1509788624368,"1005501008399":1478686804061,"1020928156294":1478686417228,"1005501008392":1478686804061,"1005501008395":1478686804061,"1005501008394":1478686804061,"1019724544724":1509788625077,"1019724544725":1509788625076,"1005501008390":1478686804061,"1016301582028":1480585069066,"1025883835891":1509788667402,"1019724544722":1509788625077,"1023162576828":1509788624977,"1021464216222":1478686417108,"1005501008412":1478686804061,"1021464216221":1478686417108,"1005501008409":1478686804061,"1019724544712":1509788624354,"1005501008408":1478686804061,"1018271875875":1509788624286,"1005501008411":1478686804061,"1005501008404":1478686804061,"1019724544709":1509788625077,"758643533":1444487341748,"1005501008406":1478686804061,"1005501008401":1478686804061,"1024341158383":1509788624536,"1021596601719":1478686416987,"1024341158382":1509788624536,"516540490":1478686804033,"1022030848928":1509788624466,"1025732051969":1509788624942,"1156420192":1444487341721,"1024341158147":1509788624536,"1024341158146":1509788624536,"1022208366113":1478686804041,"1021791908341":1478686417009,"1022208366112":1478686804041,"1024055949321":1509788624928,"1021592931813":1478686416972,"1022208366107":1478686804040,"1024341158203":1509788624536,"1025628772987":1509788625022,"1022208366106":1478686804040,"1022208366111":1478686804040,"1019889295458":1509788625080,"1022208366110":1478686804040,"1022208366109":1478686804040,"1022208366108":1478686804040,"1024341158204":1509788624536,"1022435646397":1478686417294,"1024912095190":1509788624926,"1025792476113":1509788624418,"1025792476112":1509788624418,"1025796800621":1509788624616,"1025792476114":1509788624418,"1025796800617":1509788624822,"4998823733":1509788667393,"1025796800615":1509788624827,"1022459763070":1478686417217,"1022260925791":1478686417014,"1025792476107":1509788624418,"1024967406308":1509788624937,"1025792476109":1509788624418,"1025792476108":1509788624418,"1023328359727":1509788624254,"1025792476111":1509788624418,"1021075483365":1465470268250,"1025792476110":1509788624418,"1004588314664":1444487341763,"1019272595311":1478686804021,"1021465264662":1478686417300,"1022367358930":1478686417204,"1024341158245":1509788625136,"1014713128838":1480585069072,"1021888248670":1478686417054,"516540468":1478686804033,"1024936211686":1509788625006,"1021757829736":1478686417127,"1014803304726":1478686804051,"1021757829735":1478686417127,"1014803304728":1478686804051,"1025513689734":1509788624507,"1021757829732":1478686417127,"1014803304730":1478686804051,"1021723227285":1509788624403,"1025513689732":1509788624507,"1025513689731":1509788624441,"1014803304732":1478686804051,"1025513689730":1509788624441,"1014803304735":1478686804051,"1025513689729":1509788624423,"1014803304734":1478686804051,"1023364928179":1509788624225,"1023364928178":1509788624225,"1023364928181":1509788624225,"1023364928180":1509788624225,"1011593728092":1478686417220,"150855652":1444487341751,"1023364928185":1509788624225,"1021602892682":1478686804046,"1725673976":1444487341705,"1021103925580":1478686417095,"1024341158075":1509788624536,"1024341158074":1509788624536,"1021606431673":1509788624815,"1025445009032":1509788624369,"1014803304737":1478686804051,"1022204303297":1509788624920,"1022204303296":1509788624920,"1014803304739":1478686804051,"1021716149464":1509788624557,"1022204303299":1509788624920,"1021716149465":1509788624557,"1022204303301":1509788624920,"1022600921113":1509788625062,"1021716149468":1509788624557,"1022204303303":1509788624920,"1022204303302":1509788624920,"1021723227299":1509788624395,"1021716149463":1509788624557,"1021758091860":1509788624395,"1019767535948":1509788624316,"1210031965":1444487341725,"1022204303284":1509788624920,"1022204303287":1509788624920,"1024341158100":1509788624535,"1022204303286":1509788624920,"1022204303289":1509788624920,"1024341158105":1509788624535,"1022204303291":1509788624920,"1022204303290":1509788624920,"1021032885740":1478686417091,"1022204303292":1509788624920,"1022204303295":1509788624920,"1022204303294":1509788624920,"1022328164413":1478686417015,"1025732052447":1509788624942,"1013631669905":1480585069072,"1024341158128":1509788624536,"1024341158132":1509788624536,"1020073957024":1465470268309,"1024794381807":1509788624470,"1024794381806":1509788624470,"1024794381804":1509788624470,"1024794381802":1509788624470,"1025069383041":1509788667497,"1024794381796":1509788624470,"1024794381795":1509788624470,"4980211526":1509788624157,"1024341157894":1509788624615,"1024341157897":1509788624615,"1210032000":1444487341740,"1024794381808":1509788624470,"1021567896956":1509788624456,"1024055949616":1509788624928,"1006548913587":1478686804028,"1021653485580":1478686417120,"4968546191":1509788624157,"1023186955764":1509788625080,"1022253061191":1478686417284,"1022253061190":1478686417284,"1024794381789":1509788624470,"1019767929278":1509788625077,"1024985494206":1509788624279,"1019767929276":1509788625077,"1021500129654":1478686417007,"1025890913521":1509788667456,"1019767929289":1509788625078,"1019767929294":1509788624354,"1009230491124":1478686804030,"1024540630082":1509788667549,"1024341157962":1509788624536,"1025890913519":1509788667456,"1020294158709":1465470268294,"1025890913518":1509788667455,"1025732052309":1509788624942,"1025890913517":1509788667456,"1024341157964":1509788624536,"1025890913516":1509788667456,"1022432107199":1478686417212,"1025042382405":1509788624498,"1021997688006":1478686417156,"1021989430362":1478686417057,"1024341158005":1509788624518,"1020835887502":1478686416998,"1023364928079":1509788624862,"1022489904699":1478943089254,"1023364928083":1509788624862,"1018236093573":1478686804046,"1024341157986":1509788624536,"1023364928082":1509788624862,"1021242053082":1478686417100,"1025513689725":1509788624466,"1025513689724":1509788624466,"1024341157984":1509788624536,"1024688210736":1509788625213,"1023364928085":1509788624862,"1025513689720":1509788624511,"1023364928084":1509788624862,"168943080":1444487341755,"1014713128584":1480585069072,"1025513689715":1509788624511,"1022416247763":1509788625016,"1025630344379":1509788624293,"1871165318":1444487341718,"1025630344377":1509788624293,"1025630344376":1509788624293,"1025630344383":1509788624293,"1000456271674":1478686804064,"1004342415255":1444487341756,"1025069380101":1509788667497,"1002035713282":1478686417023,"1871165332":1444487341749,"1021847745063":1509788624446,"1021847745066":1509788624446,"1021847745064":1509788624446,"1021847745065":1509788624446,"1022759008737":1509788625056,"1025907295257":1509788667465,"1022646927948":1480585069148,"1025907295258":1509788667462,"1022002539729":1478686417157,"1021274951792":1478686417101,"1021274951793":1478686417101,"1022646927944":1480585069148,"1022169786068":1478686417186,"1025295736997":1509788624945,"1022646927940":1480585069148,"1012084735030":1478686804069,"1025689065218":1509788624335,"1022472210626":1480585069122,"1024055948974":1509788624928,"1022472210617":1480585069122,"1022472210616":1480585069122,"1022646927918":1480585069148,"1023820806358":1491634246535,"1022472210619":1480585069122,"1022472210618":1480585069122,"1022646927916":1480585069148,"1022472210621":1480585069122,"1022472210620":1480585069122,"1022646927912":1480585069148,"1022472210609":1480585069122,"1022472210608":1480585069122,"1009043715857":1478686804030,"1022472210611":1480585069122,"1022646927909":1480585069148,"1022472210610":1480585069122,"1022472210613":1480585069122,"1022472210612":1480585069122,"1022472210615":1480585069122,"1021390427967":1478686417042,"1022472210614":1480585069122,"1022646927904":1480585069148,"1022646927935":1480585069148,"1022472210600":1480585069122,"1022472210603":1480585069122,"1022472210602":1480585069122,"1022472210605":1480585069122,"1022472210604":1480585069122,"1022472210607":1480585069122,"1022646927929":1480585069148,"1022472210606":1480585069122,"1022646927925":1480585069148,"1022472210594":1480585069121,"1022472210597":1480585069121,"1024938310566":1509788667503,"1022472210599":1480585069122,"1022646927921":1480585069148,"1019596225560":1509788624946,"1022472210598":1480585069121,"1022472210585":1480585069121,"1021847745105":1509788624220,"1022646927883":1480585069148,"1024341157878":1509788624535,"1024341157877":1509788624535,"1022472210590":1480585069121,"1022646927879":1480585069148,"1022046187060":1478686804027,"1022646927876":1480585069148,"1022646927873":1480585069148,"1022051823508":1478686417269,"1017286689694":1509788624928,"1020944805266":1478686417000,"1022015253571":1478686417160,"1021961644338":1478686417262,"1022646927897":1480585069148,"1021847745098":1509788624220,"1019612609841":1509788625079,"1022646927893":1480585069148,"1016301713629":1480585069066,"1021847745102":1509788624220,"1022957057135":1509788624406,"1016301713628":1480585069066,"1022051823515":1478686417269,"1022646927888":1480585069148,"1021847745101":1509788624220,"1022956926101":1509788624446,"1023286810827":1509788624536,"1023485777134":1509788624586,"1022956926097":1509788624446,"1023485777131":1509788624586,"1022956926096":1509788624446,"1022435644801":1478686417294,"1023485777128":1509788624586,"1023485777127":1509788624586,"1023924616911":1509788624961,"1023485777125":1509788624586,"1023485777123":1509788624586,"1022051823467":1478686417269,"1022051823476":1478686417269,"1022051823478":1478686417269,"1022051823473":1478686417269,"1023485777145":1509788624586,"1018490124999":1478686804066,"1022543252522":1509788625075,"1022956926092":1509788624446,"1022956926095":1509788624446,"1023485777139":1509788624586,"1021119915828":1478686417233,"1022646928073":1480585069149,"1021270102070":1478686804027,"1022460155678":1478686417298,"1023485777118":1509788624586,"1022461990689":1509788624586,"1021921802001":1509788624466,"1022646928085":1480585069149,"1023485777109":1509788624586,"1022699357684":1509788624399,"1023485777108":1509788624586,"1021581525840":1509788624397,"1023485777107":1509788624586,"1022646928081":1480585069149,"1022646928046":1480585069149,"1022646928043":1480585069148,"1021254246231":1478686417237,"1022646928041":1480585069148,"1022646928037":1480585069148,"4941413965":1509788624157,"1021847745278":1509788624557,"1021847745279":1509788624557,"1021847745277":1509788624557,"1023994999524":1491634246532,"1022646928060":1480585069149,"1022469461975":1478686417073,"1022646928058":1480585069149,"1023994999522":1491634246532,"658898845":1444487341699,"1022646928055":1480585069149,"1022982747827":1509788624175,"1025593250345":1509788624931,"1022646928050":1480585069149,"1022646928049":1480585069149,"1879029533":1478686804029,"1022646928013":1480585069148,"1022646928011":1480585069148,"1022646928009":1480585069148,"1724497454":1444487341723,"1022646928008":1480585069148,"1022646928004":1480585069148,"1022646928001":1480585069148,"1022646928031":1480585069148,"1022646928029":1480585069148,"1022646928025":1480585069148,"1022646928017":1480585069148,"1022472210937":1480585069124,"1022646928239":1480585069149,"1022472210936":1480585069124,"1022472210939":1480585069124,"1022646928237":1480585069149,"1023485777260":1509788624905,"1021550592192":1478686804029,"1022472210941":1480585069124,"1022472210940":1480585069124,"1023485777258":1509788624905,"1022472210943":1480585069124,"1022646928233":1480585069149,"1022472210942":1480585069124,"1025445009583":1509788624369,"1022472210928":1480585069124,"1023485777254":1509788624905,"1022472210931":1480585069124,"1022646928229":1480585069149,"1022472210930":1480585069124,"1022472210933":1480585069124,"1023485777249":1509788624905,"1022646928224":1480585069149,"1022646928253":1480585069149,"1023485777277":1509788624905,"1022472210922":1480585069124,"1022472210925":1480585069124,"1022472210924":1480585069124,"1023485777274":1509788624905,"1022472210927":1480585069124,"1022646928249":1480585069149,"1022472210926":1480585069124,"1022472210913":1480585069124,"1023485777271":1509788624905,"1022472210914":1480585069124,"1023485777268":1509788624905,"1022472210917":1480585069124,"1022472210919":1480585069124,"1023485777265":1509788624905,"1022472210918":1480585069124,"1022646928204":1480585069149,"1025295737259":1509788624945,"1022646928199":1480585069149,"1020657629741":1478686804050,"1015213033130":1480585069070,"1021567239162":1509788624861,"1023485777247":1509788624905,"1021567239163":1509788624861,"1021847745280":1509788624557,"1021567239160":1509788624861,"1021567239161":1509788624861,"1023485777244":1509788624905,"1023485777241":1509788624905,"1022646928216":1480585069149,"1012835879019":1478686417224,"1022472210883":1480585069124,"1022472210882":1480585069124,"1022646928209":1480585069149,"1022472210872":1480585069123,"1022472210875":1480585069123,"1022472210874":1480585069123,"1022646928172":1480585069149,"1022472210877":1480585069123,"1021921933026":1509788624465,"1022472210879":1480585069124,"1022472210865":1480585069123,"1022472210864":1480585069123,"1022646928166":1480585069149,"1022472210867":1480585069123,"1022472210866":1480585069123,"1022646928164":1480585069149,"1022472210868":1480585069123,"1023485777185":1509788624586,"1022472210870":1480585069123,"1022472210859":1480585069123,"1022472210861":1480585069123,"1022472210863":1480585069123,"1019956143012":1509788625076,"1022646928184":1480585069149,"1022472210849":1480585069123,"1022472210850":1480585069123,"1022472210855":1480585069123,"1022472210841":1480585069123,"1022472210840":1480585069123,"4980208055":1509788624162,"1025007386300":1509788667506,"4673228776":1478943089213,"1025007386303":1509788667506,"1022472210842":1480585069123,"1019956142993":1509788625077,"1025007386302":1509788667506,"1022472210845":1480585069123,"1023485777163":1509788624586,"1025007386297":1509788667506,"1025007386296":1509788667506,"1022472210847":1480585069123,"1022472210846":1480585069123,"1025007386298":1509788667506,"1025007386293":1509788667506,"1022472210832":1480585069123,"1025512905938":1509788624341,"1021994150430":1478686417156,"1022472210835":1480585069123,"1019956143001":1509788625076,"1025007386294":1509788667506,"1022472210839":1480585069123,"1023485777153":1509788624586,"1022472210838":1480585069123,"1008629649040":1478686804030,"1022472210816":1480585069123,"1023485777173":1509788624586,"1023485777170":1509788624586,"1083414802":1444487341742,"1019148997484":1509788625078,"1022472210810":1480585069123,"1022472210815":1480585069123,"1022472210801":1480585069123,"1020938251725":1478686417084,"1022472210800":1480585069123,"1022472210802":1480585069123,"1025556029060":1509788624341,"1023783569185":1491634246535,"1021832671364":1478686804035,"1022472210793":1480585069123,"1021794008790":1509788624394,"1022389113436":1478686417205,"1021832671365":1478686804035,"1022472210792":1480585069123,"1022646928381":1480585069149,"1021832671367":1478686804035,"1022472210794":1480585069123,"1022472210797":1480585069123,"1022472210796":1480585069123,"1022389113435":1478686417205,"1022472210799":1480585069123,"1022646928376":1480585069149,"1022472210785":1480585069123,"1025900348699":1509788667463,"1022472210784":1480585069123,"1025900348698":1509788667461,"1022472210787":1480585069123,"1022646928373":1480585069149,"1022472210786":1480585069123,"113368925":1444487341703,"1022472210789":1480585069123,"1025900348703":1509788667457,"1021832671369":1478686804035,"1021832671371":1478686804035,"1022472210790":1480585069123,"1022646928368":1480585069149,"1025900348700":1509788667462,"1022472210776":1480585069123,"1022472210779":1480585069123,"1023121420161":1509788624957,"1022472210782":1480585069123,"1023572150510":1509788624974,"1012352118176":1478686417074,"1022472210769":1480585069123,"1022472210768":1480585069123,"1022472210771":1480585069123,"1022472210770":1480585069123,"1022472210773":1480585069123,"1022472210772":1480585069123,"1022472210774":1480585069123,"1021940541754":1478686416973,"1022472210754":1480585069123,"1023939952323":1509788667538,"1012625906718":1478686804049,"1022472210745":1480585069123,"1022472210744":1480585069123,"1022472210747":1480585069123,"1025987786895":1514456869767,"1021487418443":1478686416985,"1022472210750":1480585069123,"1025987786890":1514456869767,"1022472210736":1480585069123,"1022472210741":1480585069123,"1022472210742":1480585069123,"1022165591272":1478686417278,"1022472210720":1480585069122,"1022472210723":1480585069122,"1025987786903":1514456869767,"1022472210722":1480585069122,"1025987786897":1514456869767,"1022472210724":1480585069123,"1025987786896":1514456869767,"1022472210713":1480585069122,"1022472210712":1480585069122,"1022472210715":1480585069122,"1022472210714":1480585069122,"1022646928268":1480585069149,"1023485777291":1509788624905,"1022472210719":1480585069122,"1021390427799":1478686417042,"1022222653489":1478686417192,"1022472210705":1480585069122,"1023485777287":1509788624905,"1022646928262":1480585069149,"1021286879350":1478686417237,"1023485777285":1509788624905,"1022472210706":1480585069122,"1022472210709":1480585069122,"1022472210708":1480585069122,"1022646928257":1480585069149,"1023485777281":1509788624905,"1021286879347":1478686417237,"1022472210710":1480585069122,"1021792829060":1478686417052,"1019472479318":1509788624368,"1019472479319":1509788624368,"1022472210699":1480585069122,"1019472479316":1509788624368,"1022472210698":1480585069122,"1019472479317":1509788624368,"1022472210701":1480585069122,"1022472210700":1480585069122,"1022472210703":1480585069122,"1022472210702":1480585069122,"1022646928279":1480585069149,"1022646928276":1480585069149,"1012172944162":1478686804028,"1022472210695":1480585069122,"1019472479320":1509788624368,"1022646928272":1480585069149,"1023485777296":1509788624905,"1022904496950":1509788624482,"1025791692574":1509788624507,"1025791692570":1509788624441,"1025796803750":1509788624523,"1021993625974":1478686417011,"1025796803748":1509788624537,"1025796803746":1509788624540,"1022904496932":1509788624482,"1025791692559":1509788624466,"1022904496929":1509788624482,"1025791692553":1509788624511,"1025791692555":1509788624466,"1022904496941":1509788624482,"1022904496943":1509788624482,"1025791692551":1509788624511,"1022929007010":1509788625052,"1009954979060":1491634246524,"1022400254213":1478686417207,"1008897702961":1478686804034,"1021843681380":1478686417053,"1025401250923":1509788624377,"1025401250922":1509788624377,"1025401250927":1509788624377,"1025401250926":1509788624377,"1022904496920":1509788624482,"1025401250925":1509788624377,"1022904496923":1509788624482,"1025401250924":1509788624377,"1025401250931":1509788624377,"1025401250930":1509788624377,"1022904496900":1509788624482,"1025401250929":1509788624377,"1021886937067":1478686804027,"1025401250928":1509788624377,"1022904496911":1509788624482,"1023485777455":1509788624251,"1023485777453":1509788624251,"1023485777452":1509788624251,"1025791692638":1509788624423,"1023485777451":1509788624251,"1025791692632":1509788624466,"1020657629509":1478686804050,"1025791692634":1509788624466,"1022472211121":1480585069126,"1023485777447":1509788624251,"1025791692629":1509788624511,"1022472211120":1480585069126,"1023485777446":1509788624251,"1951378949":1444487341746,"1023485777444":1509788624251,"1025791692630":1509788624511,"1024786645166":1509788624512,"1020978752947":1478686417087,"1023485777441":1509788624251,"1021345470029":1465470268225,"1022472211113":1480585069126,"1022472211112":1480585069126,"1022472211117":1480585069126,"1023995654239":1491634246530,"1022472211116":1480585069126,"1023835880420":1491634246504,"1022472211119":1480585069126,"1013029996535":1478686804066,"1022472211118":1480585069126,"1022199670115":1509788624933,"1021782998454":1509788624395,"1022472211104":1480585069126,"1022472211107":1480585069126,"1022472211106":1480585069126,"1022472211109":1480585069126,"1022904497001":1509788624482,"1022472211108":1480585069126,"1023485777458":1509788624251,"1022472211111":1480585069126,"1022904497003":1509788624482,"1022472211110":1480585069126,"1023485777456":1509788624251,"1022904496981":1509788624482,"1022472211096":1480585069125,"1023485777422":1509788624252,"1022472211099":1480585069125,"1021968591004":1509788624355,"1022472211101":1480585069125,"1023485777419":1509788624251,"1021968591002":1509788624355,"1022904496977":1509788624482,"1021968591003":1509788624355,"1022472211103":1480585069126,"1022472211102":1480585069125,"1021968591001":1509788624355,"1022472211089":1480585069125,"1022472211088":1480585069125,"1022472211091":1480585069125,"1023995654241":1491634246532,"1022472211090":1480585069125,"1022904496990":1509788624482,"1022472211095":1480585069125,"1022904496987":1509788624482,"1022904496986":1509788624482,"1023195603380":1509788625043,"1023485777438":1509788624251,"1022904496964":1509788624482,"1023485777436":1509788624251,"1025607274600":1509788624823,"1021951945612":1478686417261,"1022472211085":1480585069125,"1025791692649":1509788624507,"1025607274607":1509788624799,"1021951945613":1478686417261,"1022472211084":1480585069125,"1022472211087":1480585069125,"1023485777433":1509788624251,"1021951945615":1478686417261,"1022472211086":1480585069125,"1023485777431":1509788624251,"1025791692644":1509788624507,"1025791692647":1509788624507,"1025791692641":1509788624441,"1025607274599":1509788624833,"1025607274598":1509788624829,"1025791692643":1509788624441,"1023485777424":1509788624252,"1022472211064":1480585069125,"1022904497078":1509788625197,"1021951945597":1478686417261,"1022149338803":1478686417277,"1022472211057":1480585069125,"1022472211059":1480585069125,"1022472211058":1480585069125,"1022904497086":1509788625197,"1022472211061":1480585069125,"557054910":1444487341738,"1022472211060":1480585069125,"1022472211062":1480585069125,"1022472211049":1480585069125,"1022472211048":1480585069125,"1022472211050":1480585069125,"1022472211053":1480585069125,"1020805740219":1478686417030,"1022472211055":1480585069125,"1021951945583":1478686417261,"1022472211041":1480585069125,"1022472211040":1480585069125,"1022472211043":1480585069125,"1022472211045":1480585069125,"1022472211044":1480585069125,"1022904497064":1509788625196,"1022472211033":1480585069125,"1024017938038":1509788624517,"1024752566860":1509788667502,"1022472211035":1480585069125,"1022472211034":1480585069125,"1022472211037":1480585069125,"1022472211036":1480585069125,"1022472211039":1480585069125,"1022472211025":1480585069125,"1024752566853":1509788667502,"1022472211027":1480585069125,"1023397829895":1509788625039,"1022472211026":1480585069125,"1020984913200":1478686804039,"1022472211029":1480585069125,"1021390427613":1478686417042,"1024752566848":1509788667502,"1022472211031":1480585069125,"1022472211030":1480585069125,"1025714752263":1509788624822,"1025714752262":1509788624832,"1025714752261":1509788624828,"1020167412973":1509788624389,"1017286689112":1509788624939,"1025818693081":1509788667843,"1018476624827":1478686804029,"1025818693080":1509788667844,"1012905217932":1478686417018,"1025818693084":1509788667843,"1025714752268":1509788624745,"1022472211001":1480585069124,"1022472211000":1480585069124,"1020264404563":1509788624971,"1022472211002":1480585069124,"1022472211004":1480585069124,"1022472211007":1480585069125,"1010010157926":1491634246520,"1022472210993":1480585069124,"1010010157928":1491634246521,"1022472210992":1480585069124,"1010010157929":1491634246521,"1022904497151":1509788625197,"1020657629641":1478686804050,"1022472210994":1480585069124,"1022472210997":1480585069124,"1022472210996":1480585069124,"1022904497144":1509788625197,"1021304311896":1478686417004,"1022472210999":1480585069124,"1022904497147":1509788625197,"1022472210998":1480585069124,"1022472210985":1480585069124,"1024752566845":1509788667502,"1022472210984":1480585069124,"1021656368456":1509788624396,"1022904497127":1509788625197,"1022472210986":1480585069124,"1022472210989":1480585069124,"1022472210988":1480585069124,"1022472210991":1480585069124,"1022472210990":1480585069124,"1022472210977":1480585069124,"1022472210976":1480585069124,"1020934581830":1478686417033,"1021898995674":1478686417054,"1022472210979":1480585069124,"1022904497135":1509788625197,"1022472210978":1480585069124,"1022472210980":1480585069124,"1022472210983":1480585069124,"1022472210982":1480585069124,"1022904497108":1509788625196,"1022472210973":1480585069124,"1023927106757":1491634246530,"1022472210972":1480585069124,"1022472210974":1480585069124,"1022904497113":1509788625197,"1021666343436":1478686417248,"1019008097152":1509788624301,"1022472210952":1480585069124,"1025585255354":1509788624336,"1022904497094":1509788625197,"370265317":1491634246519,"1022065716677":1478686417271,"1022904497088":1509788625197,"1022904497090":1509788625197,"1022472210945":1480585069124,"1022472210944":1480585069124,"1022472210946":1480585069124,"1022472210949":1480585069124,"1025585255351":1509788625019,"1022904497097":1509788625197,"1022472210948":1480585069124,"1022472210951":1480585069124,"1022472210950":1480585069124,"1022549282624":1509788624427,"1019195528999":1478686804054,"1020657629192":1478686804065,"1024055948697":1509788624928,"1022155892417":1509788624959,"1021425027668":1509788624978,"1020754752072":1478686417076,"1022220688070":1478686804049,"1025485379694":1509788624360,"1025485379693":1509788624360,"1025485379692":1509788624360,"1025485379691":1509788624360,"1025485379690":1509788624361,"1025485379689":1509788624361,"1025485379688":1509788624361,"1020984913060":1478686804022,"1025485379687":1509788624360,"1025485379686":1509788624360,"1025485379685":1509788624360,"1025485379684":1509788624361,"1010769431847":1478950494939,"1025784483368":1509788624349,"1019766093153":1509788624315,"1020657629256":1478686804050,"1022549282572":1509788624434,"1022452815180":1509788624525,"1022455305385":1478686417297,"1025010924755":1509788624332,"113368476":1444487341703,"1022452815207":1509788624525,"1022452815208":1509788624525,"1021982484833":1478686417057,"1024529748259":1509788624538,"1017286688919":1509788624939,"1021517696167":1509788624401,"1009965071860":1491634246523,"1020657629319":1478686804050,"1022096384724":1478686417181,"1019398947723":1480585069073,"1023946374282":1491634246531,"1017505592177":1478686804016,"1022646927869":1480585069148,"1023946374281":1491634246517,"1022646927867":1480585069148,"1022646927865":1480585069148,"1021974227245":1509788624463,"1019455571815":1478686804021,"1025331519912":1509788624467,"1025331519918":1509788624467,"1023483942720":1509788624947,"1023958168460":1509788667535,"1025331519910":1509788624467,"1021254376637":1478686417237,"1022904496867":1509788624482,"4980208385":1509788624162,"1022904496855":1509788624482,"1020996051731":1478686417230,"1021886019111":1478686417258,"1025485379758":1509788624360,"1025485379757":1509788624360,"1025331519897":1509788624467,"1025485379756":1509788624360,"1025485379755":1509788624360,"1025331519903":1509788624467,"1025485379754":1509788624360,"1025485379753":1509788624360,"1025331519901":1509788624467,"1025485379752":1509788624360,"1022904496834":1509788624482,"1025485379751":1509788624360,"1019724674886":1509788625078,"1025485379750":1509788624360,"1012557355534":1478686417026,"1022904496847":1509788624482,"1022904496840":1509788624482,"1023634148938":1509788624948,"1022904497460":1509788624889,"1022646929005":1480585069150,"1024383737583":1509788624329,"1022390032344":1478686417290,"1022646929000":1480585069150,"1022904497468":1509788624889,"1022898075037":1509788624402,"1021941722270":1509788624464,"1022646928992":1480585069150,"1020984912782":1478686804022,"1014882415":1478686804024,"1022646929018":1480585069150,"1022646929016":1480585069150,"1022646929015":1480585069150,"1022904497451":1509788624889,"1021342584846":1478686417103,"1021441543781":1478686417107,"1022646928970":1480585069150,"1024383737550":1509788624329,"1021425028458":1509788624978,"1016957049729":1478686804031,"1022904497414":1509788624889,"1022478765217":1478943089487,"1022478765216":1478943089487,"1022646928986":1480585069150,"1022904497421":1509788624889,"1022646928980":1480585069150,"1021087539551":1478686416981,"1022904497416":1509788624889,"1022646928976":1480585069150,"1022646928942":1480585069150,"1022904497521":1509788624889,"1022646928938":1480585069150,"1022646928931":1480585069150,"1022646928954":1480585069150,"1019166037938":1478686804020,"1005989389587":1480585069062,"1022646928909":1480585069150,"1018271877428":1509788624354,"1021721526236":1509788624403,"1022646928900":1480585069150,"1022646928898":1480585069150,"1284346080":1509788625020,"1021646799463":1509788624195,"1022904497477":1509788624889,"1022646928926":1480585069150,"1022887982150":1509788625018,"1024383737488":1509788624329,"1016543277605":1478686804021,"1016543277604":1478686804034,"1021603807428":1478686417246,"1022904497481":1509788624889,"1020895784625":1478686417079,"1022646928914":1480585069150,"1012910328509":1478686417026,"1022904497482":1509788624889,"1024688736346":1509788624427,"1024984054179":1509788624924,"1024984054178":1509788624924,"1022646929130":1480585069150,"1022904497584":1509788624889,"1025172925818":1509788624922,"1025172925817":1509788624922,"1025172925816":1509788624922,"1024984054182":1509788624924,"1022646929127":1480585069150,"1022262108150":1478686804065,"1025172925814":1509788624922,"4974834703":1509788624162,"1022646929123":1480585069150,"1025172925811":1509788624922,"1025172925810":1509788624922,"1025172925809":1509788624922,"1025172925808":1509788624922,"1020073958745":1465470268310,"1022646929149":1480585069151,"1025172925804":1509788624922,"1022904497569":1509788624889,"1025172925803":1509788624922,"1025172925802":1509788624922,"1022646929145":1480585069151,"1025172925800":1509788624922,"1022904497580":1509788624889,"1025172925798":1509788624922,"1021498559096":1478686417112,"1022904497583":1509788624889,"1025815808791":1509788667405,"1022646929138":1480585069150,"1025172925794":1509788624922,"1022646929136":1480585069150,"1025172925792":1509788624922,"1025172925791":1509788624922,"1025172925790":1509788624922,"1025172925787":1509788624922,"833481992":1478686804064,"1024383737423":1509788624329,"1019299598013":1509788624281,"1022646929119":1480585069150,"1022904497538":1509788624889,"1022904497549":1509788624889,"1022646929110":1480585069150,"1024984054168":1509788624924,"1021594371986":1478686417048,"1022646929105":1480585069150,"1024984054175":1509788624924,"1024577851848":1509788624925,"1023133084501":1509788625152,"1023133084497":1509788625152,"1023133084499":1509788625152,"1022904497650":1509788624889,"1023133084498":1509788625152,"1021602496612":1509788624408,"1022904497656":1509788624889,"1010057343039":1491634246534,"1022083409106":1478686417178,"1023133084492":1509788625152,"1016957049707":1478686804034,"1019166037812":1478686804020,"1022904497622":1509788624889,"1008744595920":1478686804019,"1019025923756":1509788624324,"1022904497606":1509788624889,"1020741776619":1478686417028,"1022904497201":1509788625196,"1573880010":1491634246506,"1024341156502":1509788624518,"1021345075468":1478686804023,"1021644702500":1478686417248,"1021981962046":1509788625248,"1022904497210":1509788625196,"1021981962045":1509788625246,"1022904497190":1509788625197,"1022904497196":1509788625197,"1022904497192":1509788625197,"1024567628080":1509788667495,"1022904497171":1509788625197,"1021865571877":1509788624513,"1019448493596":1478686804021,"1022904497176":1509788625197,"1022904497155":1509788625197,"1022904497167":1509788625197,"1023926450967":1491634246530,"1023926450966":1491634246530,"1022472211897":1480585069121,"1022472211896":1480585069121,"1021439840032":1478686416986,"1022472211899":1480585069121,"1022472211898":1480585069121,"1022646929196":1480585069151,"1021981962102":1509788625247,"1022472211889":1480585069121,"1021439840043":1478686416986,"1022472211888":1480585069121,"1021981962107":1509788625247,"1022296971265":1478686417068,"1022904497279":1509788624249,"1021981962104":1509788625246,"1022472211890":1480585069121,"1022472211893":1480585069121,"1022472211892":1480585069121,"1022646929184":1480585069151,"1334678237":1491634246519,"1022909216669":1509788624402,"1021981962083":1509788625247,"1022472211883":1480585069121,"1022472211882":1480585069121,"1022472211884":1480585069121,"1022646929210":1480585069151,"1022472211887":1480585069121,"1016930965620":1478686804019,"1022472211886":1480585069121,"1022472211873":1480585069121,"1022472211875":1480585069121,"1022472211874":1480585069121,"1022472211877":1480585069121,"1022472211876":1480585069121,"1022646929202":1480585069151,"1021318993640":1478686417102,"1022472211879":1480585069121,"1025516443653":1509788624336,"1021981962067":1509788625247,"1025516443655":1509788624338,"1025516443654":1509788624339,"1021981962071":1509788625247,"1022254112401":1478686417196,"1022646929159":1480585069151,"1022646929157":1480585069151,"1022646929155":1480585069151,"1021981962077":1509788625247,"1021981962050":1509788625247,"1021981962051":1509788625247,"1014585353313":1480585069074,"1021981962049":1509788625248,"1022646929179":1480585069151,"1021981962054":1509788625247,"1021981962055":1509788625246,"1021981962052":1509788625247,"1022646929176":1480585069151,"1021981962053":1509788625247,"1024300392601":1509788624292,"1021981962059":1509788625247,"1021981962057":1509788625246,"1022646929171":1480585069151,"1021981962063":1509788625247,"187684433":1444487341703,"1022646929168":1480585069151,"1022646929391":1480585069091,"1022904497332":1509788624250,"1022646929388":1480585069091,"1022904497334":1509788624250,"1022646929387":1480585069091,"1022904497331":1509788624250,"1022646929381":1480585069091,"1021040224219":1478686417036,"1022904497336":1509788624250,"1274123903":1478950494921,"1022904497338":1509788624250,"1021075481003":1465470268250,"1022904497316":1509788624250,"1022646929404":1480585069091,"1022646929401":1480585069091,"1022904497314":1509788624250,"1019723493684":1478686804021,"1022646929399":1480585069091,"1024341156363":1509788625136,"1020390492535":1478686804047,"1022646929398":1480585069091,"1022646929393":1480585069091,"1020294157065":1465470268294,"1022904497302":1509788624250,"1022813927736":1509788625055,"1022904497299":1509788624249,"1022904497309":1509788624250,"1022904497308":1509788624250,"1022904497305":1509788624250,"1022904497307":1509788624250,"1007244630320":1478686804033,"1022904497285":1509788624250,"1022646929373":1480585069091,"1022416245146":1478686804039,"1022646929370":1480585069091,"1022904497280":1509788624250,"1022646929369":1480585069091,"1022904497283":1509788624250,"1021650731636":1478686417049,"1024607998515":1509788667590,"1022904497295":1509788624250,"1022904497289":1509788624250,"1024341156399":1509788625104,"1024341156398":1509788625104,"1022904497291":1509788624250,"1021498297126":1478686417007,"1021248477707":1478686417039,"1022646929323":1480585069151,"1022646929321":1480585069151,"1022646929319":1480585069151,"1024341156442":1509788625104,"1022646929317":1480585069151,"1022904497407":1509788624889,"1022646929316":1480585069151,"1024341156440":1509788625104,"1022646929315":1480585069151,"1021212170716":1509788624171,"1022646929313":1480585069151,"1022904497403":1509788624889,"1022646929312":1480585069151,"1274123811":1478950494921,"1001689834599":1478686417018,"1022646929340":1480585069151,"1022646929339":1480585069151,"1022646929336":1480585069151,"124377779":1444487341704,"1025589843167":1509788624351,"1024341156424":1509788624518,"1011987071511":1478686804040,"1022646929294":1480585069151,"1024341156465":1509788625103,"1022646929291":1480585069151,"1022646929289":1480585069151,"1023572151471":1509788624974,"1024341156468":1509788625103,"1022646929285":1480585069151,"1022646929282":1480585069151,"1009745118329":1491634246512,"1024616911596":1498657040078,"1022646929311":1480585069151,"1022646929309":1480585069151,"1024136425044":1509788624600,"1022904497345":1509788624249,"1020927110887":1478686417082,"1022646929306":1480585069151,"1011987071549":1478686804026,"1022646929304":1480585069151,"1022904497346":1509788624249,"1018651472205":1509788625019,"1020900634490":1478686417080,"1022646929299":1480585069151,"1020962237191":1478686417001,"407618998":1478950494909,"1022646929296":1480585069151,"1022646928493":1480585069149,"1021749574637":1478686417126,"1022646928490":1480585069149,"1022646928488":1480585069149,"1020657630472":1478686804058,"1022646928484":1480585069149,"1022646928481":1480585069149,"1022646928507":1480585069149,"1801303367":1444487341739,"1024341156239":1509788624548,"1022646928497":1480585069149,"1025399677019":1509788624298,"1024577852241":1509788624925,"1022646928454":1480585069149,"1021602497180":1509788624408,"1025504778758":1509788624338,"1024341156258":1509788624518,"1025504778757":1509788624340,"1022646928476":1480585069149,"1021852595696":1509788624399,"1021602497179":1509788624408,"4981126876":1509788624160,"1025278699913":1509788667580,"1022646928466":1480585069149,"1020294156438":1465470268293,"1022646928431":1480585069149,"1022827559914":1509788625054,"1017022322153":1478686804016,"1009959565537":1480585069071,"1022646928418":1480585069149,"1021627794303":1478686417119,"1022646928446":1480585069149,"1538885099":1444487341702,"1024341156289":1509788625103,"1024341156292":1509788625103,"1022646928437":1480585069149,"1021847745619":1509788624856,"1021847745616":1509788624856,"1021084656619":1509788624975,"1016608156699":1478686804034,"1020657630564":1478686804058,"1021847745620":1509788624856,"1021847745621":1509788624856,"1021646798944":1509788624534,"1022646928388":1480585069149,"1010013697818":1491634246526,"1012625906607":1478686804049,"1022646928410":1480585069149,"1011987071421":1478686804040,"1024341156324":1509788624518,"1025120891751":1509788625023,"1012512415771":1444487341761,"1025792608366":1509788624409,"1022646928621":1480585069149,"1025792608363":1509788624409,"1022646928616":1480585069149,"1025792608359":1509788624409,"1022646928613":1480585069149,"1022646928637":1480585069149,"1022646928629":1480585069149,"1025792608373":1509788624409,"1025792608372":1509788624409,"1025792608371":1509788624409,"1022646928625":1480585069149,"1025792608369":1509788624409,"1011618633567":1478686804064,"1025792608368":1509788624409,"1528268214":1458304307281,"1019364346011":1509788624315,"1528268198":1458304307281,"1022646928603":1480585069149,"1020294025239":1465470268281,"1022422668145":1478686417293,"1022646928595":1480585069149,"1021865571779":1509788624433,"1024341156182":1509788625103,"1024577852350":1509788624925,"1024341156186":1509788625103,"1003492178670":1478686417220,"1022344418885":1478686417202,"1515291779":1478950494924,"1019744596922":1465470268275,"1024341156171":1509788625103,"1528268236":1458304307281,"1021865571804":1509788624433,"1024341156172":1509788625103,"1021974883450":1509788624389,"1024341156215":1509788625103,"1022646928519":1480585069149,"1025712918342":1509788624309,"1022037403690":1509788625144,"1021988252991":1478686417154,"1022646928514":1480585069149,"1024341156220":1509788625103,"1023692342991":1509788624325,"1021895717794":1478686417258,"1022238776375":1509788624947,"1022238776379":1509788624931,"1022238776377":1509788624932,"1022646928749":1480585069150,"1022021544656":1509788624181,"1021041927485":1478686417092,"1022904497725":1509788624583,"1025007122632":1509788667497,"1024577852028":1509788624925,"1022646928766":1480585069150,"1012625906380":1478686804049,"1020219971105":1509788625081,"1022646928761":1480585069150,"1024341155979":1509788625103,"1022021806795":1478686417266,"1024341155978":1509788625103,"1022646928757":1480585069150,"4981127162":1509788624160,"1023845449265":1491634246520,"1022646928732":1480585069150,"1022646928728":1480585069150,"1019193955171":1478686804020,"1329696772":1491634246534,"1022646928679":1480585069150,"1022646928677":1480585069150,"1019704358074":1509788624354,"1022646928674":1480585069150,"1022904497784":1509788624583,"1019484668325":1509788625021,"1223792574":1444487341754,"1022904497764":1509788624583,"1016644332288":1478686804031,"1022904497774":1509788624583,"1022079346460":1478686417301,"1024528569627":1509788624183,"1223792556":1444487341739,"1024528569626":1509788624183,"1022904497748":1509788624583,"1022646928652":1480585069150,"1024528569636":1509788624183,"1024528569635":1509788624183,"1024341156086":1509788625103,"1024528569633":1509788624183,"1024341156085":1509788625103,"1022646928648":1480585069149,"1024528569632":1509788624183,"1024577851935":1509788624925,"1022646928644":1480585069149,"1022904497755":1509788624583,"1022262107151":1478686804050,"1022646928670":1480585069150,"1021041927497":1478686417092,"1022646928668":1480585069150,"1021041927502":1478686417092,"1022646928667":1480585069150,"1022646928666":1480585069150,"1021137461010":1478686417233,"1022904497731":1509788624584,"142202625":1444487341711,"1022646928663":1480585069150,"1022646928660":1480585069150,"1022904497845":1509788624583,"1021390426353":1478686417042,"1020916886543":1478686417080,"1021142310847":1478686417234,"1021390426355":1478686417042,"1022904497841":1509788624583,"1021646799247":1509788624818,"1021960859387":1480585069071,"1022904497854":1509788624583,"1021425028812":1509788624978,"1022904497848":1509788624583,"1022904497850":1509788624583,"1022904497829":1509788624583,"1021918392424":1509788624869,"1022646928893":1480585069150,"1022646928891":1480585069150,"1021679452077":1478686417249,"1022904497826":1509788624583,"1022646928887":1480585069150,"1022904497839":1509788624583,"1024341155855":1509788625103,"1022904497832":1509788624583,"1024577852136":1509788624925,"1024341155852":1509788625103,"1022423454310":1478686417210,"1021226064535":1478686417099,"1022375875867":1509788624945,"1024341155903":1509788625103,"1024341155901":1509788625103,"1021687053847":1478686417009,"1024341155872":1509788624518,"1020657630388":1478686804058,"1022904497795":1509788624583,"1020657630389":1478686804058,"1022904497794":1509788624583,"1022543252227":1509788625064,"1022904497802":1509788624583,"1022646928812":1480585069150,"1024341155926":1509788625104,"1021572482396":1478686417048,"1022646928809":1480585069150,"1024341155925":1509788625104,"1022646928807":1480585069150,"1018490125723":1478686804066,"1022646928804":1480585069150,"1020977702944":1478686417087,"1022646928800":1480585069150,"1022646928826":1480585069150,"1021426208388":1478686417044,"1021974883657":1509788624389,"1022646928823":1480585069150,"1022646928821":1480585069150,"1022646928817":1480585069150,"1022646928783":1480585069150,"1020791190761":1478686417077,"1022646928777":1480585069150,"1022904497860":1509788624583,"1022956925924":1509788624857,"1022904497857":1509788624583,"1022956925921":1509788624857,"1024341155943":1509788625103,"407619518":1478950494909,"1022646928794":1480585069150,"1022956925920":1509788624857,"1022956925923":1509788624857,"1022956925922":1509788624857,"1024341155940":1509788625102,"1022904497868":1509788624583,"1022646928789":1480585069150,"1022646928786":1480585069150,"1022904497864":1509788624583,"1024188066125":1509788624454,"1022065715407":1478686417012,"1024341155730":1509788625248,"1010919128963":1444487341758,"1010919128966":1444487341758,"1012208061631":1478686417073,"1022811948199":1509788625102,"1024341155725":1509788625248,"478936212":1444487341749,"1021825452359":1509788624995,"1012689479734":1478686416995,"1023751732374":1509788624926,"1022021539314":1509788624181,"1022021539312":1509788624180,"1022428835139":1478686417294,"1022811948170":1509788625102,"1021402886274":1478686417043,"1022811948173":1509788625102,"1021047823339":1478686417092,"1016400135935":1480585069068,"1022451904078":1478686417296,"1024341155799":1509788625104,"1024341155800":1509788625104,"249556620":1478950494908,"1021390434085":1478686417042,"1021677338630":1478686417120,"1024188061397":1509788624229,"1024442328333":1509788624926,"1020840070728":1478686417031,"1008347719349":1478686804015,"1009302839204":1509788625017,"1023771917586":1491634246535,"1022566987040":1509788624567,"1021919694779":1509788624465,"1022811948230":1509788625102,"1022081308838":1478686417061,"1022015378608":1478686417266,"1022015378613":1478686417266,"1021176914569":1478686416977,"1022472220791":1480585069121,"1025608592247":1509788624999,"1022780752390":1509788624462,"1022361069839":1478686417203,"1023959599306":1509788624538,"1022015378606":1478686417266,"1025608592248":1509788624997,"1022811948057":1509788625102,"1017190888709":1478686804058,"1017190888708":1478686804058,"1022065711003":1478686417270,"1022015378589":1478686417266,"1022811948052":1509788625102,"1025007109999":1509788667497,"1021030652521":1478686417091,"1022427524406":1478686417294,"1015658420652":1478686804031,"1022046574228":1478686417269,"1021684023601":1478686417249,"1020907967220":1478686417080,"1021684023602":1478686417249,"1022460817221":1480585069074,"1021687562621":1480585069059,"1022460817219":1480585069074,"1021687824754":1509788624195,"1022262109108":1478686804050,"1022262109107":1478686804050,"688245205":1478950494913,"4965648169":1509788624164,"1021443650290":1478686417107,"1022046574216":1478686417269,"1083416653":1444487341723,"1021912092346":1509788624451,"1022811948124":1509788625102,"1022811948127":1509788625102,"1024341155707":1509788625103,"4973119617":1509788624162,"1010919128959":1444487341758,"1009163507409":1478686804054,"1024341155708":1509788625103,"1022262108796":1478686804050,"1025331518309":1509788625171,"1014730826576":1465470268256,"1025650666610":1509788624429,"1015472295697":1509788624171,"1021390433875":1478686417042,"1020858945068":1478686417031,"154396673":1444487341748,"1020257856962":1465470268311,"840422179":1478950494917,"1021881552187":1509788624437,"1024459237212":1509788625029,"1021687824512":1509788624534,"1021848259382":1478686417053,"1022476284411":1478943089487,"1022476284412":1478943089487,"1024434332844":1509788624465,"1022331315731":1478686417288,"1022261453351":1478686417197,"1024055939011":1509788624969,"1022165195893":1478686417013,"1021341281567":1478686417041,"1024449668166":1509788624972,"1021341281565":1478686417041,"1022331315712":1478686417288,"1021949317473":1478686417145,"1021145981060":1478686417096,"1024156472806":1509788667500,"1022192983787":1478686417281,"1020597060041":1478686804031,"1024014257557":1509788667857,"1024953763217":1509788624192,"1022368409741":1478686417204,"1022172536659":1509788624611,"1018095856218":1465470268270,"1018215920386":1509788624284,"1022463176428":1478686417298,"172223455":1444487341728,"1022811948316":1509788625102,"4965647958":1509788624164,"1007394843702":1509788624378,"1022435650751":1478686417294,"1022811948292":1509788625102,"1021765682389":1478686417127,"1022849042343":1509788624282,"1025270568900":1509788625104,"1884000645":1509788625017,"1025521427689":1509788624431,"1024936330183":1509788625006,"1022311393166":1478686417302,"1025896693050":1509788667465,"1016558603923":1478686804024,"1025896693048":1509788667461,"1021250971213":1478686417236,"1022424902744":1478686417070,"1021672620411":1509788624396,"1024520841432":1509788624990,"1025429021362":1509788625126,"1024281516309":1509788624932,"1021925461365":1478686417141,"430701450":1491634246514,"1020916093331":1478686417032,"1024145330454":1509788625169,"1025512646546":1509788624343,"1022262108497":1478686804050,"1024145330449":1509788625129,"1024145330444":1509788625129,"1024145330443":1509788625129,"1024145330442":1509788625129,"1024145330440":1509788625129,"1022238646524":1509788624930,"1024145330435":1509788625144,"1023949114061":1509788667493,"1022238646522":1509788624932,"1017127842593":1478686804019,"1010002283120":1491634246524,"1018762612826":1509788624372,"1004588303493":1444487341762,"1025585261317":1509788624304,"1021234062583":1478686417039,"1024134451600":1509788625036,"1023275031880":1509788624392,"430701555":1491634246514,"1021400265351":1478686417106,"1021400265345":1478686417106,"1025711354798":1509788624305,"1022811948744":1509788625102,"1025902198288":1509788667452,"1022811948736":1509788625102,"1021687825204":1509788624818,"1022217937561":1478686417192,"1018517767702":1480585069070,"1021981561005":1478686416984,"1022030190579":1478686417058,"1021554932515":1478686417245,"1022811948561":1509788625102,"1007947959330":1478686804023,"1018889361614":1509788624945,"1022811948565":1509788625102,"845140205":1491634246514,"1022019049282":1478686417161,"1023995644085":1491634246532,"1303359248":1444487341735,"1022019049274":1478686417161,"1025596401762":1509788624843,"430701420":1491634246514,"1022811948657":1509788625102,"1022262108594":1478686804050,"1022811948660":1509788625102,"179824743":1444487341744,"1023529954590":1509788624821,"1021501060108":1478686417112,"1022307066884":1478686417015,"1021775512741":1509788624994,"1021775512736":1509788624994,"1021733832219":1509788624514,"1015472295126":1509788624172,"1021687563087":1480585069060,"1020294032815":1465470268282,"1019739606751":1509788624173,"1025900363654":1509788667464,"1022172536272":1509788624611,"1012216975158":1478686804024,"1025900363658":1509788667462,"603046140":1444487341729,"1025099517775":1509788624304,"1025745825987":1509788624972,"1022477726618":1478943089487,"1021502633407":1509788625004,"1022811948953":1509788624421,"1021460557827":1478686417044,"1022811948956":1509788624421,"1020271882036":1465470268317,"1024661746010":1509788624604,"1024005212343":1491634246533,"1024273258664":1509788624277,"118088753":1444487341725,"1021943681858":1478686417144,"1021951546072":1478686417145,"1021501453718":1478686417244,"1021877882628":1478686417053,"1022472221628":1480585069121,"1010002283376":1491634246524,"1022811949041":1509788624421,"1019862161190":1509788624283,"1021985624232":1478686417264,"1021328435289":1478686416978,"1022811949021":1509788624421,"1021197887400":1464448510787,"1023932073117":1491634246530,"1021974876658":1509788624453,"1021396462701":1478686417006,"1010378595539":1509788624380,"1025720660703":1509788625007,"1021560699559":1509788624401,"1020906525107":1478686417080,"1021859268862":1509788625080,"1022811948839":1509788624420,"1022811948838":1509788624420,"1015496413953":1478686804028,"1019748388594":1509788624324,"1025720660731":1509788624345,"1025720660732":1509788624346,"1021127646388":1478686417095,"1025429545753":1509788624437,"1019166042180":1478686804020,"1002491316836":1478950494935,"1022811948804":1509788624420,"1022811948807":1509788624420,"1024145330428":1509788625166,"1024145330427":1509788625166,"1024145330424":1509788625244,"1024145330421":1509788625246,"1015599961433":1465470268264,"1021352554106":1478686416978,"1021687562862":1480585069059,"1021425955459":1478686417007,"1021971730809":1478686417149,"1022262108322":1478686804050,"1310436857":1478686804024,"1015472295382":1509788624172,"1021626367663":1509788624933,"1022260928611":1478686417014,"1022811948875":1509788624421,"1021626367667":1509788624931,"1022811948878":1509788624421,"1022185119213":1478686417187,"1023878727427":1491634246530,"1025407146985":1509788624435,"1020991722292":1509788624930,"1025407146984":1509788624435,"1023878727425":1491634246530,"1020991722294":1509788624930,"1023878727424":1491634246530,"1796574994":1509788624310,"1020991722301":1509788624946,"1025270567431":1509788625104,"1020991722296":1509788624942,"1020991722297":1509788624946,"1020991722298":1509788624946,"1020805728289":1478686417077,"1022811947180":1509788624195,"1022811947183":1509788624195,"1020991722286":1509788624942,"1025407146952":1509788624512,"1025407146954":1509788624512,"1019028284953":1480585069072,"1025407146956":1509788624451,"1025407146948":1509788624509,"1021418616200":1478686417043,"1022065709855":1478686417175,"1025407146968":1509788624424,"1025407146973":1509788624435,"1022231831833":1509788624921,"1022811947137":1509788624195,"1025407146960":1509788624452,"1022811947140":1509788624195,"1021605263544":1478686417246,"1003312873136":1478686804054,"1012493539833":1478686417223,"1003312873137":1478686804054,"1021605263554":1478686417246,"1012265995130":1478686417026,"1022811947233":1509788624196,"1003312873134":1478686804054,"1022811947231":1509788624195,"1020610037144":1509788624353,"1020991722308":1509788624932,"1020991722309":1509788624940,"1021502632662":1509788625004,"1025906915401":1509788667462,"1022376144589":1478686417290,"1010091936321":1491634246522,"1021925460971":1478686417141,"1022811947056":1509788624195,"1023949114490":1509788667493,"1019196057777":1509788624946,"118088603":1444487341742,"1021388204803":1478686804024,"1021704734243":1478686417050,"1022811947046":1509788624195,"1025331519176":1509788625172,"1025331519183":1509788625171,"1025331519182":1509788625171,"1025331519180":1509788625172,"1025331519171":1509788625171,"1025331519169":1509788625171,"1025331519174":1509788625171,"1025331519173":1509788625171,"1025331519172":1509788625171,"1023751731204":1509788624926,"1021409047783":1478686804050,"1000527695942":1444487341732,"1025331519187":1509788625172,"1025331519186":1509788625172,"1025331519185":1509788625172,"1021271944411":1478686804066,"1025331519151":1509788625172,"1025331519150":1509788625172,"1025331519149":1509788625172,"1022248216216":1478686417066,"1012889891018":1478686804020,"1025331519163":1509788625172,"1020309498643":1465470268301,"1025331519162":1509788625172,"1022081703145":1478686417272,"1025331519165":1509788625172,"1025331519155":1509788625172,"1025331519154":1509788625172,"1023018783903":1509788625049,"1025331519153":1509788625172,"1020309498654":1465470268258,"1025331519157":1509788625172,"1025429021796":1509788624407,"1025429021786":1509788624429,"1020309498657":1465470268301,"1020309498662":1465470268258,"1020294031941":1465470268282,"840423143":1478950494917,"1022248216231":1478686417066,"1022248216230":1478686417066,"1022930308990":1509788625073,"1022248216233":1478686417066,"1025214207592":1509788624936,"1021527798307":1509788624912,"1021527798309":1509788624912,"1025214207596":1509788624936,"1024663844689":1509788624417,"1025214207599":1509788624936,"1024663844688":1509788624417,"1021527798311":1509788624912,"1025214207598":1509788624936,"1021527798312":1509788624912,"1017230209600":1478686804065,"1021527798313":1509788624912,"1021527798314":1509788624912,"1025214207587":1509788624936,"1021527798315":1509788624912,"1021627152472":1478686417300,"1024663844699":1509788624417,"1021527798317":1509788624912,"1021527798319":1509788624912,"1021527798320":1509788624912,"1021527798321":1509788624912,"1021527798322":1509788624912,"1021527798324":1509788624912,"1025214207612":1509788624936,"1024663844673":1509788624417,"1024663844687":1509788624417,"1021527798328":1509788624912,"1024663844686":1509788624417,"1021527798330":1509788624912,"4553566837":1465469681389,"1010076207309":1491634246534,"1025214207604":1509788624936,"1025214207607":1509788624936,"1021527798335":1509788624912,"1025214207560":1509788624936,"1022226195617":1478686417064,"1025214207563":1509788624936,"1025214207564":1509788624936,"1025214207566":1509788624936,"1024661616478":1509788625069,"1019599749414":1465470268274,"430701696":1491634246514,"1022811947410":1509788624196,"1000038413099":1478686417021,"1024661747545":1509788624906,"1025214207559":1509788624936,"1025214207558":1509788624936,"1025214207577":1509788624936,"1024663844709":1509788624417,"1021311266622":1465470268205,"1022811947406":1509788624196,"1025214207582":1509788624936,"1025214207570":1509788624936,"1025214207573":1509788624936,"1021943682372":1478686417144,"1021527798303":1509788624912,"1025214207574":1509788624969,"1023926305647":1491634246528,"1023949770115":1509788667501,"1023926305640":1491634246528,"1023949770123":1509788667502,"1025901148632":1509788667789,"1021026589776":1509788624932,"1023949770130":1509788667502,"1015150919183":1480585069068,"1024663844622":1509788624417,"1023949770142":1509788667501,"1020770864926":1478686417029,"1023949770151":1509788667502,"1024735408995":1509788667507,"1023926305631":1491634246530,"1021925460511":1478686417141,"1023926305630":1491634246530,"1021990475513":1478686417155,"1018335591455":1478686804054,"1021619550251":1478686804050,"1024983908523":1509788624924,"1018674792665":1478686804024,"1021750739057":1509788624403,"1024535391855":1509788625027,"1021258965634":1478686417101,"1023949770095":1509788667501,"1022811947280":1509788624196,"1022811947285":1509788624196,"1021258965637":1478686417101,"1023949770099":1509788667501,"1021581672023":1478686417114,"1023949770110":1509788667502,"1021083998216":1478686417002,"1023949770107":1509788667502,"1022428309544":1478686417302,"230418553":1444487341725,"1004329317279":1444487341711,"1021687563381":1480585069060,"1023888949675":1491634246517,"1022021799943":1478686417266,"1825802500":1478686804033,"1022811947352":1509788624196,"1023751731548":1509788624926,"1000038413292":1478686417021,"1022975265553":1509788625018,"1024469328446":1509788624522,"1022811947343":1509788624196,"1021409047980":1478686804050,"1021731604196":1478686417124,"1012037142284":1478686804019,"1008601870411":1478686804030,"1022239434532":1478686417065,"1015472294860":1509788624172,"1021473534589":1509788624398,"1015868252318":1465470268260,"1018311343859":1478686804031,"1022055616955":1478686417173,"1021365659860":1478686417104,"1024944194971":1509788624406,"1021365659859":1478686417104,"1021365659878":1478686417104,"1022331576693":1478686417068,"1022468548868":1478686417303,"1021365659892":1478686417104,"1022238778499":1509788624935,"1021406295587":1509788624406,"1022238778497":1509788624947,"1026232358545":1514456869770,"1026232358544":1514456869770,"1026232358546":1514456869769,"1022535791939":1480585069131,"1026232358549":1514456869769,"1026232358548":1514456869768,"1024653096105":1509788624177,"1019125280289":1509788625079,"1022038446214":1509788624899,"1026232358543":1514456869770,"1020251958641":1478686804021,"1021428053864":1478686804026,"1016832416093":1478686804058,"1021714170980":1509788624404,"1016301569734":1480585069066,"1022647991326":1509788624978,"1022172534964":1478686417186,"1019197631085":1509788625086,"1026223442219":1514456869766,"1025913207725":1509788667818,"1021982610545":1478686417152,"1023958158911":1509788667535,"647217384":1491634246511,"1022148155985":1509788624408,"1023751731912":1509788624926,"1022361071389":1478686417203,"1023919358002":1509788624948,"1021825454063":1509788624995,"1021825454070":1509788624995,"1021825454068":1509788624995,"1021825454064":1509788624995,"1023888950000":1491634246517,"1021825454078":1509788624995,"1022566986698":1509788624200,"4965646690":1509788624162,"1021852192085":1509788624394,"1021825454077":1509788624995,"1021825454072":1509788624995,"1008036959716":1478686804018,"1021465408082":1478686417045,"1019852723634":1509788624285,"1019852723635":1509788624285,"1008036959721":1478686804018,"1019852723636":1509788624285,"1022566986734":1509788624230,"1010741916351":1509788624276,"1019612464014":1509788624312,"1010741916356":1509788624276,"5208527028":1532526019715,"1020785020323":1478686416990,"1022429621161":1478686417016,"1021687564138":1480585069060,"5026467139":1514456869765,"1019612464019":1509788624312,"1021356878739":1478686417042,"1023153528505":1509788624958,"1022474188349":1478943089315,"1019271558994":1509788624312,"1022433946577":1478686417071,"1020294162519":1465470268294,"1864337888":1491634246534,"1024222928480":1509788667495,"1021733831679":1509788624513,"4994616992":1509788667399,"1021755458213":1478686417051,"1021736453104":1478686417124,"1019612856933":1509788625076,"1020976124195":1478686417087,"1022262109271":1478686804050,"1022372867575":1478686417204,"1022221346552":1478686417281,"1025680156821":1509788624351,"1023627735854":1509788624278,"1021396199519":1478686417106,"5026467028":1514456869765,"1022566986269":1509788625168,"1019197631307":1509788625086,"1024661746977":1509788624454,"1022811948000":1509788625102,"1007161022665":1478686804030,"1022811948003":1509788625102,"1023958683396":1509788625037,"1021968192956":1478686804029,"1021276008266":1478686416985,"1017072265659":1478686804031,"1024294755128":1509788625032,"1012354339486":1478686804021,"1023153528619":1509788624958,"464125139":1491634246534,"1021502894535":1478686417112,"1020953842183":1478686417000,"185855121":1444487341722,"1025538597306":1509788624311,"1016863336125":1478686804015,"1010091936090":1491634246528,"1019971476600":1480585069076,"1022016689024":1509788625067,"1000527696750":1444487341731,"1020940473223":1478686417084,"1024198938697":1509788667888,"1021091207820":1478686417094,"1022384795049":1478686417290,"1024576547533":1509788624462,"1022566986466":1509788624827,"1022228424402":1478686417065,"1006580251525":1478686804025,"1023549618020":1509788624817,"1024486240007":1509788624334,"1021049527400":1478686417036,"1007313317815":1478686804033,"1019859931997":1509788624322,"1022002533166":1478686417157,"1012883207099":1478686417074,"5026466884":1514456869765,"1021971862863":1478686417056,"4973121421":1509788624165,"1022600802501":1509788624206,"1021483889198":1478686417046,"1021475763122":1478686417242,"1022566986429":1509788624844,"5026466934":1514456869765,"1025538597315":1509788624300,"1025538597314":1509788624300,"1025538597312":1509788624282,"1025310678618":1509788624294,"1022069645058":1478686416979,"1021483889204":1478686417046,"1514651056":1491634246505,"1025538597316":1509788624281,"1022566986411":1509788624827,"1021483889208":1478686417046,"1021483889213":1478686417046,"1022451509706":1478686417302,"1022030191958":1478686417058,"1021417437663":1478686417106,"1019963871860":1478686804021,"1022002404586":1478686417157,"1025521429795":1509788624829,"1025521429797":1509788624824,"1025521429796":1509788624833,"1022002404572":1478686417157,"1022420051004":1478686417293,"1024233411017":1509788625017,"1019037068163":1509788625080,"123858721":1444487341727,"1021938440427":1478686417143,"1021938440418":1478686417143,"1021938440423":1478686417143,"1022081699953":1478686417178,"1012493538805":1478686417223,"1004329319944":1444487341711,"1022420051018":1478686417293,"1021926377222":1478686417010,"1019760576252":1465470268315,"1024926763769":1509788624530,"1024926763773":1509788624530,"1022365655339":1478686417204,"1021075477569":1465470268250,"1021234065117":1478686417039,"1023173579125":1509788625083,"1025627727036":1509788625022,"1002029295089":1478686417024,"1021687564603":1480585069060,"1018991978688":1509788624392,"1018991978715":1509788624391,"1021782724224":1509788624395,"1015835225088":1478686804065,"1025512910114":1509788624341,"4861577575":1509788624163,"1015592361549":1480585069063,"1025512910108":1509788624336,"1020074486122":1509788625081,"1542566723":1444487341700,"1019448505221":1478686804021,"363199763":1478686417018,"1024577856961":1509788624925,"1024661748429":1509788624500,"1024735411923":1509788667508,"1024735411922":1509788667507,"1025446979914":1509788624359,"1025446979919":1509788624359,"1024735411925":1509788667507,"1025446979918":1509788624359,"1024735411924":1509788667507,"1024735411931":1509788667507,"1024840529252":1509788624970,"1024735411935":1509788667507,"1023567444321":1509788624345,"1024454389253":1509788624975,"1022046183045":1478686804027,"1025521429976":1509788624201,"1024735411956":1509788667507,"1024608003942":1509788667589,"1024735411939":1509788667507,"1024735411938":1509788667507,"1024735411943":1509788667507,"1024183082502":1509788624923,"1024895699100":1509788624944,"1024535913230":1509788625070,"1024735411946":1509788667507,"1021604738165":1478686417246,"1024735411944":1509788667509,"970445015":1491634246519,"1024262771519":1509788624938,"1021929391698":1478686416981,"1024608003721":1509788667589,"1019166040809":1478686804020,"1024403794644":1509788624419,"1021353993364":1465470268228,"1022291209384":1478686417286,"1021353993360":1465470268227,"1021353993361":1465470268227,"1021353993362":1465470268228,"1022044348276":1478686417059,"1021353993363":1465470268228,"1024735411971":1509788667507,"1021618107603":1478686417117,"1024735411970":1509788667507,"1021618107600":1478686417117,"1024735411969":1509788667507,"1021353993359":1465470268227,"1021618107606":1478686417117,"1024735411974":1509788667507,"1024735411973":1509788667507,"1023054568244":1509788625048,"1026227111443":1514456869768,"1022181185394":1478686417187,"1004588306415":1444487341762,"1616873835":1478686804029,"1024737377996":1509788625018,"2373674053":1509976385181,"2373674052":1509976385181,"1019852200514":1509788625080,"1023994987382":1491634246532,"1021326729844":1465470268214,"1012265993826":1478686417025,"1021502636013":1509788625004,"1024403794585":1509788624819,"1021326729843":1465470268214,"1023994987386":1491634246532,"1012684103956":1478686417074,"1024403794569":1509788624193,"1012111855388":1478686417025,"1019028286299":1480585069073,"1303356615":1444487341722,"1017553159011":1509788624284,"1011344314709":1478686804022,"1004329320225":1444487341711,"1022850224113":1509788624234,"1022850224115":1509788624234,"1023286815176":1509788624869,"1022850224117":1509788624234,"1023286815183":1509788624869,"1022850224118":1509788624234,"1023286815180":1509788624869,"1021773156103":1509788625083,"1022850224121":1509788624234,"1022850224123":1509788624234,"1023286815169":1509788624869,"1022850224124":1509788624234,"1022850224127":1509788624234,"1023286815197":1509788624869,"1023286815186":1509788624869,"1023286815184":1509788624869,"1023286815190":1509788624869,"1021967932228":1509788624464,"1023286815211":1509788624869,"1022155887729":1509788624957,"1020551984365":1478686804031,"1024663845876":1509788624417,"1023286815215":1509788624869,"1019417703247":1509788624315,"1023835867158":1491634246504,"1023286815212":1509788624869,"1020861962586":1478686804039,"1022030847118":1509788624466,"1022081831317":1478686417062,"1023286815205":1509788624869,"1024663845880":1509788624417,"1008287165382":1478686804025,"1023286815218":1509788624869,"1024663845869":1509788624417,"1022253197914":1478686417196,"1023286815222":1509788624870,"1020551984368":1478686804031,"1022045265803":1478686417059,"1021838164835":1478686417134,"1022238649101":1509788624947,"1024403794462":1509788624533,"462287430":1491634246533,"1022238649102":1509788624931,"1022238649104":1509788624932,"1019562396567":1480585069070,"1023286815147":1509788624869,"1018674791600":1478686804024,"1023286815150":1509788624870,"1021821517897":1478686417132,"1021368411983":1478686417042,"1023286815163":1509788624869,"1022482053554":1478943089531,"1024597649371":1509788624939,"1023286815160":1509788624869,"1023286815166":1509788624869,"1023286815165":1509788624869,"428077179":1509788624366,"1025596400473":1509788624507,"1023286815154":1509788624870,"851958590":1509788625019,"1025477913131":1509788624369,"1025596400475":1509788624824,"1023286815153":1509788624870,"1023286815152":1509788624870,"1023286815156":1509788624869,"1023286815307":1509788624568,"1025267424350":1509788624999,"1023286815309":1509788624568,"1023286815297":1509788624568,"1023286815303":1509788624568,"1021390431614":1478686417042,"1023286815300":1509788624568,"1023286815322":1509788624569,"1021668297430":1478686416989,"1023286815325":1509788624569,"1023484733064":1509788624355,"1585165411":1444487341735,"1023484733063":1509788624355,"1023286815315":1509788624569,"1023484733062":1509788624355,"1585165409":1444487341715,"1019430940710":1478686804048,"1023484733061":1509788624355,"1023484733060":1509788624355,"1023484733059":1509788624355,"1023286815319":1509788624569,"1023484733058":1509788624355,"1023286815317":1509788624569,"1025516973918":1509788624308,"1021468688013":1509788624918,"1023484733103":1509788624355,"1023484733102":1509788624355,"1022065712386":1478686417270,"1023484733101":1509788624355,"367656922":1444487341725,"1023484733100":1509788624355,"1019364228102":1509788624315,"1023484733151":1509788624355,"1023484733150":1509788624355,"1023484733149":1509788624355,"1019767391344":1509788625081,"1019767391345":1509788624317,"1022460683725":1478686417298,"1025533750330":1509788624347,"1024913787704":1509788624375,"1022535792961":1480585069131,"1008898084262":1480585069067,"1024403794311":1509788625099,"1023286815258":1509788624569,"1021982087262":1509788624834,"1023286815263":1509788624569,"1022487296582":1478943089315,"1023561808830":1509788624191,"1022848912446":1509788624325,"1023286815253":1509788624568,"1023286815274":1509788624569,"1023286815279":1509788624569,"4994614231":1509788667398,"1023286815277":1509788624569,"1024661747729":1509788624906,"1023286815268":1509788624569,"1001797309788":1478686417023,"1023286815290":1509788624568,"1018922391064":1509788624309,"1023286815295":1509788624568,"1023286815293":1509788624569,"1023286815282":1509788624569,"1023286815281":1509788624569,"1020312643023":1465470268317,"1023484733154":1509788624355,"1023286815286":1509788624568,"1023484733153":1509788624355,"1023286815285":1509788624568,"1023484733152":1509788624355,"1022466319827":1478686417072,"1025372542617":1509788624307,"1021741960956":1509788624816,"1021771451450":1478686417128,"1022378893551":1509788624393,"1000526126690":1444487341713,"1020878084976":1509788624175,"1025269914808":1509788625008,"1021721512228":1478686804047,"1022378893562":1509788625017,"584697921":1491634246514,"1022378893553":1509788624393,"1022378893554":1509788624393,"1022378893557":1509788624393,"1022378893558":1509788624393,"1024384526425":1509788667499,"1012117228718":1478686417223,"1017322616675":1465470268241,"1015382508485":1465470268246,"1024384526423":1509788667499,"1021626365933":1509788624930,"1021234064392":1478686417039,"1024384526411":1509788667499,"1000526126686":1444487341739,"1025120487333":1509788624294,"1024632650381":1509788624990,"1022081045227":1478686417061,"1023286815375":1509788625170,"1023286815374":1509788625169,"1023286815386":1509788625170,"4994614115":1509788667398,"1023286815390":1509788625170,"1010093900916":1491634246522,"1010093900917":1491634246528,"1023286815379":1509788625170,"1023286815378":1509788625170,"1010093900920":1491634246528,"1023286815376":1509788625170,"1023286815380":1509788625170,"1023286815403":1509788625169,"1023286815401":1509788625169,"1023286815400":1509788625169,"1021036023924":1478686417300,"1023286815407":1509788625170,"1023286815406":1509788625170,"1023286815404":1509788625170,"1023286815395":1509788625169,"1023286815394":1509788625169,"1023286815393":1509788625169,"1023286815392":1509788625170,"1023286815399":1509788625169,"451932161":1491634246505,"1023286815397":1509788625170,"1021049917772":1478686417232,"1022421755656":1478686417210,"1023286815416":1509788625170,"1023286815423":1509788625170,"1023286815421":1509788625170,"1023286815411":1509788625170,"1025521430073":1509788624524,"1021929129045":1509788624465,"1020391423999":1478686804071,"1024183082492":1509788624923,"1024183082489":1509788624923,"1026226586683":1514456869793,"1025521430069":1509788624543,"1023995642117":1491634246530,"1025521430071":1509788624537,"1024183082481":1509788624923,"1024183082478":1509788624923,"1024183082476":1509788624923,"1024183082475":1509788624923,"1024183082462":1509788624923,"1024454389239":1509788624975,"1024183082458":1509788624923,"1024454389236":1509788624975,"1024454389242":1509788624975,"1024454389241":1509788624975,"1022142125992":1478686416975,"1024454389244":1509788624975,"1025521561093":1509788624800,"1021881288454":1509788624426,"1025521561091":1509788624824,"1015346072717":1478686804058,"1025521561089":1509788624829,"1021478649605":1478686417045,"1019102604523":1509788624314,"1021925459030":1478686417141,"1021902128587":1509788624399,"1024183082435":1509788624923,"1015868255653":1465470268260,"1021199855592":1465470268193,"1024608003279":1509788667589,"1021199855595":1465470268193,"1022880236480":1509788624542,"1024183082424":1509788624923,"1024183082422":1509788624923,"1021199855584":1465470268192,"1021345474382":1465470268225,"1024183082417":1509788624923,"1022454916273":1478686417072,"1021390431266":1478686417042,"1024183082412":1509788624923,"1024183082411":1509788624923,"1021881026401":1478686417137,"1021771451870":1478686417128,"1024183082398":1509788624923,"1024183082397":1509788624923,"1020865108931":1478686416988,"1016400137634":1480585069069,"1021881026384":1478686417137,"1024183082393":1509788624923,"1000936957946":1444487341754,"1000936957947":1444487341749,"1021199855583":1465470268192,"1022480743172":1478943089488,"1021199855576":1465470268192,"1021881026379":1478686417137,"1574680154":1491634246506,"1021137333225":1478686417002,"1024895831015":1509788624944,"1021137333228":1478686417002,"1023484733206":1509788624355,"1023484733205":1509788624355,"1023484733204":1509788624355,"4994613817":1509788667398,"1022670139521":1509788625074,"1020998800166":1478686417034,"1025521430185":1509788625108,"1025521430187":1509788625088,"1019028285863":1480585069073,"1574680133":1491634246506,"1022028881624":1509788624427,"1024913787601":1509788624375,"1020884900404":1478686417032,"1021390431444":1478686417042,"1020884900403":1478686417032,"1022235241131":1478686417193,"1021974878508":1509788624453,"1574680172":1491634246506,"1008904768564":1509788624388,"1024300258907":1509788624292,"1020742550441":1478686417028,"1024895831000":1509788624943,"1024895831005":1509788624944,"1024087006068":1509788624518,"1005662752015":1480585069065,"1021137333181":1478686417002,"1021515480098":1478686417047,"1021076789208":1478686417094,"1020888177313":1478686417032,"1021140085684":1478686417037,"1024608003171":1509788667589,"1021278233577":1478686417004,"1007095484564":1478686804023,"1023926570459":1491634246528,"1023926570460":1491634246528,"1020392472378":1478686804065,"1024615736117":1509788624224,"1019436971968":1509788624315,"1025783052672":1509788624295,"1021742745714":1478686804032,"1021018723739":1478686417090,"1018554337919":1509788624389,"1021742745717":1478686804032,"1025372147737":1509788624305,"1025685922626":1509788624309,"1024615736121":1509788624224,"1024615736120":1509788624224,"1024615736123":1509788624224,"1021018723735":1478686417090,"1024615736122":1509788624224,"1021390431074":1478686417042,"1024608002968":1509788667589,"1022811949217":1509788624421,"1022364738904":1480585069075,"1022811949220":1509788624421,"4961586065":1509788624163,"1024140746580":1509788624281,"1019298692662":1509788625078,"1019298692663":1509788625076,"1024140746578":1509788624281,"1019298692664":1509788625078,"1021468686487":1509788624918,"1025909928016":1509788667456,"1022421754297":1478686417210,"1025681859532":1509788624343,"1021226068347":1478686417003,"1005490272068":1478686417222,"1024140746559":1509788624926,"1024140746553":1509788625019,"1022956650612":1509788624420,"1021832660327":1478686804035,"1022811949261":1509788624420,"1022811949263":1509788624420,"1021997686613":1478686417156,"1021832660328":1478686804035,"1019436971967":1509788624313,"1022811949116":1509788624421,"1023175546472":1509788625043,"1021985234806":1478686417153,"1022811949106":1509788624421,"1022160867818":1478686417186,"1025720270288":1509788624346,"1021906190894":1509788624465,"1022579440143":1509788624424,"1024132489025":1509788624328,"1019195269259":1509788624321,"1299816909":1444487341748,"1022254378829":1509788624368,"1022254378830":1509788624368,"1021331972108":1509788624976,"1021331972111":1509788624976,"1021331972106":1509788624976,"1022811949169":1509788624421,"1021331972100":1509788624976,"1021278233801":1478686417004,"1021331972101":1509788624976,"1024572744044":1509788667537,"1021331972102":1509788624976,"4870885017":1509788624164,"1021331972103":1509788624976,"1024572744053":1509788667536,"1022453867207":1478686417215,"1022811949166":1509788624421,"1021278233817":1478686417004,"1024132489018":1509788624328,"1020769683114":1478686417029,"1021331972113":1509788624976,"1024572744056":1509788667536,"1024132489021":1509788624328,"1024615736277":1509788624563,"1024615736273":1509788624563,"1024615736272":1509788624563,"1016417438522":1509788624941,"1021461479365":1478686416980,"1025331517087":1509788624467,"1024615736269":1509788624563,"1024615736271":1509788624563,"1023145268263":1509788625045,"1023901927589":1509788625086,"1023901927594":1509788625085,"1010091934669":1491634246522,"1023901927596":1509788625085,"1023901927601":1509788625086,"1023901927600":1509788625086,"1010091934674":1491634246527,"1022397507166":1478686417070,"1020739798315":1478686417075,"1021992181389":1478686417155,"1018740464729":1509788624366,"1022633964618":1480585069095,"1016949582630":1478686804031,"1021325813263":1478686804040,"1021344162065":1478686417041,"1012961719546":1458304307281,"1021775121228":1478686804033,"1022397507168":1478686417070,"1021729902084":1509788624400,"1023901927569":1509788625086,"1021858743896":1478686417257,"1021858743900":1478686417257,"1022633964564":1480585069095,"102493020":1444487341733,"1025007504028":1509788624978,"1022633964573":1480585069095,"684311936":1478686804029,"1022633964569":1480585069095,"1021400530324":1478686417240,"1007370856031":1478686804025,"1025721449597":1509788624425,"1020294161401":1465470268294,"1017436900938":1478686804015,"1016558600739":1478686804024,"1025721449595":1509788624428,"1024983910521":1509788624924,"1022633964597":1480585069095,"1021386367696":1478686417006,"1022633964592":1480585069095,"1023549750739":1509788624858,"1023549750736":1509788624858,"1004329319208":1444487341711,"1023549750735":1509788624858,"1023549750734":1509788624858,"1023549750733":1509788624858,"1021386367681":1478686417006,"1022633964576":1480585069095,"1022288848966":1478686417068,"1024926764814":1509788624530,"1025300059587":1509788624298,"1019066820733":1509788624309,"1024926764806":1509788624530,"1022811949355":1509788624183,"1004329319362":1444487341711,"1024186751801":1509788624616,"1000526125379":1444487341731,"1021694281":1478950494920,"1025721449601":1509788624406,"1022209551667":1509788624938,"1022209551672":1509788624938,"1021613650363":1478686417008,"1023602572836":1509788624949,"1025737310106":1509788624346,"1025504389625":1509788624295,"1021136809303":1478686417037,"1021283476501":1478686417040,"1025504389624":1509788624295,"1022176858967":1478686417187,"1025504389626":1509788624295,"1020052738756":1509788624281,"1022873421095":1509788624426,"1025300059522":1509788624297,"4994614368":1509788667398,"1021022655624":1478686417035,"1008020840331":1478686804023,"1008287035293":1478686804030,"1025504389595":1509788624295,"1019132486668":1509788624313,"1025504389591":1509788624295,"1025504389590":1509788624295,"1021390430876":1478686417042,"1020294030144":1465470268282,"1019717715701":1509788625077,"1025504389579":1509788624296,"1025504389578":1509788624295,"1021460561631":1478686417108,"1022155886633":1509788624957,"1009120778590":1478686804030,"1019310358195":1509788625078,"1025504389693":1509788624296,"1025504389692":1509788624296,"1025504389695":1509788624296,"1022390560211":1478686417206,"1025504389673":1509788624296,"1013667458483":1478686804016,"1025504389668":1509788624296,"1024608002453":1509788667589,"4994615213":1509788667398,"1025504389663":1509788624296,"1020305301543":1478686804049,"1025504389655":1509788624297,"1025504389654":1509788624296,"1022043822162":1478686417059,"1021570790536":1478686417245,"1025504389754":1509788624297,"1025504389749":1509788624297,"4561166739":1465469681389,"1024663845895":1509788624417,"1024663845894":1509788624417,"1024663845893":1509788624417,"1025504389742":1509788624297,"1024663845891":1509788624417,"1007584507400":1478950494939,"1022328957241":1478686417288,"1025504389729":1509788624297,"1025504389728":1509788624297,"1021978549286":1478686417150,"1012593798622":1478686416977,"1021990739211":1478686417155,"154396602":1444487341746,"1021052802331":1478686417036,"856939928":1491634246514,"1021037466866":1465470268183,"1012418434736":1478686417074,"1009710790933":1480585069062,"720356448":1478950494915,"1024334467438":1509788625032,"1024608002332":1509788667589,"1022181183730":1478686417187,"1025504389788":1509788624297,"1024615735700":1509788624449,"1024615735703":1509788624449,"1024615735702":1509788624449,"1025504389784":1509788624297,"1025504389783":1509788624297,"1024615735711":1509788624449,"1024615735704":1509788624449,"4994615069":1509788667398,"1988991036":1444487341745,"1019230265476":1509788624373,"1293525979":1444487341754,"1009744475997":1491634246512,"1021261851096":1478686804047,"1021647204545":1509788625020,"1001366865954":1480585069061,"1022410613343":1478686417292,"4965648665":1509788624163,"1021487954786":1478686417046,"1021594252748":1478686417114,"1021481794311":1478686417110,"1025504389848":1509788624295,"1022412579477":1478686417208,"134604541":1444487341721,"1025504389831":1509788624295,"1025504389830":1509788624295,"1021974879330":1509788624426,"1012037144055":1478686804015,"1021288851044":1478686417004,"1021739207557":1478686417124,"1020865372073":1478686416999,"1024779712085":1509788625003,"1020865372071":1478686416999,"1020865372064":1478686416999,"1024270505143":1509788624174,"1020865372067":1478686416999,"1021379158332":1478686804033,"1020865372062":1478686416999,"1026225012748":1514456869772,"1026225012750":1514456869772,"1022033336880":1478686417166,"1433647688":1444487341721,"1021769353697":1478686417254,"1022032419407":1478686417166,"1017113296644":1480585069063,"1022038972911":1478686417011,"1022956651350":1509788624818,"1025284331529":1509788624249,"1825801093":1478686804033,"1012166379108":1478686417223,"1021182946488":1478686417003,"1015835225086":1478686804065,"1019704345759":1509788624367,"1024917851714":1509788624926,"1000526125980":1444487341713,"1021827810874":1478686417256,"1021557421574":1478686417245,"1021557421570":1478686417245,"1025152204979":1509788624269,"1020667317223":1478686804059,"1024579035852":1509788624925,"1025152204982":1509788624268,"1025152204981":1509788624269,"1000526125944":1444487341714,"1007161544959":1478686804023,"1021622956557":1478686417247,"1000526125939":1444487341718,"1025628513100":1509788625087,"1021391479004":1478686416979,"1025628513099":1509788625107,"1025628513098":1509788625124,"1025628513097":1509788625115,"1015365338894":1465470268263,"4982687587":1509788624162,"1025002391982":1509788624462,"1024088055610":1509788624467,"1022045919735":1478686417269,"1021871850348":1509788624402,"1021546936264":1509788624397,"1022173581690":1478686417186,"1024664239549":1509788625025,"1022032419554":1478686417166,"1021234063698":1478686417039,"1022329088151":1478686417201,"1024686384383":1509788625005,"1011593738054":1478686417220,"1001087165843":1478686417022,"1016538816143":1478686804069,"1016538816142":1478686804069,"1024926765701":1509788624530,"1021588351883":1509788624397,"1016538816147":1478686804069,"1016538816146":1478686804069,"1016538816145":1478686804069,"1016538816144":1478686804069,"1016538816151":1478686804069,"1016538816150":1478686804069,"1016538816149":1478686804069,"1016538816148":1478686804069,"1016538816155":1478686804069,"1019903838196":1509788625019,"1016538816154":1478686804069,"1016538816153":1478686804069,"1016538816152":1478686804069,"1016538816159":1478686804069,"1016538816158":1478686804069,"1016538816157":1478686804069,"1024687695081":1509788625212,"1024300256721":1509788624298,"4968536081":1509788624164,"1025100438631":1509788624173,"1025133600360":1509788624307,"1021965173113":1478686417148,"1022460821461":1480585069117,"1012118410820":1478686416993,"1022460821469":1480585069117,"1021362257245":1478686416981,"1000307758666":1478686417018,"1022460821464":1480585069117,"1026232352953":1514456869769,"1022460821478":1480585069117,"1018814514847":1509788624929,"1026232352952":1514456869770,"772267621":1444487341735,"1022460821477":1480585069117,"1026232352955":1514456869769,"1022460821476":1480585069117,"1024936333946":1509788625006,"1026232352954":1514456869769,"1026232352957":1514456869768,"1012148033591":1478686417223,"1026232352956":1514456869769,"1016092517214":1509788624941,"1022455316371":1478686417216,"1024686908570":1509788625102,"1021626232117":1478686417008,"1021966745964":1478686417262,"1022338136200":1478686417069,"1020294037055":1465470268283,"1021987062611":1478686417264,"1019581535157":1509788624354,"1013504084467":1478686804054,"1009446156250":1478686804055,"1009446156251":1478686804055,"1024652698185":1509788624171,"1020438079129":1478686804027,"1021226071439":1478686417003,"1022186426193":1478686417278,"1022431460862":1478686417212,"1024055942700":1509788624928,"1023627732185":1509788624278,"1025219445755":1509788624433,"1023627732189":1509788624278,"1023627732191":1509788624278,"1025219445759":1509788624434,"1025219445758":1509788624424,"1023627732183":1509788624278,"1025219445751":1509788624510,"1023627732182":1509788624278,"1025219445750":1509788624510,"1021323590552":1465470268210,"100660521":1444487341704,"1021323590549":1465470268210,"1021323590547":1465470268210,"1022486241509":1509788625075,"1023627732208":1509788624277,"1023627732212":1509788624278,"1022096247218":1478686417181,"1023627732203":1509788624278,"1023924606645":1509788624960,"1023627732207":1509788624277,"1023627732198":1509788624278,"1019125283190":1509788625080,"1017142125445":1478686804022,"916834217":1478950494918,"1012148033864":1478686417223,"1021825456198":1509788624995,"1001087165625":1478686417022,"1021825456196":1509788624995,"1024300256452":1509788624298,"1017190884493":1478686804015,"1012800896614":1478686417074,"1021825456201":1509788624995,"4556586670":1465469681388,"1021398294977":1478686417106,"1021605391803":1509788624860,"1009775405722":1478686804025,"1021605391806":1509788624860,"1025711481082":1509788624346,"1021605391807":1509788624860,"1018739933196":1509788624367,"1021605391810":1509788624860,"1020437030759":1478686804029,"1019166177964":1478686804020,"1013102481469":1478686804016,"1014038522054":1478686804016,"1012148033792":1478686417223,"1585557465":1444487341733,"1000145759452":1478686804029,"1009078435915":1478686804023,"1020975859565":1478686417087,"1021483099325":1478686417110,"1024096960886":1509788624325,"1021206410545":1478686417038,"1538894393":1444487341702,"1025010259488":1509788624598,"1025010259491":1509788624598,"1025010259492":1509788624598,"1001087165454":1478686417022,"1025010259494":1509788624598,"1021471827202":1478686417045,"1025010259497":1509788624598,"1025010259496":1509788624598,"1024782198967":1509788625021,"1016877888489":1478686804019,"1011767665478":1478686804051,"1025010259472":1509788624598,"1011767665474":1478686804051,"1025010259477":1509788624598,"1011767665472":1478686804051,"1011767665484":1478686804051,"1025010259483":1509788624598,"1025010259485":1509788624598,"1025010259484":1509788624598,"1011767665480":1478686804051,"1025010259486":1509788624598,"1025010259457":1509788624598,"1028052069874":1532526019715,"1025010259459":1509788624598,"1020923036315":1478686417033,"1020923036310":1478686417033,"1025010259467":1509788624598,"1025010259469":1509788624598,"1021721383431":1478686804047,"1025010259468":1509788624598,"1025010259471":1509788624598,"1025010259470":1509788624598,"1005848215571":1509788624373,"1025010259568":1509788624494,"1020783581781":1478686417225,"1025100438913":1509788624273,"1025010259552":1509788624494,"1025010259555":1509788624494,"1025010259561":1509788624494,"1025010259563":1509788624495,"1025010259564":1509788624494,"1025010259567":1509788624494,"1025010259566":1509788624495,"1025010259537":1509788624495,"1025010259536":1509788624495,"1025010259540":1509788624495,"1021742749078":1478686804032,"1025010259543":1509788624495,"1021742749079":1478686804032,"1025010259547":1509788624495,"1025010259546":1509788624495,"1021887716416":1478686804049,"1025010259549":1509788624494,"1025010259551":1509788624494,"271049174":1478686416992,"1025010259525":1509788624494,"1025010259530":1509788624495,"1025010259532":1509788624495,"1025010259535":1509788624495,"1025010259534":1509788624495,"1020880831440":1478686417079,"715774123":1444487341746,"1024055942289":1509788624928,"1024313495354":1509788624926,"1022461607327":1478686417298,"1024322800770":1509788667508,"1024322800769":1509788667508,"1021413762023":1478686417106,"1020880831455":1478686417079,"1021647465488":1509788624396,"1022461607311":1478686417298,"1024470382026":1509788625003,"1022549288537":1509788624386,"1022549288536":1509788624386,"1025911631854":1509788667466,"1024008886618":1509788667494,"1020880831436":1478686417079,"1024528447573":1509788625175,"1021693465437":1478686417121,"1021811300985":1478686417052,"1001087166371":1478686417022,"1025874798647":1509788667683,"120321386":1506424601447,"1020878472113":1509788624934,"1022075931352":1509788624416,"1025010259453":1509788624598,"1025010259452":1509788624598,"1025010259455":1509788624598,"1021251368433":1478686417236,"1021530285388":1509788624433,"1022200712535":1478686416978,"1024895832628":1509788624943,"1025593653395":1509788624201,"1021990470102":1509788625067,"1024895832632":1509788624943,"1021462782300":1478686417108,"1022037918853":1478686417167,"1025593653398":1509788624186,"1025593653397":1509788624198,"1008495574448":1478686804064,"1025593653396":1509788624204,"4994620397":1509788667399,"1021251368413":1478686417236,"1021251368411":1478686417236,"1018421832750":1480585069059,"1022384797797":1478686417290,"1021755070431":1478686417051,"1366270720":1491634246520,"1025296648943":1509788624511,"1021989028311":1478686416976,"1022112761911":1478686417182,"1022458330585":1478686417072,"1021530285413":1509788624423,"1022112761913":1478686417182,"1021827685313":1509788624897,"1021832666006":1478686804035,"1021832666007":1478686804035,"1021827685315":1509788624897,"1021827685317":1509788624896,"1021827685318":1509788624897,"1025300056771":1509788624297,"1021827685320":1509788624897,"1024055942171":1509788624928,"1021827685321":1509788624896,"1019006530530":1509788624316,"1021827685322":1509788624896,"1021967139739":1478686417148,"1021827685323":1509788624896,"1021827685324":1509788624896,"1021827685325":1509788624896,"1025902325480":1509788667449,"1021827685326":1509788624896,"1021827685328":1509788624896,"1021827685329":1509788624896,"1021827685330":1509788624896,"1021827685331":1509788624896,"1022166765466":1478686417186,"1023864967520":1509788624927,"1021827685334":1509788624897,"1021827685335":1509788624897,"1021501318216":1478686416982,"1021206542063":1478686417099,"1020878472025":1509788624934,"1021206542072":1478686417099,"1024538147175":1509788624429,"1021974872107":1509788624435,"1021206542066":1478686417099,"1021206542064":1478686417099,"1024538147177":1509788624426,"1024538147176":1509788624432,"1024538147178":1509788624408,"1025864968192":1509788667512,"1024016883207":1509788625147,"1015868257369":1465470268260,"1022021535518":1509788624181,"1024016883212":1509788625147,"1022021535515":1509788624179,"1024016883210":1509788625147,"1024016883209":1509788625147,"1024016883208":1509788625147,"1025524970547":1509788624523,"1025524970550":1509788624523,"1025524970549":1509788624523,"1025524970548":1509788624523,"1021589530959":1478686417246,"1018814514215":1509788624929,"1018509513171":1509788624426,"1025609775400":1509788624824,"1022339447325":1478686417015,"1022410227307":1478686417070,"1022351768294":1478686417203,"1024454390832":1509788624975,"1022410227308":1478686417070,"1001544204972":1478686804029,"1022351768298":1478686417203,"540791498":1509788624362,"1024322800762":1509788667508,"1024454390817":1509788624975,"1024454390816":1509788624975,"1024322800767":1509788667508,"1024454390822":1509788624975,"1024322800765":1509788667508,"1022410227314":1478686417070,"1024454390826":1509788624975,"1022195076484":1509788624820,"1021231969338":1478686417099,"1024454390831":1509788624975,"1021827685310":1509788624896,"1024055942545":1509788624928,"1020850691224":1478686804057,"1019811431069":1465470268320,"1022172532164":1509788625231,"1022172532165":1509788625232,"1022172532162":1509788625231,"1409787678":1509788625020,"1024247171604":1509788625070,"1022451514644":1478686417215,"1025628651510":1509788624540,"1022371166683":1478686417069,"1022371166681":1478686417069,"1021329883096":1478686417041,"1022491091594":1478943089490,"1025300056854":1509788624297,"1022172532150":1509788625231,"1022172532151":1509788625231,"1023730886801":1509788624960,"1022172532148":1509788625231,"1022172532149":1509788625231,"1022172532144":1509788625231,"1022220169879":1478686417192,"1002455536768":1491634246518,"1022058759415":1475218613699,"1022172532159":1509788625232,"1022172532156":1509788625231,"1022172532157":1509788625231,"1022172532155":1509788625231,"1022172532135":1509788625232,"1022172532133":1509788625231,"1023384991207":1509788624969,"1022172532142":1509788625232,"1022172532140":1509788625232,"1022172532141":1509788625232,"4994620105":1509788667398,"1022544308208":1509788625063,"1022172532136":1509788625231,"1022172532137":1509788625232,"1019541557766":1509788625077,"1012972071604":1478686804025,"1023071600819":1509788624220,"1023071600817":1509788624220,"1023071600816":1509788624220,"1021984833654":1478686417264,"1023071600815":1509788624220,"1022486242194":1478943089489,"1023071600813":1509788624220,"1021984833653":1478686417264,"1020784761083":1478686804040,"1023549350717":1509788625158,"1023549350716":1509788625157,"1023549350718":1509788625157,"1024055942414":1509788624928,"1023549350715":1509788625157,"1022142517052":1478686417277,"1012413713354":1478686417074,"4994619906":1509788667398,"1025628651375":1509788624746,"1024002725891":1491634246532,"1025628651369":1509788624828,"1024002725889":1491634246532,"1025628651370":1509788624832,"1021901741372":1478686417054,"1024273254486":1509788624277,"1024686384942":1509788624997,"1024686384940":1509788625005,"1020610040336":1509788624353,"1023549350721":1509788625157,"1021314021387":1478686417041,"1021869891382":1478686416983,"1024221875044":1509788624925,"1009998093434":1491634246524,"1024936334865":1509788625006,"1024008888137":1509788667493,"1025532048029":1509788624297,"1024786132705":1509788624406,"1021289512292":1478686417237,"1025607941632":1509788624407,"1021887715769":1478686804065,"1020935487620":1478686417228,"1021239439979":1478686417003,"1532997503":1491634246519,"1024016881903":1509788624444,"1024016881910":1509788624444,"1024016881909":1509788624444,"1024016881908":1509788624444,"1019448504068":1478686804021,"1025532048035":1509788624297,"1024016881907":1509788624444,"1025532048032":1509788624297,"1020850690980":1478686804057,"1126414111":1491634246535,"1021609322500":1478686417049,"1021609322501":1478686417049,"1025428108527":1509788624511,"1021609322510":1478686417049,"1021609322511":1478686417049,"1021609322506":1478686417049,"1021388078022":1478686417240,"1025428108539":1509788624424,"1025428108538":1509788624433,"1025428108542":1509788624434,"1025428108531":1509788624433,"1025428108530":1509788624510,"1024528449042":1509788625175,"1002035722575":1478686417024,"1022498956575":1509788624969,"1021740388597":1509788624395,"1020884239846":1478686417032,"1022646677014":1480585069091,"1024686907506":1509788624420,"1022646677019":1480585069150,"1020294167073":1465470268295,"1022646677023":1480585069091,"1021887715619":1478686804050,"1022646677020":1480585069091,"1022646676996":1480585069150,"1022646677003":1480585069090,"1022501447072":1509788624538,"1004039516451":1480585069064,"1020953706941":1478686417085,"1023071602681":1509788624856,"1020953706930":1478686417085,"1023071602677":1509788624856,"1021869627403":1478686804033,"1023071602676":1509788624856,"1023071602675":1509788624856,"1020953706934":1478686417085,"1023071602672":1509788624856,"1022455577381":1478686417072,"1022501447150":1509788624538,"1023949118509":1509788667493,"1023973760420":1509788625017,"1021435258490":1478686417044,"1021175346886":1465470268187,"1021175346882":1465470268187,"1025405700859":1509788624387,"1025405700858":1509788624387,"1021789410157":1509788624815,"1025405700857":1509788624387,"1025405700856":1509788624387,"1025405700855":1509788624387,"1025405700854":1509788624387,"1025405700853":1509788624387,"1025405700851":1509788624387,"1025405700850":1509788624387,"1025405700849":1509788624387,"1021175346889":1465470268187,"1025405700848":1509788624387,"1025329811050":1509788625099,"1012945595480":1478686417074,"1025405700847":1509788624387,"1025405700846":1509788624387,"1023958162614":1509788667535,"1025405700845":1509788624387,"1025405700844":1509788624387,"1025405700843":1509788624387,"1025405700842":1509788624387,"1025405700841":1509788624387,"1025405700840":1509788624387,"1025405700839":1509788624387,"1025405700895":1509788624387,"1025405700894":1509788624387,"1025405700893":1509788624387,"1025405700892":1509788624387,"1025405700891":1509788624387,"1025405700890":1509788624387,"1025405700889":1509788624387,"1025405700888":1509788624387,"1025405700887":1509788624387,"1024462386001":1509788624558,"1025405700886":1509788624387,"1025405700885":1509788624387,"1024462386003":1509788624558,"1025405700884":1509788624387,"1024462386002":1509788624558,"1025405700883":1509788624387,"1024462386005":1509788624558,"1024462386004":1509788624558,"1025911630052":1509788667467,"1020390498808":1478686804071,"1021962028117":1478686417262,"1024300386558":1509788624292,"1022127050316":1509788624338,"1024016882159":1509788624554,"1020547655847":1509788624934,"1025314213055":1509788624308,"1009269934324":1509788624390,"1024016882163":1509788624554,"1024016882162":1509788624554,"1024016882161":1509788624554,"1024016882160":1509788624554,"1025405700902":1509788624386,"1025405700901":1509788624387,"1025405700900":1509788624387,"1025405700899":1509788624387,"1025405700898":1509788624387,"1025405700897":1509788624386,"1025405700896":1509788624386,"1024016882055":1509788624217,"1024016882054":1509788624217,"1025791696991":1509788624511,"331081469":1478686804046,"1024016882061":1509788624217,"1024016882057":1509788624217,"1024016882056":1509788624217,"117961297":1500459286943,"1020504797030":1478686804031,"1021119122112":1478686417095,"1022431459367":1478686417016,"1024132351620":1509788624326,"1011593736739":1478686417220,"1025791697013":1509788624507,"1024132351628":1509788624326,"1024132351631":1509788624326,"1024132351630":1509788624326,"1024132351625":1509788624326,"1025791697001":1509788624441,"1024132351635":1509788624326,"1009162453846":1509788624388,"1025791696999":1509788624423,"1025791696998":1509788624466,"1022746416637":1509788625016,"1021789410037":1509788624194,"1025791696992":1509788624511,"1025428108584":1509788624437,"1021004303862":1478686417035,"1021004303858":1478686417035,"1021004303859":1478686417035,"1025428108576":1509788624432,"1022191274558":1478686417188,"1025428108579":1509788624432,"1025671248800":1509788624186,"1023830103138":1509788625038,"1025428108580":1509788624432,"1025428108583":1509788624437,"1019118599499":1509788624314,"1015155109519":1444487341759,"1020884239371":1478686417032,"295429120":1444487341727,"1020234006489":1465470268312,"1025428108555":1509788624432,"1007298114281":1478686804015,"1022589657695":1509788625062,"1025428108545":1509788624427,"1022886010247":1509788625018,"1021992306236":1478686417057,"1008286775252":1478686804030,"1025485780727":1509788624431,"1022235243702":1478686417193,"1019297507231":1509788624376,"1025485780726":1509788624429,"1025671248794":1509788624197,"1025671248793":1509788624204,"1025671248792":1509788624200,"1025428108570":1509788624432,"1025671248797":1509788625087,"1024341281323":1509788625071,"1025428108565":1509788624432,"1024884828854":1509788625024,"1025671248790":1509788625106,"1025671248789":1509788625124,"1025428108566":1509788624432,"1025671248788":1509788625115,"1022238783234":1509788624947,"1021681276381":1478686417120,"1022238783237":1509788624931,"1025428108640":1509788625126,"1025428108645":1509788625136,"1015563911538":1478686804027,"4994620541":1509788667399,"1022338923803":1478686417015,"1021681669569":1509788624426,"450752260":1444487341748,"1025512648805":1509788624337,"1025512648804":1509788624340,"1022021402632":1509788624179,"1025428108621":1509788625245,"1025428108622":1509788625245,"1021689009262":1478686417121,"1014712874137":1480585069067,"1022230262952":1478686417065,"1025428108633":1509788625126,"1025428108632":1509788625126,"1025428108637":1509788625126,"1025428108636":1509788625126,"1025428108638":1509788625126,"1025428108625":1509788625128,"1025428108624":1509788625128,"1025428108626":1509788625104,"1025428108629":1509788625112,"1025428108628":1509788625129,"1025428108630":1509788625126,"1008898085348":1480585069067,"1021789409690":1509788624533,"1021962946374":1478686417148,"1025074879944":1509788624999,"1021359766276":1478686417006,"1022444173477":1478686417295,"1023796029491":1509788625102,"1019102867853":1509788624317,"4839560796":1509788624165,"1021081766899":1478686417094,"1021550604265":1478686804067,"1025671247898":1509788624537,"1025671247897":1509788624542,"1025671247896":1509788624540,"1025671247903":1509788624523,"1021460555038":1478686417044,"1021311269937":1465470268205,"1023071602047":1509788624561,"1023071602046":1509788624561,"1024453079174":1509788625030,"1023071602044":1509788624561,"1024879192359":1509788625069,"1022850224161":1509788624234,"1022850224160":1509788624234,"1022850224163":1509788624234,"1022850224162":1509788624234,"1022850224164":1509788624234,"1020963274909":1478686417085,"1021962946352":1478686417148,"1022850224144":1509788624234,"1022850224150":1509788624234,"1022850224154":1509788624234,"1022850224158":1509788624234,"1022850224129":1509788624234,"1022850224131":1509788624234,"1022850224132":1509788624234,"1022850224134":1509788624234,"1020288793449":1509788624436,"1022850224136":1509788624234,"1025521562445":1509788624524,"1022850224138":1509788624234,"1023093359502":1509788624385,"1023093359501":1509788624385,"1021962946351":1478686417148,"1022059413779":1478686417060,"1017142125581":1478686804022,"1025035427508":1509788624269,"1025906649765":1509788667461,"1021311794313":1478686804018,"1010091939921":1491634246522,"1010091939925":1491634246522,"1024686908014":1509788624818,"1021189109200":1465470268190,"1019297506448":1509788624375,"1021189109201":1465470268190,"1019297506449":1509788624375,"1021189109202":1465470268191,"1019297506450":1509788624375,"1019899511030":1509788624940,"1022400789917":1478686804071,"1024688349807":1509788624592,"1025485780457":1509788625125,"1022470519202":1478686804049,"1025485780456":1509788625117,"1025485780458":1509788625109,"1025485780461":1509788625088,"1020886730700":1478686417227,"1023796029611":1509788624534,"1001087165220":1478686417022,"1023071602050":1509788624561,"1019297506446":1509788624375,"1019297506447":1509788624375,"1023071602048":1509788624561,"1024098797351":1509788625036,"1013902075754":1478686804071,"1025296649813":1509788624512,"1010538626795":1478686804024,"1022226200399":1478686416985,"1022226200398":1478686416985,"1025900358239":1509788667461,"1021953509152":1478686417146,"1020390498831":1478686804016,"1025900358241":1509788667460,"1023796029685":1509788624195,"1021413762825":1478686417106,"1022309560423":1478686417199,"1021606177388":1480585069071,"1019611550597":1509788624392,"1019611550598":1509788624392,"1021304192400":1478686417102,"1019360944449":1465470268242,"1019360944451":1465470268273,"1022501447216":1509788624538,"1019360944453":1465470268242,"449965532":1491634246519,"1024686908391":1509788624534,"1020858947607":1478686417031,"1025219445790":1509788624437,"1025428109185":1509788624373,"1023958163307":1509788667535,"1012583708023":1478686417223,"1021741306714":1478686417253,"1021632784855":1509788624401,"1025219445774":1509788624432,"1025219445761":1509788624427,"1025219445763":1509788624432,"1025219445762":1509788624432,"1024517832111":1509788625028,"1024008887312":1509788667494,"1025608072380":1509788624186,"1025809129798":1509788667443,"1020773358945":1478686417076,"1025608072372":1509788624204,"1025608072371":1509788624200,"482864025":1478686804068,"1022646676979":1480585069117,"1025219445850":1509788625135,"1022646676981":1480585069090,"1025219445840":1509788625126,"1024273255669":1509788624277,"1025219445845":1509788625126,"1025604271431":1509788625084,"1025219445846":1509788625126,"1020790529092":1478686417029,"1025219445835":1509788625129,"1023821453081":1491634246536,"1025521562179":1509788624205,"1022646676966":1480585069090,"1025219445839":1509788625126,"4985839195":1508316495865,"1025219445825":1509788625245,"1022646676969":1480585069090,"1021425296935":1509788624977,"1025219445829":1509788625245,"1022055874775":1478686417059,"1022646676973":1480585069090,"1017142125835":1478686804022,"1023540312236":1509788625008,"1024452292983":1509788667888,"1019612598991":1509788624366,"4994620981":1509788667395,"1025874800014":1509788667684,"1025874800002":1509788667684,"1022068723560":1478686417060,"1022073311027":1478686417012,"1021831880335":1478686417134,"1024016882517":1509788624852,"1024016882516":1509788624852,"1024528448986":1509788625175,"1024016882515":1509788624852,"1024016882513":1509788624852,"1024016882527":1509788624852,"1024462254591":1509788624973,"1024943936545":1509788624978,"1024183861588":1509788624517,"1024183861594":1509788624517,"1021906196760":1478686417140,"1004787009214":1480585069067,"1021887715868":1478686804065,"1021501448549":1478686417007,"4968538003":1509788624160,"1021285056005":1465469681396,"1012739030181":1478686804017,"1024528448905":1509788624471,"1024528448904":1509788624471,"1023071601918":1509788625155,"1024528448907":1509788624471,"1024528448906":1509788624471,"1021890599492":1478686417054,"1024528448909":1509788624471,"1024528448908":1509788624471,"1024528448911":1509788624471,"1024530415084":1509788624477,"1023071601912":1509788625155,"1024528448897":1509788624471,"1023071601911":1509788625156,"1023071601910":1509788625156,"1025428109154":1509788624363,"1024528448898":1509788624471,"1024528448901":1509788624471,"1025428109156":1509788624367,"1023071601906":1509788625155,"1000356388549":1478950494932,"1024528448903":1509788624471,"1024528448902":1509788624471,"1024528448923":1509788624471,"1024530415091":1509788624413,"1024528448913":1509788624471,"1021359766270":1478686417006,"1006898616547":1509788624388,"1024528448919":1509788624471,"1024528448918":1509788624471,"1024528448936":1509788624471,"1025607941619":1509788624428,"1024528448938":1509788624471,"1022092316282":1478686417012,"482863907":1478686804068,"1021776040336":1509788624395,"1025607941621":1509788624425,"1024528448941":1509788624471,"1025607941620":1509788624431,"1024528448940":1509788624471,"1024528448943":1509788624471,"1024528448942":1509788624471,"1024528448928":1509788624471,"1010812694048":1509788624276,"1023821453213":1491634246536,"1024745627780":1509788624342,"1025100438438":1509788624181,"1022073311040":1478686417012,"1025191527743":1509788624922,"1025874800117":1509788667845,"1021025272118":1509788624276,"1024333154286":1509788625031,"472245281":1478686804033,"1021000237235":1478686417230,"1022080254045":1509788624190,"1022053388244":1478686417172,"1022646936135":1480585069154,"1022646936131":1480585069154,"1024161713163":1509788667562,"1700896078":1491634246508,"1021936339080":1509788624978,"1022646936106":1480585069154,"1023926574702":1491634246528,"1022646936098":1480585069154,"1022291213814":1478686417286,"1022646936119":1480585069154,"1021709720084":1509788624396,"1022646936112":1480585069154,"1022646936077":1480585069154,"1022646936075":1480585069154,"1008058190972":1480585069066,"1008058190974":1480585069066,"1023821453317":1491634246536,"1022000302966":1478686417157,"1022646936066":1480585069154,"1022646936065":1480585069154,"1022646936094":1480585069154,"1022646936092":1480585069154,"1021882209399":1478686417137,"1022646936084":1480585069154,"1020995911816":1478686417088,"1022646936082":1480585069154,"1021750615429":1509788624395,"1022000302949":1478686417157,"1022646936080":1480585069154,"1022646936299":1480585069155,"1022460688140":1478686417298,"1021696219580":1509788624404,"1022646936295":1480585069155,"1022646936293":1480585069155,"1022646936288":1480585069155,"1022646936316":1480585069155,"1025910842736":1509788667459,"1021977103085":1478686417010,"1022646936313":1480585069155,"1024462520001":1509788624987,"1024502100333":1509788625070,"1022646936310":1480585069155,"1025500724460":1509788624295,"1022646936308":1480585069155,"1022646936307":1480585069155,"1021195533199":1464448510787,"1022646936305":1480585069155,"1024132352833":1509788624324,"1024132352832":1509788624324,"1024132352844":1509788624324,"1020836009687":1478686417078,"1024132352841":1509788624324,"1021226073489":1478686417003,"1020251829219":1465470268317,"1022646936284":1480585069155,"1021576028917":1509788624401,"1022646936281":1480585069155,"1022646936280":1480585069155,"1022711162380":1509788624349,"1025296646181":1509788624507,"1022646936239":1480585069154,"1020087728603":1509788625078,"1020087728600":1509788625078,"1022646936236":1480585069154,"1022646936235":1480585069154,"1022646936234":1480585069154,"1022646936233":1480585069154,"1022646936229":1480585069154,"5208526527":1532526019715,"1021299995162":1480585069071,"1022646936225":1480585069154,"1020792492999":1478686804039,"1024132352822":1509788624325,"1021846819567":1509788625084,"1024132352818":1509788624324,"1022646936247":1480585069155,"1022646936246":1480585069155,"1018179348483":1509788624284,"1024132352828":1509788624325,"1022646936244":1480585069155,"1299428782":1444487341747,"1022646936242":1480585069155,"1009839499049":1491634246520,"1022646936241":1480585069155,"1022646936205":1480585069154,"1023277905943":1509788625041,"1024161713357":1509788667562,"1022646936197":1480585069154,"1025596797527":1509788624930,"4965654280":1509788624159,"1024926767739":1509788624189,"1017230733235":1465470268315,"1022646936221":1480585069154,"1024926767740":1509788624189,"1023165841787":1509788625044,"1022646936212":1480585069154,"1022646936431":1480585069155,"1021195532816":1464448510787,"1021152934042":1465470268183,"1009264952585":1478686804055,"1023154045270":1509788624325,"1022065708597":1478686417175,"1022646936422":1480585069155,"1022646936419":1480585069155,"1018194946244":1509788624284,"1022646936416":1480585069155,"1020886730859":1509788624176,"1020886730862":1509788624177,"1020886730860":1509788624177,"1020886730861":1509788624177,"1022646936434":1480585069155,"1025671247627":1509788624428,"1025671247630":1509788624406,"1025671247629":1509788624425,"1022646936392":1480585069155,"1025671247628":1509788624431,"1021944990061":1478686417144,"1022646936388":1480585069155,"1023949115866":1509788667493,"1021872248213":1478686417136,"1024926768037":1509788624415,"1022646936414":1480585069155,"1022646936413":1480585069155,"1022646936411":1480585069155,"1022646936410":1480585069155,"1022646936406":1480585069155,"1024926768049":1509788624415,"1025632187811":1509788624999,"1022646936402":1480585069155,"1022646936400":1480585069155,"1021950495058":1478686417145,"1023154045205":1509788624325,"1021786529437":1509788625068,"1024055941080":1509788624969,"1023252612920":1509788625042,"1022038445982":1509788624899,"1022646936379":1480585069155,"1025671247743":1509788624823,"1025671247742":1509788624832,"1025671247741":1509788624828,"1022646936374":1480585069155,"1021941058008":1478686417055,"1377938301":1478686804029,"1016565811641":1478686804046,"1022646936332":1480585069155,"1022646936328":1480585069155,"1025530740711":1509788624407,"1022646936322":1480585069155,"1025530740710":1509788624431,"1022711162837":1509788624349,"1025530740709":1509788624425,"1025530740708":1509788624428,"1021825454089":1509788624995,"1023483426242":1509788625081,"1021060268657":1478686417093,"1022243896291":1478686417066,"1018763397789":1478686804022,"1023154045227":1509788624325,"1022566984915":1509788624539,"1021150574650":1478686417097,"1021971991340":1478686417150,"1002276365618":1478686416993,"1021971991328":1478686417150,"1021971991335":1478686417150,"1022519143324":1509788625064,"1024161713591":1509788667562,"1414507987":1491634246533,"1021971991348":1478686417150,"1022447056870":1478686417071,"1020957510785":1478686417085,"1025671247744":1509788624745,"1020745830512":1509788624285,"1021037462483":1478686417035,"1020745830513":1509788624285,"1020745830514":1509788624285,"1020745830515":1509788624285,"1020745830509":1509788624285,"1020745830510":1509788624285,"1020745830511":1509788624285,"1018553688031":1478686804033,"1020745830506":1509788624285,"1020745830507":1509788624285,"1020745830500":1509788624285,"1020745830501":1509788624285,"1020745830502":1509788624285,"1020745830503":1509788624285,"1021984836186":1478686417264,"1020745830499":1509788624285,"1021096052533":1465470268251,"1023949115704":1509788667493,"1021199203600":1465470268191,"1021195533017":1464448510787,"1024008884874":1509788667493,"1021096052528":1465470268251,"1009004123250":1478686804032,"1022646936481":1480585069087,"1022646936480":1480585069087,"1025792355520":1509788625007,"4563400232":1465469681386,"1023154045321":1509788624325,"1021096052510":1465470268251,"1025521564884":1509788624426,"1025596797778":1509788624930,"1020294166339":1465470268294,"1022646936479":1480585069087,"1024278364835":1509788624441,"1024278364834":1509788624441,"1024278364837":1509788624441,"1024278364836":1509788624441,"1024278364838":1509788624441,"1022646936468":1480585069087,"1022646936467":1480585069087,"1022458328659":1478686417016,"1022646935660":1480585069153,"1022646935656":1480585069153,"1020504793142":1478686804035,"1025879384523":1509788667715,"1020525504235":1478686804033,"1020504793140":1478686804032,"1022646935678":1480585069153,"1022646935676":1480585069153,"1024116754656":1509788625036,"1024161713714":1509788667562,"1022646935668":1480585069153,"1022646935664":1480585069153,"1020295607465":1509788625078,"1022646935631":1480585069153,"210630313":1478686416992,"1510842408":1444487341722,"1020921334114":1478686417081,"1022472219346":1480585069121,"1000038149165":1478686417021,"1836816201":1478950494926,"1021729380617":1478686417124,"1022646935642":1480585069153,"1022425167760":1478686417210,"1022646935640":1480585069153,"1022646935636":1480585069153,"1022646935633":1480585069153,"1023008164568":1509788625049,"1021751271347":1478686417051,"1021974874331":1509788624510,"1021906195710":1478686417140,"1022208506623":1478686804065,"1021195532637":1464448510787,"1012555529138":1478686417074,"124386613":1444487341752,"4994618348":1509788667399,"1021928084776":1509788624565,"1016861375272":1478686804066,"1013894867535":1478686804052,"1024652437659":1509788624213,"1019297507406":1509788624376,"1019297507407":1509788624376,"1025596796988":1509788624929,"1000038149261":1478686417021,"1022646935806":1480585069153,"1021010985606":1478686416987,"1019187672616":1480585069078,"1022646935802":1480585069153,"1022646935799":1480585069153,"1000777316489":1478686417018,"1020903901423":1478686417227,"1022646935758":1480585069153,"1022646935755":1480585069153,"1022646935753":1480585069153,"1022646935748":1480585069153,"1022646935774":1480585069153,"1022646935773":1480585069153,"1019166044505":1478686804020,"1022646935771":1480585069153,"1022646935770":1480585069153,"1022646935768":1480585069153,"1022646935766":1480585069153,"1022646935762":1480585069153,"1025792356270":1509788625004,"1021721385339":1478686804047,"1009998222012":1491634246514,"1025540570326":1509788624302,"1022871199223":1509788625018,"1025540570322":1509788624303,"1025540570331":1509788624302,"1020903901375":1478686417227,"1022646935741":1480585069153,"1019297507556":1509788624376,"1019297507557":1509788624376,"1022646935737":1480585069153,"1022646935733":1480585069153,"1022646935732":1480585069153,"1022646935731":1480585069153,"1025875583169":1509788667406,"1025540570314":1509788624303,"1022646935692":1480585069153,"1022646935690":1480585069153,"1022646935686":1480585069153,"1024274825613":1509788624330,"1022646935684":1480585069153,"1025540570366":1509788624302,"1025540570361":1509788624303,"1022646935682":1480585069153,"1024668035322":1509788625025,"1025540570341":1509788624302,"1025540570340":1509788624302,"1025627993644":1509788624186,"1025627993643":1509788624197,"1025627993642":1509788624204,"1025627993641":1509788624200,"1021984180500":1478686417152,"1293400041":1478950494922,"1024132352228":1509788624327,"1022646935916":1480585069154,"124386412":1444487341753,"1024132352224":1509788624327,"1022646935913":1480585069154,"1024132352226":1509788624327,"1007404283418":1478686804015,"1021398297586":1478686417106,"1021298553285":1465470268202,"1024132352233":1509788624327,"1024132352232":1509788624327,"1022646935905":1480585069154,"1025540570373":1509788624302,"1022646935934":1480585069154,"1025540570372":1509788624303,"1022646935933":1480585069154,"1025540570374":1509788624302,"1022646935931":1480585069154,"1022646935927":1480585069154,"1022139369393":1478686417184,"1022646935920":1480585069154,"1025540570378":1509788624303,"1022646935885":1480585069154,"4968534790":1509788624165,"1021713652009":1478686417250,"1022646935882":1480585069154,"1022417041171":1478686417293,"1022646935899":1480585069154,"1024132352220":1509788624326,"1015472297228":1509788624172,"1022646935888":1480585069154,"1022646935855":1480585069154,"1006891144392":1478686804025,"1022646935852":1480585069154,"1022918250752":1509788625052,"1024008884230":1509788667493,"1022646935847":1480585069154,"1022646935844":1480585069154,"1022646935843":1480585069154,"1009264953158":1478686804055,"1021498305961":1478686417007,"1022646935840":1480585069154,"1012118412615":1478686416993,"1022646935857":1480585069154,"1021502631422":1509788625004,"1025792355917":1509788625007,"139457327":1478950494905,"1024278364211":1509788625145,"1024278364210":1509788625145,"1024278364213":1509788625145,"1022646935818":1480585069153,"1024278364212":1509788625145,"1025604268367":1509788625084,"1022646935816":1480585069153,"1022646935814":1480585069153,"1024278364216":1509788625145,"1022646935810":1480585069153,"1022208637920":1480585069087,"1020962622850":1478686417033,"1023796028773":1509788624420,"1022646935834":1480585069153,"1022646935827":1480585069153,"1025596797383":1509788624930,"1022015115080":1509788625067,"1017801671385":1444487341760,"1025033196499":1509788625203,"1019889683776":1509788624369,"1023638744825":1509788624948,"1025033196507":1509788625203,"1022646936037":1480585069154,"1022646936036":1480585069154,"1025033196504":1509788625203,"1025033196511":1509788625203,"1021917729896":1509788624535,"1025033196481":1509788625204,"1021411011500":1478686417043,"1025033196485":1509788625204,"1008117564160":1478686804030,"1015912297057":1480585069075,"1025879384159":1509788667689,"1025033196492":1509788625204,"1022090871313":1478686417062,"1021237345586":1478686417039,"1021471043365":1509788624405,"1025033196528":1509788625203,"1022646936011":1480585069154,"1010194173709":1478686804055,"1025033196534":1509788625203,"1022090871318":1478686417062,"1022646936009":1480585069154,"1021195532469":1464448510787,"1025033196532":1509788625203,"1025033196538":1509788625204,"1022646936004":1480585069154,"1025033196536":1509788625203,"1022646936003":1480585069154,"1025033196543":1509788625203,"1022646936002":1480585069154,"1025033196542":1509788625204,"1022646936001":1480585069154,"1022646936000":1480585069154,"1022646936031":1480585069154,"1021998467207":1478686417157,"1021998467204":1478686417156,"1020964719972":1478686417086,"1025033196519":1509788625203,"1022392659970":1509788624354,"1025033196518":1509788625203,"1022392659969":1509788624354,"1022646936023":1480585069154,"1010194173715":1478686804055,"1022392659978":1509788624354,"1025033196524":1509788625203,"1020777025576":1478686417018,"1024278364313":1509788624216,"585881889":1444487341729,"1024278364317":1509788624553,"1021531595556":1478686417113,"1024278364289":1509788624553,"1022646935997":1480585069154,"1022646935995":1480585069154,"1018858947456":1509788625081,"1022646935994":1480585069154,"1022646935993":1480585069154,"1022396068027":1478686417015,"1022646935991":1480585069154,"1024278364301":1509788624553,"1024278364300":1509788624553,"1024278364302":1509788624553,"1022646935948":1480585069154,"1022646935947":1480585069154,"1025891705058":1509788667452,"1025033196475":1509788625204,"1025033196473":1509788625202,"1022646935939":1480585069154,"1025033196478":1509788625204,"1022646935936":1480585069154,"1022230133431":1478686417065,"1021404326766":1478686417106,"1024278364323":1509788624216,"1024278364325":1509788624216,"1024278364324":1509788624216,"1016301837146":1480585069066,"1024278364328":1509788624216,"1022230133433":1478686417065,"1019820214550":1509788624376,"1022776958633":1509788625056,"1021928084308":1509788624228,"1025557869823":1509788624336,"1015720018267":1478686804046,"1021952724435":1478686417056,"1024116625109":1509788624525,"1021653361541":1509788624195,"1024116625108":1509788624525,"1024116625105":1509788624525,"4982691033":1509788624166,"1377938955":1478686804033,"1025033196670":1509788624498,"1024116625092":1509788624525,"1024116625094":1509788624525,"4994618762":1509788667399,"1023222857729":1509788624957,"1024116625097":1509788624525,"1024116625096":1509788624525,"1024116625099":1509788624525,"1024002725887":1491634246530,"1021528845169":1478686417007,"1024116625079":1509788624525,"1021653361639":1509788624534,"1024116625073":1509788624525,"1024116625075":1509788624525,"1024116625085":1509788624525,"1015472296571":1509788624171,"1024116625086":1509788624525,"1025033196545":1509788625203,"1022238785175":1509788624941,"745656356":1444487341724,"1022238785174":1509788624931,"1022238785173":1509788624932,"1022238785172":1509788624947,"1022238785178":1509788624972,"1022238785176":1509788624932,"1025296647363":1509788624466,"1024661745175":1509788624604,"1022065707862":1478686417175,"1021167091406":1478686417038,"1024919821669":1509788624533,"1024116625029":1509788624801,"1024008886065":1509788667494,"1021120693013":1478686417095,"1024116625028":1509788624801,"1021120693014":1478686417095,"1024116625030":1509788624801,"1024116625027":1509788624801,"1024116625026":1509788624801,"1024116625036":1509788624801,"1024116625033":1509788624801,"1024840786391":1509788624926,"1024116625032":1509788624801,"1024116625034":1509788624801,"1024116625013":1509788624801,"1022633829846":1480585069087,"1024116625012":1509788624801,"1021919564616":1478686417259,"1020566659818":1478686417074,"1024116625011":1509788624801,"1023833775448":1491634246536,"1024116625023":1509788624801,"1022633829850":1480585069079,"1025033196739":1509788624498,"1025033196743":1509788624498,"1019125282017":1509788625079,"1020850426646":1478686417078,"1022633829838":1480585069079,"1022472219747":1480585069121,"1025033196745":1509788624498,"1025792354696":1509788625007,"1022633829834":1480585069079,"1025033196748":1509788624498,"1021027632563":1478686417091,"1022014982297":1509788625068,"1021027632564":1478686417091,"1303359753":1444487341716,"1021027632566":1478686417091,"1022633829873":1480585069079,"1021551781233":1478686804029,"1025033196795":1509788624254,"1025033196794":1509788624254,"1025033196793":1509788624253,"1025033196798":1509788624254,"1020850426672":1478686417078,"1024278366176":1509788624850,"1024278366179":1509788624850,"1022633829859":1480585069079,"1024278366181":1509788624850,"1024278366180":1509788624850,"123337710":1509788624168,"1018468752674":1478686804037,"1024278366184":1509788624850,"1018468752673":1478686804037,"1022633829867":1480585069079,"1022633829866":1480585069079,"1025551186894":1509788624341,"1018468752676":1478686804037,"1018468752677":1478686804037,"1025832723508":1509788667443,"1021427002854":1509788624399,"1025033196691":1509788624498,"4982690877":1509788624165,"1024116624945":1509788624187,"1025033196695":1509788624498,"1022633829790":1480585069079,"1025033196700":1509788624498,"1024116624935":1509788624187,"1025033196679":1509788624498,"1020999713899":1478686417089,"1025033196678":1509788624498,"1024686909473":1509788624195,"1024116624930":1509788624187,"1022107387500":1478686417012,"1023486177456":1509788625038,"1025033196681":1509788624498,"1004382922193":1478686804061,"1025033196680":1509788624498,"1025033196687":1509788624498,"1024116624917":1509788624187,"1025033196723":1509788624498,"1024116624919":1509788624187,"1025033196721":1509788624498,"1025033196727":1509788624498,"1024116624912":1509788624187,"1024116624915":1509788624187,"1025033196725":1509788624498,"1022633829808":1480585069079,"1025033196724":1509788624498,"1024116624924":1509788624187,"1025033196730":1509788624498,"1023020223686":1509788625083,"1024116624926":1509788624187,"1024116624921":1509788624187,"1025033196735":1509788624498,"1024116624920":1509788624187,"1024116624923":1509788624187,"1024116624922":1509788624187,"1004382922237":1478686804061,"1025033196715":1509788624498,"1020850426746":1478686417078,"1025033196712":1509788624498,"1022221483208":1478686417192,"1022439584719":1478686417295,"1024184781761":1509788625035,"1022439584718":1478686417295,"1026227114498":1514456869793,"1022075667863":1478686417177,"1023210930669":1509788624987,"1022784954229":1509788624217,"1022784954228":1509788624217,"1022784954231":1509788624217,"1022784954227":1509788624217,"1022784954226":1509788624217,"1022421889233":1478686417293,"1019267624148":1509788624292,"1022408389009":1478686417292,"1020294165407":1465470268294,"1020950563016":1478686417033,"1025033196819":1509788624253,"1001087166681":1478686417022,"1025033196817":1509788624253,"1025033196823":1509788624253,"1025033196820":1509788624253,"1025033196827":1509788624253,"1024248349777":1495284743422,"1025033196830":1509788624254,"1025033196803":1509788624254,"1019605260425":1480585069076,"1025033196801":1509788624253,"1025033196800":1509788624254,"1000038148951":1478686417021,"1025033196806":1509788624253,"1024313229416":1509788624926,"1025033196804":1509788624253,"1775735950":1444487341709,"1303359734":1444487341734,"1016927565867":1478686804024,"1025033196813":1509788624253,"1025033196812":1509788624253,"1024661745448":1509788624604,"1022784954165":1509788624852,"1022784954164":1509788624852,"1022784954167":1509788624852,"1024632646998":1509788667473,"1022784954163":1509788624852,"1022472220055":1480585069121,"1025033196834":1509788624253,"1016669883296":1478686804053,"1025033196839":1509788624253,"1025033196838":1509788624254,"1019704088204":1509788624312,"1003492170075":1478686417220,"1025033196841":1509788624253,"1022784954159":1509788624852,"1021595297468":1478686417246,"1021595297466":1478686417246,"1021493061855":1478686417111,"1021493061853":1478686417111,"1022394365449":1509788624384,"1022394365448":1509788624384,"1022394365445":1509788624384,"1022394365444":1509788624384,"1022394365447":1509788624384,"1022394365446":1509788624384,"1022394365443":1509788624384,"1021831746727":1478686417053,"1015016173285":1478686804052,"1015016173287":1478686804053,"1024919821491":1509788625100,"1019264347561":1478686804021,"1015016173286":1478686804052,"1015016173289":1478686804053,"1015016173288":1478686804053,"1015016173291":1478686804053,"542105060":1478686417019,"1015455649923":1480585069075,"1022059285024":1478686417270,"1016936479503":1478686804067,"1009857060102":1491634246513,"1022460949071":1478686417217,"1020068593141":1480585069078,"1019255827776":1478686804047,"1015472296956":1509788624172,"1000038149075":1478686417021,"1014712876197":1480585069072,"1022749564330":1509788624379,"1022037920516":1478686417167,"1009593216376":1509788624372,"1020390500619":1478686804071,"4968535491":1509788624164,"1019930838425":1509788624353,"1020390500613":1478686804031,"1023994992580":1491634246529,"1021773159281":1509788625083,"1018587501971":1509788624940,"1021653361244":1509788624818,"665836117":1478686804033,"1020390500626":1478686804016,"1024161712677":1509788667562,"1025033197137":1509788624601,"1015472295986":1509788624171,"1025033197136":1509788624601,"1016936478919":1478686804067,"1016936478918":1478686804067,"1021594772778":1509788624405,"1022711161013":1509788624349,"1024614035775":1509788624923,"1025033197120":1509788624601,"1022003055327":1509788624978,"1016444180019":1478686804023,"1025033197127":1509788624602,"1025033197124":1509788624602,"1025033197131":1509788624601,"1022429098866":1478686417070,"1025033197130":1509788624602,"1025033197135":1509788624602,"1021948005929":1478686417055,"1022472220388":1480585069121,"1022429098869":1478686417071,"1020791182624":1478686417077,"1021984837069":1478686417264,"1016927697754":1478686804024,"1021982477370":1478686417151,"1022471433943":1478686417299,"1025003051052":1509788624462,"1021885223870":1478686417257,"1025033197083":1509788624601,"1016284275173":1480585069064,"1022394234317":1478686417206,"1015513976802":1478686804028,"1022519143510":1509788625064,"1020185508219":1478686804024,"1024352550564":1509788624178,"1025033197106":1509788624602,"1025792355185":1509788625008,"1025033197111":1509788624602,"1025033197109":1509788624602,"1025033197108":1509788624602,"1025033197114":1509788624602,"1012527481302":1478686417026,"1025033197119":1509788624602,"1025033197116":1509788624602,"1021948005956":1478686417055,"1025033197090":1509788624602,"1024412843358":1509788625007,"1025033197093":1509788624602,"1025033197098":1509788624602,"1020294164691":1465470268294,"1025033197096":1509788624602,"1025033197103":1509788624602,"1025033197101":1509788624602,"1025512651582":1509788624344,"1004329314524":1444487341711,"267252075":1491634246534,"1015658416030":1478686804016,"1024161712802":1509788667562,"1020803371768":1478686417030,"1021915107460":1478686417141,"1021527796141":1509788624437,"1025596798005":1509788624930,"1022052338034":1509788625075,"1024132353398":1509788624326,"1007394845463":1509788624378,"1024917462958":1509788624519,"1006821938484":1478686804040,"1021646282899":1478686417008,"1020824736687":1509788624972,"1021660963323":1509788624400,"1525130313":1478950494925,"1024055939166":1509788624969,"1021989948771":1478686417057,"1022129800603":1478686417013,"1021343904481":1478686804050,"4657507141":1478686416965,"1021138124446":1478686417233,"1022273911370":1478686417014,"1021789935969":1478686417255,"1020900363372":1478686417080,"1021246912785":1478686417100,"1025585788854":1509788624352,"1025585788856":1509788624351,"1025512651586":1509788624344,"1015472296252":1509788624171,"1024730425682":1509788624439,"1024116624868":1509788624186,"1024116624871":1509788624186,"1024055939463":1509788624969,"1022111319395":1478686417182,"1024161712953":1509788667562,"1013208913923":1478686804015,"1024116624872":1509788624186,"1024116624853":1509788624186,"1022370903494":1478686417290,"1024116624851":1509788624186,"1024116624850":1509788624186,"1020294033799":1465470268283,"1024116624860":1509788624186,"1024919821882":1509788624194,"1024116624839":1509788624186,"1012148033383":1478686417223,"1024116624845":1509788624187,"1024116624844":1509788624186,"1021841446315":1509788624394,"1023928932668":1509788624519,"1020547654325":1509788624934,"1024116624846":1509788624186,"1024116624841":1509788624187,"1024116624843":1509788624187,"1024055939548":1509788624969,"1024116624804":1509788624524,"1024116624806":1509788624524,"1021982608720":1478686417152,"1024116624801":1509788624524,"1022033726019":1478686417166,"1024116624808":1509788624524,"1022294096585":1478686417068,"1024116624810":1509788624524,"1024116624789":1509788624525,"1022472220571":1480585069121,"1719900640":1491634246519,"1024116624790":1509788624525,"1020437686618":1478686804065,"1020437686617":1478686804065,"1024116624786":1509788624525,"1022129800234":1478686417013,"1021153984002":1478686417038,"1024116624798":1509788624524,"1024116624794":1509788624525,"1019996242714":1509788624386,"1024116624769":1509788624525,"1024116624768":1509788624524,"1019380344919":1509788625080,"1010026272210":1491634246516,"1024116624782":1509788624525,"1024055939345":1509788624969,"1024720857463":1506339176699,"1024402881613":1509788624282,"1024402881612":1509788624300,"1024402881614":1509788624300,"1012148033472":1478686417223,"1004789632351":1480585069067,"1023973627621":1509788625017,"1021974875393":1509788624441,"1023973627620":1509788625017,"1023731147887":1509788624960,"1026505572145":1515854751199,"1024332890550":1509788625031,"1022358320654":1478686416973,"1022358320653":1478686416973,"1021428051608":1478686804026,"1022358320652":1478686416973,"1023336627395":1509788624992,"1023336627394":1509788624992,"1023336627393":1509788624992,"1021655195707":1509788624272,"1021990603837":1509788625067,"1000356386494":1478950494932,"1021655195709":1509788624272,"1023336627398":1509788624992,"1021655195710":1509788624272,"1021655195711":1509788624272,"1023336627396":1509788624992,"1020925922491":1478686417082,"1025593652599":1509788624407,"1025593652598":1509788624425,"1023336627406":1509788624992,"1025593652597":1509788624431,"1936690384":1444487341746,"1025593652596":1509788624428,"1021655195721":1509788624272,"1023336627377":1509788624992,"1017244886954":1478686804025,"1021630030540":1509788624397,"1023336627382":1509788624992,"1023336627381":1509788624992,"1021655195727":1509788624272,"1025593652483":1509788624823,"1021655195713":1509788624272,"1025593652482":1509788624833,"1025593652481":1509788624829,"1021655195715":1509788624272,"1025593652487":1509788624800,"1021655195717":1509788624272,"1021655195718":1509788624272,"1021655195719":1509788624272,"1021655195736":1509788624272,"1025593652507":1509788625108,"1025593652506":1509788625125,"1021655195738":1509788624272,"1025593652505":1509788625116,"1023625898977":1509788624937,"1025593652509":1509788625088,"1025365328831":1509788624456,"1023336627371":1509788624992,"1021655195729":1509788624272,"1021655195731":1509788624272,"1023336627368":1509788624992,"1021655195732":1509788624272,"1021211786180":1478686417235,"1021655195734":1509788624272,"1025596798299":1509788624929,"1023845834488":1491634246533,"1025593652524":1509788624523,"1021655195748":1509788624272,"1025593652519":1509788624537,"1025593652518":1509788624541,"1024919822075":1509788624419,"1025593652517":1509788624542,"1021247961117":1478686416992,"1207547917":1444487341706,"1012689483744":1478686416995,"1024206276712":1509788625034,"1012118411748":1478686416993,"1022616528803":1509788624384} ================================================ FILE: src/test/resources/everefblueprint.json ================================================ { "blueprint_type_id": 10, "activities": { "additionalProp1": { "time": 10, "materials": { "additionalProp1": { "type_id": 10, "quantity": 10, "probability": 10 }, "additionalProp2": { "type_id": 10, "quantity": 10, "probability": 10 }, "additionalProp3": { "type_id": 10, "quantity": 10, "probability": 10 } }, "products": { "additionalProp1": { "type_id": 10, "quantity": 10, "probability": 10 }, "additionalProp2": { "type_id": 10, "quantity": 10, "probability": 10 }, "additionalProp3": { "type_id": 10, "quantity": 10, "probability": 10 } }, "required_skills": { "additionalProp1": 10, "additionalProp2": 10, "additionalProp3": 10 } }, "additionalProp2": { "time": 10, "materials": { "additionalProp1": { "type_id": 10, "quantity": 10, "probability": 10 }, "additionalProp2": { "type_id": 10, "quantity": 10, "probability": 10 }, "additionalProp3": { "type_id": 10, "quantity": 10, "probability": 10 } }, "products": { "additionalProp1": { "type_id": 10, "quantity": 10, "probability": 10 }, "additionalProp2": { "type_id": 10, "quantity": 10, "probability": 10 }, "additionalProp3": { "type_id": 10, "quantity": 10, "probability": 10 } }, "required_skills": { "additionalProp1": 10, "additionalProp2": 10, "additionalProp3": 10 } }, "additionalProp3": { "time": 10, "materials": { "additionalProp1": { "type_id": 10, "quantity": 10, "probability": 10 }, "additionalProp2": { "type_id": 10, "quantity": 10, "probability": 10 }, "additionalProp3": { "type_id": 10, "quantity": 10, "probability": 10 } }, "products": { "additionalProp1": { "type_id": 10, "quantity": 10, "probability": 10 }, "additionalProp2": { "type_id": 10, "quantity": 10, "probability": 10 }, "additionalProp3": { "type_id": 10, "quantity": 10, "probability": 10 } }, "required_skills": { "additionalProp1": 10, "additionalProp2": 10, "additionalProp3": 10 } } }, "max_production_limit": 10 } ================================================ FILE: src/test/resources/evereftype.json ================================================ { "type_id": 10, "base_price": 10, "capacity": 10, "description": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "dogma_attributes": { "additionalProp1": { "attribute_id": 10, "value": 10 }, "additionalProp2": { "attribute_id": 10, "value": 10 }, "additionalProp3": { "attribute_id": 10, "value": 10 } }, "dogma_effects": { "additionalProp1": { "effect_id": 10, "is_default": true }, "additionalProp2": { "effect_id": 10, "is_default": true }, "additionalProp3": { "effect_id": 10, "is_default": true } }, "faction_id": 10, "graphic_id": 10, "group_id": 10, "icon_id": 10, "market_group_id": 10, "mass": 10, "masteries": { "additionalProp1": [ 10 ], "additionalProp2": [ 10 ], "additionalProp3": [ 10 ] }, "meta_group_id": 10, "name": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "packaged_volume": 10, "portion_size": 10, "published": true, "race_id": 10, "radius": 10, "sof_faction_name": "string", "sof_material_set_id": 10, "sound_id": 10, "traits": { "misc_bonuses": { "additionalProp1": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 }, "additionalProp2": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 }, "additionalProp3": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 } }, "role_bonuses": { "additionalProp1": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 }, "additionalProp2": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 }, "additionalProp3": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 } }, "types": { "additionalProp1": { "additionalProp1": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 }, "additionalProp2": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 }, "additionalProp3": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 } }, "additionalProp2": { "additionalProp1": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 }, "additionalProp2": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 }, "additionalProp3": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 } }, "additionalProp3": { "additionalProp1": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 }, "additionalProp2": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 }, "additionalProp3": { "bonus": 10, "bonus_text": { "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }, "importance": 10, "is_positive": true, "unit_id": 10 } } }, "icon_id": 10 }, "variation_parent_type_id": 10, "volume": 10, "required_skills": { "additionalProp1": 10, "additionalProp2": 10, "additionalProp3": 10 }, "applicable_mutaplasmid_type_ids": [ 10 ], "creating_mutaplasmid_type_ids": [ 10 ], "type_variations": { "additionalProp1": [ 10 ], "additionalProp2": [ 10 ], "additionalProp3": [ 10 ] }, "ore_variations": { "additionalProp1": [ 10 ], "additionalProp2": [ 10 ], "additionalProp3": [ 10 ] }, "is_ore": true, "produced_by_blueprints": { "additionalProp1": { "blueprint_type_id": 10, "blueprint_activity": "string" }, "additionalProp2": { "blueprint_type_id": 10, "blueprint_activity": "string" }, "additionalProp3": { "blueprint_type_id": 10, "blueprint_activity": "string" } }, "type_materials": { "additionalProp1": { "material_type_id": 10, "quantity": 10 }, "additionalProp2": { "material_type_id": 10, "quantity": 10 }, "additionalProp3": { "material_type_id": 10, "quantity": 10 } }, "can_fit_types": [ 10 ], "can_be_fitted_with_types": [ 10 ], "is_skill": true, "is_mutaplasmid": true, "is_dynamic_item": true, "is_blueprint": true } ================================================ FILE: src/test/resources/tracker_empty.json ================================================ {} ================================================ FILE: src/test/resources/tracker_filters.json ================================================ {"TEST-NAME":[{"date":1552492124589,"assets":9.0,"escrows":5.0,"escrowstocover":6.0,"sellorders":8.0,"walletbalance":10.0,"manufacturing":7.0,"contractcollateral":3.0,"contractvalue":4.0,"skillpoints":11,"balance":[{"id":"balence-id","value":10.0}],"asset":[{"location":"location","locationid":1000,"flag":"flag","value":9.0}]}]} ================================================ FILE: src/test/resources/tracker_total.json ================================================ {"TEST-NAME":[{"date":1552492124589,"assets":1.0,"escrows":5.0,"escrowstocover":6.0,"sellorders":8.0,"walletbalance":2.0,"manufacturing":7.0,"contractcollateral":3.0,"contractvalue":4.0,"skillpoints":11}]} ================================================ FILE: tools/bugs/conn.php ================================================ ================================================ FILE: tools/bugs/index.php ================================================ <?php echo name() . ' Bug Database' ?>


'.PHP_EOL; echo ''.PHP_EOL; echo ''.PHP_EOL; echo '
'.PHP_EOL; echo '   '.PHP_EOL; echo '   '.PHP_EOL; echo '   '.PHP_EOL; echo '   '.PHP_EOL; if ($admin) { echo ''.PHP_EOL; } checkbox($compact, 'compact', "Compact"); echo '
'.PHP_EOL; echo '
'.PHP_EOL; checkbox($wontfix, 'wontfix', "Won't Fix"); checkbox($reopened, 'reopened', "Re-Opened"); checkbox($new, 'new', "New"); checkbox($accepted, 'accepted', "Accepted"); checkbox($started, 'started', "Started"); checkbox($fixed, 'fixed', "Fixed"); checkbox($fixreleased, 'fixreleased', "Fix Released"); checkbox($javabug, 'javabug', "Java Bugs"); echo '
'.PHP_EOL; //echo ''.PHP_EOL; echo ''.PHP_EOL; echo "
".PHP_EOL; $sql = "SELECT * FROM ".table(); $and = false; if ($version != 'All' || $java != 'All' || $os != 'All' || $wontfix || $reopened || $new || $accepted || $started || $fixed || $fixreleased || $javabug) { $sql = $sql . " WHERE "; } add_where($sql, $and, $version, 'version'); add_where($sql, $and, $java, 'java'); add_where($sql, $and, $os, 'os'); checkbox_where($sql, $and, $wontfix, '-2'); checkbox_where($sql, $and, $reopened, '-1'); checkbox_where($sql, $and, $new, '0'); checkbox_where($sql, $and, $accepted, '1'); checkbox_where($sql, $and, $started, '2'); checkbox_where($sql, $and, $fixed, '3'); checkbox_where($sql, $and, $fixreleased, '4'); search_where($sql, $and, $javabug, 'log', 'net.nikr'); $sql = $sql." ORDER BY $order $desc"; $statement = $dbh->prepare($sql); $statement->execute(); $rows = $statement->fetchAll(PDO::FETCH_ASSOC); foreach ($rows as &$row) { echo '
'.PHP_EOL; switch ($row['status']) { case -2: echo ' Won\'t Fix '; break; case -1: echo ' Re-Opened '; break; case 0: echo ' New '; break; case 1: echo ' Accepted '; break; case 2: echo ' Started '; break; case 3: echo ' Fixed '; break; case 4: echo ' Fix Released '; break; } if (strpos(format($row['log']), 'net.nikr') === false) { echo '  Java Bug '; } echo " Date: ".formatDate($row['date']); echo " Count: "; if ($row['count'] > 10) { echo ''; } elseif ($row['count'] > 6) { echo ''; } elseif ($row['count'] > 2) { echo ''; } else { echo ""; } echo format($row['count']); echo ""; echo ' BugId: '.format($row['id']).''; echo "
".PHP_EOL; if ($admin) { echo '
'; //Edit echo ' '; //Delete echo ' '; echo "
"; } echo '
'; echo "OS: ".format_list($row['os'])."
"; echo "Java: ".format_list($row['java'])."
"; echo "Version: ".format_list($row['version'])."
"; if ($compact) { echo "Bug:
"; echo format($row['log']); } else { echo "Bug: ".strtok($row['log'], "\n")."
"; echo "
".format($row['log'])."

"; } echo "
"; echo "
"; } function format_space($string) { $string = preg_replace('/[\r\n]+/', '
', $string); $string = preg_replace('/\t/', '    ', $string); $string = preg_replace('/\s/', ' ', $string); return $string; } function format($string) { $string = htmlentities($string); $string = format_space($string); return $string; } function formatDate($string) { $db_date = new DateTime($string); $today = new DateTime(); $interval = $db_date->diff($today); $string = $interval->format('%a days ago'); if ($string == '0 days ago') { return 'Today'; } else { return $string; } } function format_list($string) { $string = str_replace(";", "    ", $string); return format_space($string); } function select($values, $name, $selected) { echo '".PHP_EOL; } function makeSafe($find, $in, $default) { $key = array_search($find, $in); $value = $in[$key]; if (empty($value)) { return $default; } else { return $value; } } function getArray($dbh, $column, $revers = false) { $statement = $dbh->prepare("SELECT $column FROM ".table()); $statement->execute(); $rows = $statement->fetchAll(PDO::FETCH_ASSOC); $array = array(); foreach ($rows as &$row) { $temp = explode(';', $row[$column]); $temp = array_merge($temp, $array); $array = array_unique($temp); } if ($revers) { rsort($array); } else { sort($array); } array_unshift($array, "All"); return $array; } function update($dbh, $id, $status) { $statement = $dbh->prepare("UPDATE ".table()." SET status=$status WHERE id=$id"); $statement->execute(); } function delete($dbh, $id) { $statement = $dbh->prepare("DELETE FROM ".table()." WHERE id=$id"); $statement->execute(); } function add_where(&$sql, &$and, $value, $column) { if ($value != 'All') { if ($and) { $sql = $sql . " AND "; } $sql = $sql . " $column regexp '(^|;)$value(;|$)' "; $and = true; } } function checkbox($ignore, $value, $name) { echo ''.PHP_EOL; $fg = 'Black'; switch ($value) { case 'wontfix': $bg = 'Gainsboro'; break; case 'reopened': $bg = '#ff33ff'; break; case 'new': $bg = '#cc3300'; break; case 'accepted': $bg = '#ff9933'; break; case 'started': $bg = '#ffcc33'; break; case 'fixed': $bg = 'LightSkyBlue'; break; case 'fixreleased': $bg = 'LimeGreen'; break; case 'javabug': if (!$ignore) { $fg = '#cc3300'; } break; } if (isset($bg)) { if ($ignore) { //echo ''.PHP_EOL; echo ''.PHP_EOL; } else { echo ''.PHP_EOL; } } else { if ($ignore) { echo ''.PHP_EOL; } else { echo ''.PHP_EOL; } } } function checkbox_where(&$sql, &$and, $ignore, $value) { if ($ignore) { if ($and) { $sql = $sql . " AND "; } $sql = $sql . " status != $value "; $and = true; } } function search_where(&$sql, &$and, $ignore, $column, $value) { if ($ignore) { if ($and) { $sql = $sql . " AND "; } $sql = $sql . " $column LIKE '%$value%' "; $and = true; } } ?> ================================================ FILE: tools/bugs/jeveasset.sql ================================================ SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; CREATE TABLE IF NOT EXISTS `jeveasset` ( `id` int(11) NOT NULL AUTO_INCREMENT, `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `os` tinytext NOT NULL, `java` tinytext NOT NULL, `version` tinytext NOT NULL, `log` text NOT NULL, `count` int(11) NOT NULL, `status` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; ================================================ FILE: tools/bugs/submit.php ================================================ prepare("SELECT * FROM ".table()." where log = ?"); if ($stmt->execute(array($log_in))) { while ($row = $stmt->fetch()) { $foundRow = $row; break; } } if (empty($foundRow)) { //New bug report $count = '1'; $stmt = $dbh->prepare("INSERT INTO ".table()." (os,java,version,log,count) VALUES (:os, :java, :version, :log, :count)"); $stmt->bindParam(':os', $os_in); $stmt->bindParam(':java', $java_in); $stmt->bindParam(':version', $version_in); $stmt->bindParam(':log', $log_in); $stmt->bindParam(':count', $count); $stmt->execute(); $id = $dbh->lastInsertId(); print $id; $to_nkr = "nkr@niklaskr.dk"; $subject_nkr = "New " . name() . " bug report (BugID: " . $id . ")"; $message_nkr = name() . " bug report\r\n" . "BugID: " . $id . "\r\n" . buglink() . "#bugid" . $id . "\r\n" . "\r\n" . $log_in ; $log_fixed = str_replace(array("\r\n", "\r", "\n"), "\n", $log_in); $log_first_line = strstr($log_fixed, "\n", true); $to_zapie = "jeveassets.oae2vi@zapiermail.com"; $subject_zapie = $log_first_line . " (BugID: " . $id . ")"; $message_zapie = name() . " bug report\r\n" . $log_first_line. "\r\n" . "BugID: " . $id . "\r\n" . buglink() . "#bugid" . $id . "\r\n" ; $headers = "From: nkr@niklaskr.dk" . "\r\n" . "X-Mailer: PHP/" . phpversion(); mail($to_nkr, $subject_nkr, $message_nkr, $headers); mail($to_zapie, $subject_zapie, $message_zapie, $headers); } else { //Old bug report - Add: count, os, java, version - Update: status $count = $foundRow['count']; $count++; $id = $foundRow['id']; if ($foundRow['status'] == 4) { $status = -1; } else { $status = $foundRow['status']; } $os = add($foundRow['os'], $os_in); $java = add($foundRow['java'], $java_in); $version = add($foundRow['version'], $version_in); $stmt = $dbh->prepare("UPDATE ".table()." SET os=:os,java=:java,version=:version,count=:count,status=:status,date=current_timestamp WHERE id=:id"); $stmt->bindParam(':os', $os); $stmt->bindParam(':java', $java); $stmt->bindParam(':version', $version); $stmt->bindParam(':count', $count); $stmt->bindParam(':id', $id); $stmt->bindParam(':status', $status); $stmt->execute(); print $id; } function add($in, $add) { $out = explode(";", $in); //Split to array $out[] = $add; //Add new $out = array_unique($out); //Remove dubs return implode(";", $out); //Return string } ?> ================================================ FILE: tools/citadel/index.php ================================================ javaw -jar $INSTALL_PATH/jeveassets.jar java -jar $INSTALL_PATH/jeveassets.jar java -jar $INSTALL_PATH/jeveassets.jar ================================================ FILE: tools/izpack/install.xml ================================================ jEveAssets ${project.version} jEveAssets https://eve.nikr.net/jeveasset 1.6 no no runOnExit true Core installation files ================================================ FILE: tools/jarfile.properties ================================================ jarfile=jeveassets.jar ================================================ FILE: tools/packagemanager.properties ================================================ ### packagemanager.properties Example ### # Add this file to the jEveAssets directory, # to disable all program and static data all updates. # Allowing the package manager full control of updates # Comma separated list of package maintainers maintainers=DenSpirit, NovaMoon #notify users of new updates on startup [values: true|false] notifyUpdates=true ================================================ FILE: tools/update/.htaccess ================================================ # # Disable Caching # Header add "Cache-Control" "no-cache" ================================================ FILE: tools/update/github.update ================================================ https://github.com/GoldenGnu/jeveassets/releases/latest/download/jeveassets-${project.version}.zip data/ ================================================ FILE: tools/update/list.php ================================================